使用 Swift 的 C API [英] Working with C APIs from Swift
问题描述
我正在尝试跟踪网络状态.我浏览了 FXReachability 的代码.具体方法如下.
I'm trying to keep track of the network status. I went through the code of the FXReachability. Specifically the following method.
- (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,但遇到了一些问题.
What it does is it keeps checking the connection to the specified host. I'm trying to convert this method to Swift and I'm having a couple of problems.
1.将主机字符串转换为 UTF8.
我必须将主机字符串转换为 UTF8 并将其传递到 SCNetworkReachabilityCreateWithName 方法.我在 Objective-C 中找不到 UTF8String
属性的确切 Swift 等价物.但是对于 String
类型有一个名为 utf8
的属性.根据文档,
I have to convert the host string to UTF8 and pass it into the SCNetworkReachabilityCreateWithName method. I can't find the exact Swift equivalent of UTF8String
property in Objective-C. But there is a property called utf8
for the String
type. According to the documentation,
您可以通过迭代字符串的 utf8 属性来访问字符串的 UTF-8 表示.此属性的类型为 String.UTF8View,它是无符号 8 位 (UInt8) 值的集合,字符串的 UTF-8 表示中的每个字节对应一个值:
You can access a UTF-8 representation of a String by iterating over its utf8 property. This property is of type String.UTF8View, which is a collection of unsigned 8-bit (UInt8) values, one for each byte in the string’s UTF-8 representation:
如何获得字符串的完整 UTF8 表示而不是无符号 8 位 (UInt8) 值的集合?
How can I get a complete UTF8 representation of a string instead of a collection of unsigned 8-bit (UInt8) values?
2.的回调函数SCNetworkReachabilitySetCallback.
此函数的第二个参数需要 SCNetworkReachabilityCallBack
类型的内容.我深入研究源文件,发现它实际上是一个 typealias
.
Th second parameter of this function expects something of type SCNetworkReachabilityCallBack
. I dived in to the source file and found out that it's actually a typealias
.
typealias SCNetworkReachabilityCallBack = CFunctionPointer<((SCNetworkReachability!, SCNetworkReachabilityFlags, UnsafeMutablePointer<Void>) -> Void)>
我是这样定义的.
let reachabilityCallBack: SCNetworkReachabilityCallBack = {
}()
但是我收到错误 Missing return in a closure expected to return 'SCNetworkReachabilityCallBack' 在该类型别名中,您可以清楚地看到它返回 Void
.
But I get the error Missing return in a closure expected to return 'SCNetworkReachabilityCallBack' when in that typealias you can clearly see that it returns Void
.
这是错误的做法吗?
这些是我面临的问题.我已经在这工作了几个小时但运气不佳,所以我非常感谢您的帮助.
These are the problems I'm facing. I've been at this for hours now with no luck so I'd really appreciate any help.
谢谢.
推荐答案
你的第一个问题可以用
let reachability = host.withCString {
SCNetworkReachabilityCreateWithName(nil, $0).takeRetainedValue()
}
在闭包内部,$0
是一个指向 NUL 终止的 UTF-8 表示的指针字符串.
Inside the closure, $0
is a pointer to the NUL-terminated UTF-8 representation of the
String.
更新:正如 Nate Cook 在现已删除的答案以及此处,您实际上可以将 Swift 字符串传递给采用 UnsafePointer<UInt8>
的函数直接:
Update: As Nate Cook said in
a now deleted answer and also here,
you can actually pass a Swift string to a function taking a UnsafePointer<UInt8>
directly:
let reachability = SCNetworkReachabilityCreateWithName(nil, host).takeRetainedValue()
<小时>
不幸的是(据我所知)目前没有解决您的第二个问题的方法.SCNetworkReachabilitySetCallback
需要一个指向 C 函数的指针作为第二个参数,并且目前没有传递 Swift 函数或闭包的方法.请注意 SCNetworkReachabilityCallBack
只显示 Objective-C 而没有 Swift.
Unfortunately there is (as far as I know) currently no solution to your second problem.
SCNetworkReachabilitySetCallback
expects a pointer to a C function as second
parameter, and there is currently no method to pass a Swift function or closure.
Note that the documentation for SCNetworkReachabilityCallBack
shows only Objective-C but no Swift.
另请参阅Swift 是否不能使用函数指针?.
Swift 2 更新: 现在可以传递 Swift 闭包到带有函数指针参数的 C 函数.还SCNetworkReachabilityCreateWithName()
不再返回非托管对象:
Update for Swift 2: It is now possible to pass a Swift closure
to a C function taking a function pointer parameter. Also
SCNetworkReachabilityCreateWithName()
does not return an unmanaged object anymore:
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)
这篇关于使用 Swift 的 C API的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!