使用Swift中的C API [英] Working with C APIs from Swift

查看:257
本文介绍了使用Swift中的C API的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在追踪网络状态。我浏览了 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 方法。我找不到确切的Swift等价于 UTF8String 属性在Objective-C。但是对于 String 类型,有一个名为 utf8 的属性。根据文档


您可以通过遍历其utf8属性来访问String的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



这是错误的方法吗?





$ b b

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


$ b

谢谢。

解决方案

您的第一个问题可以通过

  withCString {
SCNetworkReachabilityCreateWithName(nil,$ 0).takeRetainedValue()
}

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



更新:由于 Nate Cook
a中说现在已删除答案并且还可以这里
,你实际上可以将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(
中的可达性,{(_,flags,_)print(flags)
},& context)

SCNetworkReachabilityScheduleWithRunLoop ,CFRunLoopGetMain(),kCFRunLoopCommonModes)

Swift 3(Xcode 8) strong>

  let host =google.com
var context = SCNetworkReachabilityContext(version:0,info:nil ,retain:nil,release:nil,copyDescription:nil)
let reachability = SCNetworkReachabilityCreateWithName(nil,host)!

SCNetworkReachabilitySetCallback(
中的可达性,{(_,flags,_)print(flags)
},& context)

SCNetworkReachabilityScheduleWithRunLoop ,CFRunLoopGetMain(),
CFRunLoopMode.commonModes.rawValue)


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);
    }
}

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. Converting the host string to 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,

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:

How can I get a complete UTF8 representation of a string instead of a collection of unsigned 8-bit (UInt8) values?


2. Callback function for SCNetworkReachabilitySetCallback.

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

I defined it like this.

let reachabilityCallBack: SCNetworkReachabilityCallBack = {

}()

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.

Is this the wrong way to do this?


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.

Thank you.

解决方案

Your first problem can be solved with

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

Inside the closure, $0 is a pointer to the NUL-terminated UTF-8 representation of the String.

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()


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.

See also Does Swift not work with function pointers?.


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)

Update for 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆