使用Swift的C API

我试图跟踪networking状态。 我经历了FXReachability的代码。 具体如下的方法。

- (void)setHost:(NSString *)host { if (host != _host) { if (_reachability) { SCNetworkReachabilityUnscheduleFromRunLoop(_reachability, CFRunLoopGetMain(), kCFRunLoopCommonModes); CFRelease(_reachability); } _host = [host copy]; _status = FXReachabilityStatusUnknown; _reachability = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, [_host UTF8String]); SCNetworkReachabilityContext context = { 0, ( __bridge void *)self, NULL, NULL, NULL }; SCNetworkReachabilitySetCallback(_reachability, ONEReachabilityCallback, &context); SCNetworkReachabilityScheduleWithRunLoop(_reachability, CFRunLoopGetMain(), kCFRunLoopCommonModes); } } 

它所做的是不断检查到指定主机的连接。 我试图将此方法转换为Swift,并遇到一些问题。

1.将主机string转换为UTF8。

我必须将主机string转换为UTF8并将其传递到SCNetworkReachabilityCreateWithName方法。 我无法在Objective-C中find与UTF8String属性完全相同的Swift。 但是Stringtypes有一个名为utf8的属性。 根据文件 ,

通过迭代utf8属性,可以访问string的UTF-8表示forms。 该属性的types为String.UTF8View,它是无符号8位(UInt8)值的集合,对于string的UTF-8表示中的每个字节都有一个值:

我怎样才能得到一个string的完整的UTF8表示,而不是一个无符号的8位(UInt8)值的集合?


2. SCNetworkReachabilitySetCallback的callback函数。

这个函数的第二个参数需要SCNetworkReachabilityCallBacktypes的SCNetworkReachabilityCallBack 。 我潜入源文件,发现它实际上是一个typealias

 typealias SCNetworkReachabilityCallBack = CFunctionPointer<((SCNetworkReachability!, SCNetworkReachabilityFlags, UnsafeMutablePointer<Void>) -> Void)> 

我是这样定义的

 let reachabilityCallBack: SCNetworkReachabilityCallBack = { }() 

但是,我得到错误返回在一个封闭期望返回“SCNetworkReachabilityCallBack”时,在该typealias中,你可以清楚地看到,它返回Void

这是否是错误的方式?


这些是我面临的问题。 我已经在这个几个小时没有运气,所以我非常感谢任何帮助。

谢谢。

你的第一个问题可以用

 let reachability = host.withCString { SCNetworkReachabilityCreateWithName(nil, $0).takeRetainedValue() } 

在闭包内部, $0是一个指向String的NUL终止的UTF-8表示的指针。

更新:正如Nate Cook在一个已经被删除的答案中所说的那样,在这里也可以直接传递一个Swiftstring给一个带有UnsafePointer<UInt8>的函数:

 let reachability = SCNetworkReachabilityCreateWithName(nil, host).takeRetainedValue() 

不幸的是,(据我所知)目前还没有解决你的第二个问题。 SCNetworkReachabilitySetCallback需要一个指向C函数的指针作为第二个参数,目前没有方法可以传递Swift函数或闭包。 请注意, SCNetworkReachabilityCallBack的文档SCNetworkReachabilityCallBack显示了Objective-C,但没有显示Swift。

另请参见Swift不能与函数指针一起使用吗? 。


Swift 2的更新:现在可以将Swift闭包传递给一个带有函数指针参数的C函数。 此外, SCNetworkReachabilityCreateWithName()不会返回非托pipe对象:

 let host = "google.com" var context = SCNetworkReachabilityContext(version: 0, info: nil, retain: nil, release: nil, copyDescription: nil) let reachability = SCNetworkReachabilityCreateWithName(nil, host)! SCNetworkReachabilitySetCallback(reachability, { (_, flags, _) in print(flags) }, &context) SCNetworkReachabilityScheduleWithRunLoop(reachability, CFRunLoopGetMain(), kCFRunLoopCommonModes) 

Swift 3(Xcode 8)的更新:

 let host = "google.com" var context = SCNetworkReachabilityContext(version: 0, info: nil, retain: nil, release: nil, copyDescription: nil) let reachability = SCNetworkReachabilityCreateWithName(nil, host)! SCNetworkReachabilitySetCallback(reachability, { (_, flags, _) in print(flags) }, &context) SCNetworkReachabilityScheduleWithRunLoop(reachability, CFRunLoopGetMain(), CFRunLoopMode.commonModes.rawValue)