Frage

Ich portiere eine App von Objective-C nach Swift und muss die folgende Methode verwenden:

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

Die alte Logik sieht so aus (über die sich mehrere Websites einig zu sein scheinen):

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;

Was dank der gebührenfreien Überbrückung problemlos funktioniert.Allerdings existiert ARC im „Swift-Space“ nicht und das Typsystem hat sich geändert.

Wie verwandle ich meine Streams in Instanzen von

CMutablePointer<Unmanaged<CFReadStream>?>, and
CMutablePointer<Unmanaged<CFWriteStream>?>

Und wandeln Sie sie dann wieder in um NSStream Unterklassen nach dem CFStreamCreatePairWithSocketToHost Anruf?

War es hilfreich?

Lösung

Ich habe es zum Laufen gebracht, hier ist mein Code:Stellen Sie sicher, dass Sie irgendwo eine Referenz der Verbindungsklasse aufbewahren :-)

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

Andere Tipps

Ich konnte die Beispiele, die andere in diesem Thread bereitgestellt haben, nicht zum Laufen bringen.Sicher, sie haben kompiliert, aber sie sind abgestürzt, sobald die Verbindung geöffnet war.

Allerdings ist mir in den WWDC 2014-Diskussionen (und den Versionshinweisen zu iOS 8) aufgefallen, dass es eine neue Methode zum Initialisieren eines NSStreams zum Erstellen eines gebundenen Paars von Ein-/Aus-Streams gibt.

Siehe unten:

var inputStream: NSInputStream?
var outputStream: NSOutputStream?

NSStream.getStreamsToHostWithName("localhost", port: 1234, inputStream: &inputStream, outputStream: &outputStream)

Dadurch entfällt die Notwendigkeit des umständlichen CFStreamCreatePairWithSocketToHost-Aufrufs sowie der Bedarf an nicht verwalteten Ressourcen.

Ich habe herausgefunden, wie es geht.Ein paar wichtige Hinweise:

  1. CMutablePointers wird automatisch erstellt, wenn Sie den &-Operator verwenden.
  2. Sie können bei der T in einem (n Unmanaged<T> mit .getUnretainedValue() Und getRetainedValue() (Scheint .getUnretainedValue() ist analog zu __bridge_transfer)
  3. Optionale Optionen werden automatisch initialisiert nil.
  4. Wenn ein optionales ist nil es wird in a übersetzt false Zustand.

Bisher habe ich (ungetestet):

var readStream: Unmanaged<CFReadStream>?
var writeStream: Unmanaged<CFWriteStream>?

CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, host, port, \
&readStream, &writeStream)

if (readStream && writeStream) {
    inputStream = readStream!.takeUnretainedValue();
    outputStream = writeStream!.takeUnretainedValue();
}

Ich verwende die Funktion getStreamsToHostWithName der NSStream-Klasse.Es ist einfacher und einfacher als 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-Version des CF- und NS-Codes.Bei mir funktioniert beides.

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

}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top