我试图在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
,将使用响应调用流函数。我错过了什么?
答案 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)
它开始无缝地工作。