使用Swift的C API

时间:2014-11-26 05:55:28

标签: ios c swift utf-8 callback

我正在尝试跟踪网络状态。我浏览了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方法。我无法在Objective-C中找到Swift等效的UTF8String属性。但是utf8类型有一个名为String的属性。根据{{​​3}},

  

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

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


2。 documentation的回调函数。

此函数的第二个参数需要SCNetworkReachabilityCallBack类型的东西。我潜入了源文件,发现它实际上是typealias

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

我这样定义了。

let reachabilityCallBack: SCNetworkReachabilityCallBack = {

}()

但是我收到错误在一个预期返回'SCNetworkReachabilityCallBack'的闭包中缺少返回,当你在该类型中时,你可以清楚地看到它返回Void

这是错误的方法吗?


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

谢谢。

1 个答案:

答案 0 :(得分:12)

您的第一个问题可以通过

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

在闭包内部,$0是指向NUL终止的UTF-8表示的指针 字符串。

更新:正如Nate Cook所述 现在已删除的答案以及here, 你实际上可以将一个Swift字符串传递给一个UnsafePointer<UInt8>的函数 直接:

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

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

另见Does Swift not work with function pointers?


更新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)