ultima tutorial objective logo ejemplos objective-c core-foundation swift toll-free-bridging

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:

  1. CMutablePointers creará automáticamente si utiliza el operador &.
  2. Puedes obtener en la T en un Unmanaged<T> .getUnretainedValue() con .getUnretainedValue() y getRetainedValue() (Parece que .getUnretainedValue() es análogo a __bridge_transfer )
  3. Los opcionales se inicializan automáticamente a nil .
  4. Si un opcional es nil , se traducirá en una condición false .

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