Numéro sans frais de la transition et du pointeur de l'accès au réseau Swift
-
21-12-2019 - |
Question
Je suis le portage d'une Application à partir de l'Objective-C, Swift et j'ai besoin d'utiliser la méthode suivante:
CFStreamCreatePairWithSocketToHost(alloc: CFAllocator!, host: CFString!, port: UInt32, \
readStream: CMutablePointer<Unmanaged<CFReadStream>?>, \
writeStream: CMutablePointer<Unmanaged<CFWriteStream>?>)
La vieille logique ressemble à ceci (ce que plusieurs sites web semblent être d'accord):
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;
Qui fonctionne très bien grâce au numéro sans frais de transition.Toutefois, l'ARC n'existe pas dans "Swift-espace", et le type de système a changé.
Comment puis-je activer mon flux dans les instances de
CMutablePointer<Unmanaged<CFReadStream>?>, and
CMutablePointer<Unmanaged<CFWriteStream>?>
Et puis les convertir en arrière dans NSStream
les sous-classes après la CFStreamCreatePairWithSocketToHost
appel?
La solution
Je l'ai eu à travailler, voici mon code:Assurez-vous de garder une référence de la classe de connexion quelque part :-)
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")
}
}
Autres conseils
Je n'étais pas en mesure d'obtenir les exemples d'autres, ont apporté dans ce fil de travail.Bien sûr, ils ont compilé, mais ils se sont écrasés dès que la connexion a été ouverte.
Cependant, j'ai remarqué dans la WWDC 2014 discussions (et iOS 8 release notes) qu'il existe une nouvelle méthode pour initialiser un NSStream pour la création d'un bond paire d'entrée/sortie flux.
Voir ci-dessous:
var inputStream: NSInputStream?
var outputStream: NSOutputStream?
NSStream.getStreamsToHostWithName("localhost", port: 1234, inputStream: &inputStream, outputStream: &outputStream)
Ceci élimine le besoin pour le maladroit CFStreamCreatePairWithSocketToHost appel ainsi que la suppression de la nécessité pour les ressources non managées.
J'ai travaillé sur la façon de le faire.Quelques remarques importantes:
CMutablePointers
sera automatiquement créé si vous utilisez l'opérateur&.- Vous pouvez obtenir à la
T
dans unUnmanaged<T>
avec.getUnretainedValue()
etgetRetainedValue()
(Il semble.getUnretainedValue()
est analogue à__bridge_transfer
) - Options sont automatiquement initialisées à
nil
. - Si une option est
nil
il va se traduire par unefalse
condition.
Jusqu'à présent j'ai (non testé):
var readStream: Unmanaged<CFReadStream>?
var writeStream: Unmanaged<CFWriteStream>?
CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, host, port, \
&readStream, &writeStream)
if (readStream && writeStream) {
inputStream = readStream!.takeUnretainedValue();
outputStream = writeStream!.takeUnretainedValue();
}
Je suis à l'aide de getStreamsToHostWithName fonction de NSStream classe.Il est plus facile et beeter 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()
}
Swift 3 version de CF et NS code.Tant de travail pour moi.
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)")
}
}