الوصول المجاني للجسر والمؤشر في Swift
-
21-12-2019 - |
سؤال
أقوم بنقل تطبيق من 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 الغريب بالإضافة إلى إزالة الحاجة إلى الموارد غير المُدارة.
لقد فكرت في كيفية القيام بذلك.بعض الملاحظات المهمة:
CMutablePointers
سيتم إنشاؤه تلقائيًا إذا كنت تستخدم عامل التشغيل &.- يمكنك الحصول على
T
فيUnmanaged<T>
مع.getUnretainedValue()
وgetRetainedValue()
(يبدو.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();
}
أنا أستخدم وظيفة 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)")
}
}