objective c - tutorial - Acceso gratuito a puentes y punteros en Swift
objective c vs swift (5)
Estoy usando la función getStreamsToHostWithName de la clase NSStream. Es más fácil y mejor que 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()
}
Estoy portando una aplicación de Objective-C a Swift y necesito usar el siguiente método:
CFStreamCreatePairWithSocketToHost(alloc: CFAllocator!, host: CFString!, port: UInt32, /
readStream: CMutablePointer<Unmanaged<CFReadStream>?>, /
writeStream: CMutablePointer<Unmanaged<CFWriteStream>?>)
La lógica antigua tiene este aspecto (en el que varios sitios web parecen estar de acuerdo):
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;
Lo que funciona bien gracias al puente gratuito. Sin embargo, ARC no existe en "Swift-space", y el sistema de tipos ha cambiado.
¿Cómo puedo convertir mis flujos en instancias de
CMutablePointer<Unmanaged<CFReadStream>?>, and
CMutablePointer<Unmanaged<CFWriteStream>?>
¿Y luego convertirlos de nuevo en subclases NSStream
después de la llamada CFStreamCreatePairWithSocketToHost
?
He resuelto cómo hacerlo. Algunas notas importantes:
-
CMutablePointers
creará automáticamente si utiliza el operador &. - Puedes obtener en la
T
en unUnmanaged<T>
.getUnretainedValue()
con.getUnretainedValue()
ygetRetainedValue()
(Parece que.getUnretainedValue()
es análogo a__bridge_transfer
) - Los opcionales se inicializan automáticamente a
nil
. - Si un opcional es
nil
, se traducirá en una condiciónfalse
.
Hasta ahora tengo (no probado):
var readStream: Unmanaged<CFReadStream>?
var writeStream: Unmanaged<CFWriteStream>?
CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, host, port, /
&readStream, &writeStream)
if (readStream && writeStream) {
inputStream = readStream!.takeUnretainedValue();
outputStream = writeStream!.takeUnretainedValue();
}
No pude hacer funcionar los ejemplos que otros han proporcionado en este hilo. Claro, compilaron, pero se bloquearon tan pronto como la conexión estaba abierta.
Sin embargo, noté en las discusiones de la WWDC 2014 (y en las notas de la versión de iOS 8) que hay un nuevo método para inicializar un NSStream para crear un par enlazado de flujos de entrada / salida.
Vea abajo:
var inputStream: NSInputStream?
var outputStream: NSOutputStream?
NSStream.getStreamsToHostWithName("localhost", port: 1234, inputStream: &inputStream, outputStream: &outputStream)
Esto elimina la necesidad de la incómoda llamada CFStreamCreatePairWithSocketToHost, así como la necesidad de recursos no administrados.
Tengo que funcionar, aquí está mi código: asegúrate de mantener una referencia de la clase de conexión en algún lugar :-)
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")
}
}
Versión Swift 3 de los códigos CF y NS. Ambos trabajan para mi.
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)")
}
}