Toll-free bridging and pointer access in Swift

前端 未结 5 1834
轮回少年
轮回少年 2020-12-13 19:33

I am porting an App from Objective-C to Swift and I need to use the following method:

CFStreamCreatePairWithSocketToHost(alloc: CFAllocator!, host: CFString!         


        
相关标签:
5条回答
  • 2020-12-13 20:08

    Swift 3 version of CF and NS code. Both work for me.

    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)")
    }
    
    }
    
    0 讨论(0)
  • 2020-12-13 20:18

    I got it to work, here's my code: Make sure you keep a reference of the connection class somewhere :-)

    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")
        }
    }
    
    0 讨论(0)
  • 2020-12-13 20:18

    I worked out how to do it. A few important notes:

    1. CMutablePointers will be automatically created if you use the & operator.
    2. You can get at the T in an Unmanaged<T> with .getUnretainedValue() and getRetainedValue() (Seems .getUnretainedValue() is analogous to __bridge_transfer)
    3. Optionals are automatically initialised to nil.
    4. If an optional is nil it will translate into a false condition.

    So far I have (untested):

    var readStream: Unmanaged<CFReadStream>?
    var writeStream: Unmanaged<CFWriteStream>?
    
    CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, host, port, \
    &readStream, &writeStream)
    
    if (readStream && writeStream) {
        inputStream = readStream!.takeUnretainedValue();
        outputStream = writeStream!.takeUnretainedValue();
    }
    
    0 讨论(0)
  • 2020-12-13 20:19

    I am using getStreamsToHostWithName function of NSStream class. It is more easy and beeter than 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()
    

    }

    0 讨论(0)
  • 2020-12-13 20:22

    I wasn't able to get the examples others have provided in this thread to work. Sure, they compiled, but they crashed as soon as the connection was open.

    However, I noticed in the WWDC 2014 discussions (and iOS 8 release notes) that there is a new method for initializing an NSStream for creating a bound pair of in/out streams.

    See below:

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

    This removes the need for the awkward CFStreamCreatePairWithSocketToHost call as well as removing the need for Unmanaged resources.

    0 讨论(0)
提交回复
热议问题