使用StreamDelegate / InputStream

时间:2017-08-23 14:55:16

标签: swift cocoa stream

我试图在Swift中创建一个客户端应用程序,并且我已经选择按照本教程作为灵感: https://www.raywenderlich.com/157128/real-time-communication-streams-tutorial-ios

我将二进制数据发送到输出流,我的服务器成功获取请求并回复。不幸的是,Swift客户端应用程序的StreamDelegate永远不会被触发。

我在Playgrounds中开发了一个类似于我的应用程序正在执行的HTTP请求的简单示例,并且出现了同样的问题:

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()

我收到了#34;发送了!&#34;控制台中的消息,但没有别的!我想到input.delegate = self,将使用响应调用流函数。我错过了什么?

1 个答案:

答案 0 :(得分:1)

正如@ martin-r想通的那样,我失踪了:

import UIKit
import PlaygroundSupport

...

google.query()

PlaygroundPage.current.needsIndefiniteExecution = true

编辑:如果某人遇到与我相同的问题(StreamDelegate从未触发过),可能与您的RunLoop有关。在raywenderlich.com示例和我在操场上制作的示例中,设置网络连接的函数是从主线程调用的,而在我的情况下,它没有从没有运行循环的另一个线程调用。我换了:

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

使用:

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

它开始无缝地工作。