سؤال

أقوم بنقل تطبيق من 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;

والذي يعمل بشكل جيد بفضل الجسر المجاني.ومع ذلك، ARC غير موجود في "Swift-space"، وقد تغير نظام الكتابة.

كيف يمكنني تحويل التدفقات الخاصة بي إلى مثيلات

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

ومن ثم تحويلهم مرة أخرى إلى NSStream الفئات الفرعية بعد CFStreamCreatePairWithSocketToHost يتصل؟

هل كانت مفيدة؟

المحلول

لقد نجحت في العمل، إليك الكود الخاص بي:تأكد من الاحتفاظ بمرجع لفئة الاتصال في مكان ما :-)

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. يمكنك الحصول على T في Unmanaged<T> مع .getUnretainedValue() و getRetainedValue() (يبدو .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();
}

أنا أستخدم وظيفة getStreamsToHostWithName لفئة NSStream.إنه أكثر سهولة وأفضل من CFStreamCreatePairWithSocketToHost

وظيفة 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()

}

إصدار سويفت 3 من كود CF وNS.كلاهما يعمل بالنسبة لي.

التليف الكيسي:

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

}

ن:

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

}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top