我想转换此代码段斯威夫特。 我挣扎上下车,由于一些困难地面。
- (BOOL) connectedToNetwork
{
// Create zero addy
struct sockaddr_in zeroAddress;
bzero(&zeroAddress, sizeof(zeroAddress));
zeroAddress.sin_len = sizeof(zeroAddress);
zeroAddress.sin_family = AF_INET;
// Recover reachability flags
SCNetworkReachabilityRef defaultRouteReachability = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&zeroAddress);
SCNetworkReachabilityFlags flags;
BOOL didRetrieveFlags = SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags);
CFRelease(defaultRouteReachability);
if (!didRetrieveFlags)
{
return NO;
}
BOOL isReachable = flags & kSCNetworkFlagsReachable;
BOOL needsConnection = flags & kSCNetworkFlagsConnectionRequired;
return (isReachable && !needsConnection) ? YES : NO;
}
第一,我在的主要问题是如何定义与C结构的工作。 在第一行( struct sockaddr_in zeroAddress;
上面的代码中,我认为他们是定义一个称为实例zeroAddress
(?)从结构sockaddr_in中,我假设。 我想声明一个var
是这样的。
var zeroAddress = sockaddr_in()
但我得到的错误缺少的参数变量“sin_len”呼叫这是可以理解的,因为结构发生了一些争论。 于是,我又试了一次。
var zeroAddress = sockaddr_in(sin_len: sizeof(zeroAddress), sin_family: AF_INET, sin_port: nil, sin_addr: nil, sin_zero: nil)
正如预期的那样,我得到了自己的初始值中使用的一些其他错误变量 。 我的理解是错误的原因了。 在C语言中,他们首先声明实例,然后填写参数。 它不可能在斯威夫特据我所知。 所以我真的失去了在这一点上做什么。
我读了苹果的官方文档上与雨燕Ç的API进行交互,但它没有实例与结构的工作。
任何人都可以请帮我在这里? 我会很感激。
谢谢。
更新:感谢Martin我能闯过最初的问题。 但还是斯威夫特不是让我更容易。 我越来越多新的错误。
func connectedToNetwork() -> Bool {
var zeroAddress = sockaddr_in(sin_len: 0, sin_family: 0, sin_port: 0, sin_addr: in_addr(s_addr: 0), sin_zero: (0, 0, 0, 0, 0, 0, 0, 0))
zeroAddress.sin_len = UInt8(sizeofValue(zeroAddress))
zeroAddress.sin_family = sa_family_t(AF_INET)
var defaultRouteReachability: SCNetworkReachabilityRef = SCNetworkReachabilityCreateWithAddress(UnsafePointer<Void>, UnsafePointer<zeroAddress>) // 'zeroAddress' is not a type
var flags = SCNetworkReachabilityFlags()
let didRetrieveFlags = SCNetworkReachabilityGetFlags(defaultRouteReachability, UnsafeMutablePointer<flags>) // 'flags' is not a type
defaultRouteReachability.dealloc(1) // 'SCNetworkReachabilityRef' does not have a member named 'dealloc'
if didRetrieveFlags == false {
return false
}
let isReachable: Bool = flags & kSCNetworkFlagsReachable // Cannot invoke '&' with an argument list of type '(@lvalue UInt32, Int)'
let needsConnection: Bool = flags & kSCNetworkFlagsConnectionRequired // Cannot invoke '&' with an argument list of type '(@lvalue UInt32, Int)'
return (isReachable && !needsConnection) ? true : false
}
编辑1:好吧,我改变了这一行来此,
var defaultRouteReachability: SCNetworkReachabilityRef = SCNetworkReachabilityCreateWithAddress(UnsafePointer<Void>(), &zeroAddress)
新的错误,我在这行得到的是“UnsafePointer”是无法转换为“CFAllocator”。 如何传递NULL
斯威夫特?
此外,我改变了这一行,现在错误消失。
let didRetrieveFlags = SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags)
编辑2:我通过nil
在此行后看到这个问题。 但是这个答案的答案矛盾在这里 。 它说,有没有相当于NULL
斯威夫特。
var defaultRouteReachability: SCNetworkReachabilityRef = SCNetworkReachabilityCreateWithAddress(nil, &zeroAddress)
无论如何,我得到一个新的错误说“sockaddr_in的”不等同于在上述行“SOCKADDR”。
(这个答案一再延长由于雨燕语言的变化,这使得它有点混乱。我现在已经完全重写,并删除一切是指雨燕1.x中的旧的代码可以在编辑历史中找到,如果有人需要它。)
这是你会怎么做,在雨燕2.0(Xcode中7):
import SystemConfiguration
func connectedToNetwork() -> Bool {
var zeroAddress = sockaddr_in()
zeroAddress.sin_len = UInt8(sizeofValue(zeroAddress))
zeroAddress.sin_family = sa_family_t(AF_INET)
guard let defaultRouteReachability = withUnsafePointer(&zeroAddress, {
SCNetworkReachabilityCreateWithAddress(nil, UnsafePointer($0))
}) else {
return false
}
var flags : SCNetworkReachabilityFlags = []
if !SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) {
return false
}
let isReachable = flags.contains(.Reachable)
let needsConnection = flags.contains(.ConnectionRequired)
return (isReachable && !needsConnection)
}
说明:
如夫特1.2(6.3的Xcode),进口C的结构具有在夫特,初始化所有结构体的领域的零的默认初始值,所以套接字地址结构可以与被初始化
var zeroAddress = sockaddr_in()
sizeofValue()
给出了该结构的大小,这必须被转换到UInt8
为sin_len
:
zeroAddress.sin_len = UInt8(sizeofValue(zeroAddress))
AF_INET
是一个Int32
,这必须被转换为正确的类型sin_family
:
zeroAddress.sin_family = sa_family_t(AF_INET)
withUnsafePointer(&zeroAddress) { ... }
传递结构的地址给在那里它被用来作为参数为所述闭合SCNetworkReachabilityCreateWithAddress()
所述UnsafePointer($0)
需要转换,因为函数需要一个指针sockaddr
,不sockaddr_in
。
从返回的值withUnsafePointer()
是从返回值SCNetworkReachabilityCreateWithAddress()
并具有类型SCNetworkReachability?
,即它是一个可选的。 该guard let
语句(斯威夫特2.0中的新功能)分配展开值到defaultRouteReachability
如果不是变量nil
。 否则, else
块被执行,函数返回。
- 作为夫特2,
SCNetworkReachabilityCreateWithAddress()
返回一个管理对象。 你不必明确地释放它。 作为夫特2, SCNetworkReachabilityFlags
符合OptionSetType
其具有一组类似的接口。 您创建一个空的标志变
var flags : SCNetworkReachabilityFlags = []
并检查与标志
let isReachable = flags.contains(.Reachable) let needsConnection = flags.contains(.ConnectionRequired)
的第二个参数SCNetworkReachabilityGetFlags
具有类型UnsafeMutablePointer<SCNetworkReachabilityFlags>
这意味着你必须通过可变标志的地址 。
还要注意的是注册通知回调是尽可能夫特2,比较与来自夫特Ç的API工作和夫特2 - UnsafeMutablePointer <空隙>到对象 。
更新斯威夫特3/4:
不安全的指针不能简单地被转换成不同类型的指针了(见- SE-0107 UnsafeRawPointer API )。 在这里,更新后的代码:
import SystemConfiguration
func connectedToNetwork() -> Bool {
var zeroAddress = sockaddr_in()
zeroAddress.sin_len = UInt8(MemoryLayout<sockaddr_in>.size)
zeroAddress.sin_family = sa_family_t(AF_INET)
guard let defaultRouteReachability = withUnsafePointer(to: &zeroAddress, {
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
SCNetworkReachabilityCreateWithAddress(nil, $0)
}
}) else {
return false
}
var flags: SCNetworkReachabilityFlags = []
if !SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) {
return false
}
let isReachable = flags.contains(.reachable)
let needsConnection = flags.contains(.connectionRequired)
return (isReachable && !needsConnection)
}
斯威夫特3,IPv4的IPv6的
根据马丁的r答案:
import SystemConfiguration
func isConnectedToNetwork() -> Bool {
guard let flags = getFlags() else { return false }
let isReachable = flags.contains(.reachable)
let needsConnection = flags.contains(.connectionRequired)
return (isReachable && !needsConnection)
}
func getFlags() -> SCNetworkReachabilityFlags? {
guard let reachability = ipv4Reachability() ?? ipv6Reachability() else {
return nil
}
var flags = SCNetworkReachabilityFlags()
if !SCNetworkReachabilityGetFlags(reachability, &flags) {
return nil
}
return flags
}
func ipv6Reachability() -> SCNetworkReachability? {
var zeroAddress = sockaddr_in6()
zeroAddress.sin6_len = UInt8(MemoryLayout<sockaddr_in>.size)
zeroAddress.sin6_family = sa_family_t(AF_INET6)
return withUnsafePointer(to: &zeroAddress, {
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
SCNetworkReachabilityCreateWithAddress(nil, $0)
}
})
}
func ipv4Reachability() -> SCNetworkReachability? {
var zeroAddress = sockaddr_in()
zeroAddress.sin_len = UInt8(MemoryLayout<sockaddr_in>.size)
zeroAddress.sin_family = sa_family_t(AF_INET)
return withUnsafePointer(to: &zeroAddress, {
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
SCNetworkReachabilityCreateWithAddress(nil, $0)
}
})
}
这有没有关系斯威夫特,但最好的解决办法是不使用的可达性来确定网络是否在线。 只是让你的连接,如果失败处理错误。 建立连接可以在次火起来的休眠离线收音机。
可达性的一个有效的用途是用它来通知你当网络的过渡,从离线到在线。 在这一点上你应该重新尝试失败的连接。
最好的解决办法是使用ReachabilitySwift
类 ,写在Swift 2
,并使用SCNetworkReachabilityRef
。
简单易用:
let reachability = Reachability.reachabilityForInternetConnection()
reachability?.whenReachable = { reachability in
// keep in mind this is called on a background thread
// and if you are updating the UI it needs to happen
// on the main thread, like this:
dispatch_async(dispatch_get_main_queue()) {
if reachability.isReachableViaWiFi() {
print("Reachable via WiFi")
} else {
print("Reachable via Cellular")
}
}
}
reachability?.whenUnreachable = { reachability in
// keep in mind this is called on a background thread
// and if you are updating the UI it needs to happen
// on the main thread, like this:
dispatch_async(dispatch_get_main_queue()) {
print("Not reachable")
}
}
reachability?.startNotifier()
工作就像一个魅力。
请享用
更新juanjo的回答创建单个实例
import Foundation
import SystemConfiguration
final class Reachability {
private init () {}
class var shared: Reachability {
struct Static {
static let instance: Reachability = Reachability()
}
return Static.instance
}
func isConnectedToNetwork() -> Bool {
guard let flags = getFlags() else { return false }
let isReachable = flags.contains(.reachable)
let needsConnection = flags.contains(.connectionRequired)
return (isReachable && !needsConnection)
}
private func getFlags() -> SCNetworkReachabilityFlags? {
guard let reachability = ipv4Reachability() ?? ipv6Reachability() else {
return nil
}
var flags = SCNetworkReachabilityFlags()
if !SCNetworkReachabilityGetFlags(reachability, &flags) {
return nil
}
return flags
}
private func ipv6Reachability() -> SCNetworkReachability? {
var zeroAddress = sockaddr_in6()
zeroAddress.sin6_len = UInt8(MemoryLayout<sockaddr_in>.size)
zeroAddress.sin6_family = sa_family_t(AF_INET6)
return withUnsafePointer(to: &zeroAddress, {
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
SCNetworkReachabilityCreateWithAddress(nil, $0)
}
})
}
private func ipv4Reachability() -> SCNetworkReachability? {
var zeroAddress = sockaddr_in()
zeroAddress.sin_len = UInt8(MemoryLayout<sockaddr_in>.size)
zeroAddress.sin_family = sa_family_t(AF_INET)
return withUnsafePointer(to: &zeroAddress, {
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
SCNetworkReachabilityCreateWithAddress(nil, $0)
}
})
}
}
用法
if Reachability.shared.isConnectedToNetwork(){
}
这是斯威夫特4.0
我使用这个框架https://github.com/ashleymills/Reachability.swift
并安装波德..
在AppDelegate中
var window: UIWindow?
var reachability = InternetReachability()!
var reachabilityViewController : UIViewController? = nil
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
reachabilityChecking()
return true
}
extension AppDelegate {
func reachabilityChecking() {
reachability.whenReachable = { reachability in
DispatchQueue.main.async {
print("Internet is OK!")
if reachability.connection != .none && self.reachabilityViewController != nil {
}
}
}
reachability.whenUnreachable = { _ in
DispatchQueue.main.async {
print("Internet connection FAILED!")
let storyboard = UIStoryboard(name: "Reachability", bundle: Bundle.main)
self.reachabilityViewController = storyboard.instantiateViewController(withIdentifier: "ReachabilityViewController")
let rootVC = self.window?.rootViewController
rootVC?.present(self.reachabilityViewController!, animated: true, completion: nil)
}
}
do {
try reachability.startNotifier()
} catch {
print("Could not start notifier")
}
}
}
如果互联网不存在屏幕上会出现