Swift中的免费桥接和指针访问



我正在将应用程序从Objective-C移植到Swift,我需要使用以下方法:

CFStreamCreatePairWithSocketToHost(alloc: CFAllocator!, host: CFString!, port: UInt32, 
readStream: CMutablePointer<Unmanaged<CFReadStream>?>, 
writeStream: CMutablePointer<Unmanaged<CFWriteStream>?>)

旧的逻辑是这样的(几个网站似乎都同意):

CFReadStreamRef readStream = NULL;
CFWriteStreamRef writeStream = NULL;
CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)(host), port, 
                                   &readStream, &writeStream);
NSInputStream inputStream = (__bridge_transfer NSInputStream *)readStream;
NSOutputStream outputStream = (__bridge_transfer NSOutputStream *)writeStream;

由于免费桥接,它工作得很好。但是,"Swift-space"中不存在ARC,并且类型系统发生了变化。

如何将我的流转换成

的实例
CMutablePointer<Unmanaged<CFReadStream>?>, and
CMutablePointer<Unmanaged<CFWriteStream>?>

然后在CFStreamCreatePairWithSocketToHost调用后将它们转换回NSStream子类?

我让它工作,这是我的代码:确保在某个地方保留了连接类的引用:-)

class Connection : NSObject, NSStreamDelegate {
    let serverAddress: CFString = "127.0.0.1"
    let serverPort: UInt32 = 8443
    private var inputStream: NSInputStream!
    private var outputStream: NSOutputStream!
    func connect() {
        println("connecting...")
        var readStream:  Unmanaged<CFReadStream>?
        var writeStream: Unmanaged<CFWriteStream>?
        CFStreamCreatePairWithSocketToHost(nil, self.serverAddress, self.serverPort, &readStream, &writeStream)
        // Documentation suggests readStream and writeStream can be assumed to
        // be non-nil. If you believe otherwise, you can test if either is nil
        // and implement whatever error-handling you wish.
        self.inputStream = readStream!.takeRetainedValue()
        self.outputStream = writeStream!.takeRetainedValue()
        self.inputStream.delegate = self
        self.outputStream.delegate = self
        self.inputStream.scheduleInRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
        self.outputStream.scheduleInRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
        self.inputStream.open()
        self.outputStream.open()
    }
    func stream(stream: NSStream, handleEvent eventCode: NSStreamEvent) {
        println("stream event")
    }
}

我无法得到其他人在这个线程中提供的例子。当然,它们编译了,但是一旦连接打开,它们就崩溃了。

然而,我注意到在WWDC 2014的讨论(以及iOS 8的发布说明)中,有一种新的方法可以初始化NSStream来创建绑定对的输入/输出流。

见下文:

var inputStream: NSInputStream?
var outputStream: NSOutputStream?
NSStream.getStreamsToHostWithName("localhost", port: 1234, inputStream: &inputStream, outputStream: &outputStream)

这消除了对笨拙的CFStreamCreatePairWithSocketToHost调用的需要,也消除了对非托管资源的需要。

我知道怎么做了。一些重要的注意事项:

  1. CMutablePointers将自动创建如果您使用&操作符。
  2. 你可以在Unmanaged<T>.getUnretainedValue()getRetainedValue()中得到T(似乎.getUnretainedValue()类似于__bridge_transfer)
  3. 可选项自动初始化为nil
  4. 如果可选项是nil,它将转换为false条件。

到目前为止,我已经(未经测试):

var readStream: Unmanaged<CFReadStream>?
var writeStream: Unmanaged<CFWriteStream>?
CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, host, port, 
&readStream, &writeStream)
if (readStream && writeStream) {
    inputStream = readStream!.takeUnretainedValue();
    outputStream = writeStream!.takeUnretainedValue();
}

我正在使用NSStream类的getStreamsToHostWithName函数。它比CFStreamCreatePairWithSocketToHost更简单,更好

func initNetworkCommunication() {

print("connecting...")
let serverAddress = "gzoa.vps.infomaniak.com"
let serverPort = 1234
NSStream.getStreamsToHostWithName(serverAddress, port: serverPort, inputStream: &inputStream, outputStream: &outputStream)
self.inputStream!.delegate = self
self.outputStream!.delegate = self
self.inputStream!.scheduleInRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
self.outputStream!.scheduleInRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
self.inputStream!.open()
self.outputStream!.open()

}

Swift 3版本的CF和NS代码。两个都适合我。

CF:

class Connection: NSObject, StreamDelegate {
private var inputStream: InputStream!
private var outputStream: OutputStream!
var connected = false
func connect(host: String, port: UInt32) {
    var readStream:  Unmanaged<CFReadStream>?
    var writeStream: Unmanaged<CFWriteStream>?
    CFStreamCreatePairWithSocketToHost(nil, host as CFString, port, &readStream, &writeStream)
    self.inputStream = readStream!.takeRetainedValue()
    self.outputStream = writeStream!.takeRetainedValue()
    if let inputStream = inputStream, let outputStream = outputStream {
        inputStream.delegate = self
        outputStream.delegate = self
        inputStream.schedule(in: RunLoop.current, forMode: RunLoopMode.defaultRunLoopMode)
        outputStream.schedule(in: RunLoop.current, forMode: RunLoopMode.defaultRunLoopMode)
        inputStream.open()
        outputStream.open()
        connected = true
    }
}
func stream(_ aStream: Stream, handle eventCode: Stream.Event) {
    print("stream event, (eventCode)")
}
}

NS:

class NSConnection: NSObject, StreamDelegate {
private var inputStream: InputStream?
private var outputStream: OutputStream?
var connected = false
func connect(host: String, port: Int) {
    Stream.getStreamsToHost(withName: host, port: port, inputStream: &inputStream, outputStream: &outputStream)
    if let inputStream = inputStream, let outputStream = outputStream {
        inputStream.delegate = self
        outputStream.delegate = self
        inputStream.schedule(in: RunLoop.current, forMode: RunLoopMode.defaultRunLoopMode)
        outputStream.schedule(in: RunLoop.current, forMode: RunLoopMode.defaultRunLoopMode)
        inputStream.open()
        outputStream.open()
    }
}
func stream(_ aStream: Stream, handle eventCode: Stream.Event) {
    print("stream event, (eventCode)")
}
}

最新更新