我正在将应用程序从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调用的需要,也消除了对非托管资源的需要。
我知道怎么做了。一些重要的注意事项:
-
CMutablePointers
将自动创建如果您使用&操作符。 - 你可以在
Unmanaged<T>
和.getUnretainedValue()
和getRetainedValue()
中得到T
(似乎.getUnretainedValue()
类似于__bridge_transfer
) - 可选项自动初始化为
nil
。 - 如果可选项是
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)")
}
}