Accesso a ponte e puntatore senza pedine in Swift
-
21-12-2019 - |
Domanda
Sto portando un app da Objective-C a Swift e ho bisogno di utilizzare il seguente metodo:
CFStreamCreatePairWithSocketToHost(alloc: CFAllocator!, host: CFString!, port: UInt32, \
readStream: CMutablePointer<Unmanaged<CFReadStream>?>, \
writeStream: CMutablePointer<Unmanaged<CFWriteStream>?>)
.
La vecchia logica è simile a questa (che diversi siti Web sembrano essere d'accordo):
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;
.
che funziona bene grazie a Bridging senza pedine.Tuttavia, Arc non esiste in "Swift-Space" e il sistema di tipo è cambiato.
Come faccio a girare i miei flussi in istanze di
CMutablePointer<Unmanaged<CFReadStream>?>, and
CMutablePointer<Unmanaged<CFWriteStream>?>
.
e quindi convertili indietro nelle sottoclassi NSStream
dopo la chiamata CFStreamCreatePairWithSocketToHost
?
Soluzione
L'ho capito per lavorare, ecco il mio codice: Assicurati di tenere un riferimento della classe di connessione da qualche parte: -)
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")
}
}
. Altri suggerimenti
Non ero in grado di ottenere gli esempi che altri hanno fornito in questo thread per funzionare.Certo, hanno compilato, ma si sono schiantati non appena la connessione era aperta.
Tuttavia, ho notato nelle discussioni WWDC 2014 (e le note di rilascio iOS 8) che esiste un nuovo metodo per inizializzare un NSstream per la creazione di un paio di flussi / out rilegati.
Vedi sotto:
var inputStream: NSInputStream?
var outputStream: NSOutputStream?
NSStream.getStreamsToHostWithName("localhost", port: 1234, inputStream: &inputStream, outputStream: &outputStream)
.
Ciò rimuove la necessità per l'imbarazzante chiamata CFStreamCreatePairWithShelocketOhost e la rimozione della necessità di risorse non gestite.
Ho lavorato come farlo.Alcune note importanti:
- .
-
CMutablePointers
verrà creato automaticamente se si utilizza l'operatore e l'operatore. - È possibile ottenere al
T
in unUnmanaged<T>
con.getUnretainedValue()
egetRetainedValue()
(sembra.getUnretainedValue()
è analogo a__bridge_transfer
) - Le opzioni vengono inizializzate automaticamente in generatori di generazioneGode.
- Se un opzionale è
nil
si tradurrà in una condizionenil
.
finora ho (non testato):
var readStream: Unmanaged<CFReadStream>?
var writeStream: Unmanaged<CFWriteStream>?
CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, host, port, \
&readStream, &writeStream)
if (readStream && writeStream) {
inputStream = readStream!.takeUnretainedValue();
outputStream = writeStream!.takeUnretainedValue();
}
.Sto usando GetStreamstohostwithName Funzione della classe NSstream.È più facile e Beeter di cfstreamCreatePairWithSheetOhost
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 Versione di CF e codice NS.Entrambi lavorano per 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)")
}
}
.