iosswiftcfstream

CFStreamCreatePairWithSocketToHost crashes unexpectedly with Swift


Finally time to ask my first question here!

Up front: Xcode 7.1.1, OS 10.11.2, iOS 9.0.2 (on physical device)

I'm writing a small app that communicates with my Raspberry Pi. I've got some working code that's written in Obj-C (for iOS 7) borrowed from a tutorial, and it all works fine for me in Obj-C (connects and behaves as expected with the Pi). The issue lies with rewriting it for Swift/iOS 9 (which is the goal).

The good bit:

func initNetworkCommunication() {
    var readStream: Unmanaged<CFReadStreamRef>?
    var writeStream: Unmanaged<CFWriteStreamRef>?

    CFStreamCreatePairWithSocketToHost(nil, "192.168.1.22", 777, &readStream, &writeStream)

    inputStream = readStream?.takeRetainedValue() as! NSInputStream
    outputStream = writeStream?.takeRetainedValue() as! NSOutputStream

    inputStream.scheduleInRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
    outputStream.scheduleInRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)

    inputStream.open()
    outputStream.open()
}

I believe the issue to lie in the above as this is the last method call in the stack, however the application crashes quietly with little information:

Crash Screen

Any help would be much appreciated!
Please feel free to ask for more information.

p.s. I understand the formatting on this site is rather "strict", anything I missed, overdid, etc, please let me know :)


Solution

  • I've solved it.

    Firstly:

    inputStream = readStream?.takeRetainedValue() as! NSInputStream
    outputStream = writeStream?.takeRetainedValue() as! NSOutputStream
    

    Should be:

    inputStream = readStream!.takeRetainedValue()
    outputStream = writeStream!.takeRetainedValue()
    

    Secondly, I abstracted the connection out of the ViewController (where I had this method initially) to a new class called Connection.

    Here's Connection:

    import UIKit
    
    class Connection: NSObject, NSStreamDelegate {
        var inputStream: NSInputStream!
        var outputStream: NSOutputStream!
    
        func connect() {
            var readStream:  Unmanaged<CFReadStream>?
            var writeStream: Unmanaged<CFWriteStream>?
    
            CFStreamCreatePairWithSocketToHost(nil, "192.168.1.22", 777, &readStream, &writeStream)
    
            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()
        }
    }
    

    Often I find starting to type these helps me out :p