2017-08-23 1 views
0

Je suis en train de faire une application cliente à Swift et j'ai choisi de suivre ce tutoriel comme une source d'inspiration: https://www.raywenderlich.com/157128/real-time-communication-streams-tutorial-iosTravailler avec StreamDelegate/InputStream

j'envoyer des données binaires dans le flux de sortie et mon serveur reçoit la demande avec succès et répond. Malheureusement, StreamDelegate de l'application client Swift n'est jamais déclenché.

J'ai développé dans le Playgrounds un exemple simple d'une requête HTTP similaire à ce que ma demande est en train de faire et le même problème se produit: « envoyé »

import UIKit 

class WebServerConnection: NSObject, StreamDelegate { 
    let host: String 
    var inputStream: InputStream! 
    var outputStream: OutputStream! 
    var responseHandler:((String) -> Void)? 

    init(_ host:String) { 
     self.host = host 
    } 

    func setup(responseHandler:((String) -> Void)?) { 
     self.responseHandler = responseHandler 
     var readStream: Unmanaged<CFReadStream>? 
     var writeStream: Unmanaged<CFWriteStream>? 
     CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, host as CFString, 80, &readStream, &writeStream) 
     inputStream = readStream!.takeRetainedValue() 
     outputStream = writeStream!.takeRetainedValue() 
     inputStream.delegate = self 
     inputStream.schedule(in: .current, forMode: .commonModes) 
     outputStream.schedule(in: .current, forMode: .commonModes) 
     inputStream.open() 
     outputStream.open() 
    } 

    func query(_ path:String = "/") { 
     let data = "GET \(path) HTTP/1.1\r\nhost: \(host)\r\n\r\n".data(using: .utf8)! 
     _ = data.withUnsafeBytes { outputStream.write($0, maxLength: data.count) } 
     print("sent!") 
    } 

    func stream(_ aStream: Stream, handle eventCode: Stream.Event) { 
     switch eventCode { 
     case Stream.Event.hasBytesAvailable: 
      printAvailableBytes(stream: aStream as! InputStream) 
     case Stream.Event.endEncountered: 
      print("<End Encountered>") 
     case Stream.Event.errorOccurred: 
      print("<Error occurred>") 
     default: 
      print("<Some other event>") 
     } 
    } 

    func printAvailableBytes(stream: InputStream) { 
     let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: 4096) 
     while stream.hasBytesAvailable { 
      let numberOfBytesRead = inputStream.read(buffer, maxLength: 4096) 
      if numberOfBytesRead < 0 { 
       if stream.streamError != nil { 
        break 
       } 
      } 

      if let message = String(bytesNoCopy: buffer, length: numberOfBytesRead, encoding: .utf8, freeWhenDone: true) { 
       responseHandler?(message) 
      } 
     } 
    } 

    func close() { 
     inputStream.close() 
     outputStream.close() 
    } 
} 

let google = WebServerConnection("google.com") 
google.setup() { message in 
    print(message) 
    google.close() 
} 
google.query() 

je suis la message dans la console, mais rien d'autre! Je pensais avec le input.delegate = self, la fonction de flux serait appelée avec la réponse. Qu'est-ce que je rate?

+1

Ce https://stackoverflow.com/q/24058336/1187415? –

+0

Merci, ça marche! Mais malheureusement, je ne peux pas reproduire le problème que j'ai avec mon application. Je vais essayer de reproduire. –

Répondre

0

Comme @ martin-r compris, je manquais:

import UIKit 
import PlaygroundSupport 

... 

google.query() 

PlaygroundPage.current.needsIndefiniteExecution = true 

Modifier: Si quelqu'un est d'avoir le même problème que moi, peut-être qu'il a (StreamDelegate jamais déclenché) quelque chose à voir avec votre RunLoop. Dans l'exemple de raywenderlich.com et dans l'exemple que j'ai fait dans le terrain de jeu, la fonction de configuration des connexions réseau a été appelée depuis le thread principal, alors que dans mon cas, elle n'était pas appelée depuis un autre thread. Je l'ai remplacé:

inputStream.schedule(in: .current, forMode: .commonModes) 
outputStream.schedule(in: .current, forMode: .commonModes) 

avec:

inputStream.schedule(in: .main, forMode: .commonModes) 
outputStream.schedule(in: .main, forMode: .commonModes) 

Et il a commencé à fonctionner en toute transparence.