iOS 套接字输入流阻塞 UI,但未安排在主线程上
iOS socket inputstream blocking UI, but not scheduled on main thread
当我的应用程序通过网络输入流接收数据时,会在主线程上调用相应的 streamDelegate。当接收大量数据时,UI 块值得注意。
我试图从
中触发所有相应的功能
DispatchQueue.global(qos: .whatever).sync()
但是虽然
inputStream.schedule(in: .current,forMode: .commonModes)
在该队列中调用,streamDelegate 仍在 Main 上调用?!
根据我的阅读和理解,到目前为止,.sync 对我没有任何帮助,因为它仍然会阻塞 UI,因为它会等待完成,然后再将控制权交还给 UI。所以我对 .async 进行了同样的尝试。当所有流的东西都在异步线程上工作时,outputStream 工作正常,但 inputStreams 的 streamDelegate 不会触发。我没有收到回复。
我做错了什么?
class AppDelegate {
let mSocketClass = SocketClass()
func application(_:){
DispatchQueue.global(qos: .utility).async(){
mSocketClass.setupNetworkCommunication()
mSocketClass.sendStuff()
}
}
}
.
class SocketClass:NSObject {
var mInputStream: InputStream!
var mOutputStream: OutputStream!
func setupNetworkCommunication(){
var readStream: Unmanaged<CFReadStream>?
var writeStream: Unmanaged<CFWriteStream>?
CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, "example.com" as CFString, 1234, &readStream, &writeStream)
mInputStream = readStream!.takeRetainedValue()
mOutputStream = writeStream!.takeRetainedValue()
mInputStream.schedule(in: .current, forMode: .commonModes) //happens on thread other than Main
mOutputStream.schedule(in: .current, forMode: .commonModes)
mInputStream.open()
mOutputStream.open()
mInputStream.delegate = self
}
func sendStuff(){
if mOutputStream.hasSpaceAvailable {
mOutputStream.write(...)
}
}
}
extension SocketClass:StreamDelegate{
func stream(_ aStream: Stream, handle eventCode: Stream.Event) {
switch eventCode {
case Stream.Event.hasBytesAvailable:
(aStream as! InputStream).read(...) //happens on Main
}
}
}
顺便说一句:我不喜欢使用框架的解决方案。在我看来,解决方案是更改我不明白的一行。
谢谢!
代码几乎没问题,但您需要在该线程上启动一个 运行 循环。
所以它应该看起来像:
DispatchQueue.global(qos: .utility).async(){
self.mSocketClass.setupNetworkCommunication()
RunLoop.current.run()
}
请注意:
RunLoop.current.run()
从来没有 returns。应该是您设置中的最后一行。
- 然后在后台线程上接收数据。如果你想在收到数据后更新你的用户界面,你必须使用
DispatchQueue.main.async() { /* UI updates */ }
让我知道它是如何为您服务的。
当我的应用程序通过网络输入流接收数据时,会在主线程上调用相应的 streamDelegate。当接收大量数据时,UI 块值得注意。 我试图从
中触发所有相应的功能DispatchQueue.global(qos: .whatever).sync()
但是虽然
inputStream.schedule(in: .current,forMode: .commonModes)
在该队列中调用,streamDelegate 仍在 Main 上调用?!
根据我的阅读和理解,到目前为止,.sync 对我没有任何帮助,因为它仍然会阻塞 UI,因为它会等待完成,然后再将控制权交还给 UI。所以我对 .async 进行了同样的尝试。当所有流的东西都在异步线程上工作时,outputStream 工作正常,但 inputStreams 的 streamDelegate 不会触发。我没有收到回复。
我做错了什么?
class AppDelegate {
let mSocketClass = SocketClass()
func application(_:){
DispatchQueue.global(qos: .utility).async(){
mSocketClass.setupNetworkCommunication()
mSocketClass.sendStuff()
}
}
}
.
class SocketClass:NSObject {
var mInputStream: InputStream!
var mOutputStream: OutputStream!
func setupNetworkCommunication(){
var readStream: Unmanaged<CFReadStream>?
var writeStream: Unmanaged<CFWriteStream>?
CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, "example.com" as CFString, 1234, &readStream, &writeStream)
mInputStream = readStream!.takeRetainedValue()
mOutputStream = writeStream!.takeRetainedValue()
mInputStream.schedule(in: .current, forMode: .commonModes) //happens on thread other than Main
mOutputStream.schedule(in: .current, forMode: .commonModes)
mInputStream.open()
mOutputStream.open()
mInputStream.delegate = self
}
func sendStuff(){
if mOutputStream.hasSpaceAvailable {
mOutputStream.write(...)
}
}
}
extension SocketClass:StreamDelegate{
func stream(_ aStream: Stream, handle eventCode: Stream.Event) {
switch eventCode {
case Stream.Event.hasBytesAvailable:
(aStream as! InputStream).read(...) //happens on Main
}
}
}
顺便说一句:我不喜欢使用框架的解决方案。在我看来,解决方案是更改我不明白的一行。
谢谢!
代码几乎没问题,但您需要在该线程上启动一个 运行 循环。
所以它应该看起来像:
DispatchQueue.global(qos: .utility).async(){
self.mSocketClass.setupNetworkCommunication()
RunLoop.current.run()
}
请注意:
RunLoop.current.run()
从来没有 returns。应该是您设置中的最后一行。- 然后在后台线程上接收数据。如果你想在收到数据后更新你的用户界面,你必须使用
DispatchQueue.main.async() { /* UI updates */ }
让我知道它是如何为您服务的。