一尘不染

使用Swift中的C API

swift

我正在尝试跟踪网络状态。我浏览了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.将主机字符串转换为UTF8。

我必须将主机字符串转换为UTF8并将其传递给SCNetworkReachabilityCreateWithName方法。我UTF8String在Objective-
C中找不到与属性完全相同的Swift
。但是,有一个叫做属性utf8String类型。根据文档

您可以通过迭代其utf8属性来访问字符串的UTF-8表示形式。此属性的类型为String.UTF8View,它是无符号8位(UInt8)值的集合,每个值对应于字符串的UTF-8表示形式的每个字节:

如何获得字符串的完整UTF8表示形式,而不是无符号8位(UInt8)值的集合?


2.SCNetworkReachabilitySetCallback的回调函数。

该函数的第二个参数要求类型为SCNetworkReachabilityCallBack。我深入到源文件中,发现它实际上是一个typealias

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

我是这样定义的。

let reachabilityCallBack: SCNetworkReachabilityCallBack = {

}()

但是我收到错误消息 :期望在闭包中返回’SCNetworkReachabilityCallBack’的闭包中缺少返回,
当您在该类型别名中可以清楚地看到它返回时Void

这是错误的方法吗?


这些是我面临的问题。我来这里已经好几个小时了,没有运气,所以我非常感谢您的帮助。

谢谢。


阅读 391

收藏
2020-07-07

共1个答案

一尘不染

您的第一个问题可以用解决

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

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

更新: 正如Nate Cook在现在删除的答案中以及在这里所说的那样,您实际上可以将Swift字符串传递给UnsafePointer<UInt8>直接采用以下形式的函数:

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

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


Swift 2的更新: 现在可以将Swift闭包传递给带有函数指针参数的C函数。也
SCNetworkReachabilityCreateWithName() 不再返回非托管对象:

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)
2020-07-07