Swift 1.2 同步请求的 GCDAsyncSocket
GCDAsyncSocket for Synchronous Requests with Swift 1.2
背景:
我正在使用 Swift 1.2(通过桥接头)成功地在一个项目上使用 GCDAsyncSocket
。
现在的挑战是它需要某种队列,因为它所连接的系统一次只能处理和return一个命令。
所以如果它连续调用方法,例如:
getSystemInfo()
getSystemStatus()
只有 getSystemInfo()
通过委托回调 return 发送,因为系统正忙于处理它,但是 getSystemStatus()
已成功发送 asynchronously
但未被处理控制器。我希望它能够使调用背靠背,并在控制器完成处理后让它们排队和处理,return返回先前的响应——基本上使过程同步。
问题:
正如您在下面的示例代码中看到的那样,didConnectToHost
委托回调,当它连接到控制器时,它调用 getSystemInfo()
然后 getSystemStatus()
背靠背,它应该从系统信息中获取结果后调用 getSystemStatus()
。
我一直在研究 NSCondition
、NSOperation
,甚至是 GCD,但我不确定最优雅的方法是什么。我不想再加入另一个队列处理器,因为已经为 GCDAsyncSocket
设置了队列。处理这个问题的最好、最优雅的方法是什么?
伪Class代码:
public class SendNet: NSObject, GCDAsyncSocketDelegate {
var socket:GCDAsyncSocket! = nil
func setupConnection(){
var error : NSError?
if (socket == nil) {
socket = GCDAsyncSocket(delegate: self, delegateQueue: dispatch_get_main_queue())
} else {
socket.disconnect()
}
if (!socket.connectToHost(host, onPort: port, withTimeout: 5.0, error: &error)){
println("Error: \(error)")
} else {
println("Connecting...")
}
}
public func socket(socket : GCDAsyncSocket, didConnectToHost host:String, port p:UInt16) {
println("Connected to \(host) on port \(p).")
self.socket = socket
getSystemInfo()
getSystemStatus()
}
func send(msgBytes: [UInt8]) {
var msgData = NSData(bytes: msgBytes, length: msgBytes)
socket.writeData(msgData, withTimeout: -1.0, tag: 0)
socket.readDataWithTimeout(-1.0, tag: 0)
}
func getSystemInfo() {
var sendBytes:[UInt8] = [0x0, 0x1, 0x2, 0x3]
send(sendBytes)
}
func getSystemStatus() {
var sendBytes:[UInt8] = [0x4, 0x5, 0x6, 0x7]
send(sendBytes)
}
public func socket(socket : GCDAsyncSocket!, didReadData data:NSData!, withTag tag:Int){
var msgData = NSMutableData()
msgData.setData(data)
var msgType:UInt16 = 0
msgData.getBytes(&msgType, range: NSRange(location: 2,length: 1))
println(msgType)
}
}
任何建议都将是很好的 -- 谢谢!
所以我决定为此使用 NSOperation。
使用以下代码创建了一个名为 SyncRequest.swift 的 class 文件:
import Foundation
class SyncRequest : NSOperation {
var socket:GCDAsyncSocket! = nil
var msgData:NSData! = nil
override var concurrent: Bool {
return false
}
override var asynchronous: Bool {
return false
}
private var _executing: Bool = false
override var executing: Bool {
get {
return _executing
}
set {
if (_executing != newValue) {
self.willChangeValueForKey("isExecuting")
_executing = newValue
self.didChangeValueForKey("isExecuting")
}
}
}
private var _finished: Bool = false;
override var finished: Bool {
get {
return _finished
}
set {
if (_finished != newValue) {
self.willChangeValueForKey("isFinished")
_finished = newValue
self.didChangeValueForKey("isFinished")
}
}
}
/// Complete the operation
func completeOperation() {
executing = false
finished = true
}
override func start() {
if (cancelled) {
finished = true
return
}
executing = true
main()
}
override func main() -> (){
println("starting...")
NSNotificationCenter.defaultCenter().addObserver(self, selector: "didReadData:", name: "DidReadData", object: nil)
sendData()
}
func sendData() {
socket.writeData(msgData, withTimeout: -1.0, tag: 0)
println("Sending: \(msgData)")
socket.readDataWithTimeout(-1.0, tag: 0)
}
func didReadData(notif: NSNotification) {
println("Data Received!")
NSNotificationCenter.defaultCenter().removeObserver(self, name: "DidReadData", object: nil)
completeOperation()
}
}
然后,当我需要向控制器发送内容时,我会执行以下操作:
// sync the request to the controller
let queue = NSOperationQueue() // sync request queue
let requestOperation = SyncRequest()
requestOperation.socket = socket // pass the socket to send through
requestOperation.msgData = msgData // pass the msgData to send
queue.maxConcurrentOperationCount = 1
queue.addOperation(requestOperation)
当数据来自您处理 GCDAsyncSocket 的 "didReadData" 委托的地方时,不要忘记发送 NSNotification。
public func socket(socket : GCDAsyncSocket!, didReadData data:NSData!, withTag tag:Int){
...
NSNotificationCenter.defaultCenter().postNotificationName("DidReadData", object: data)
...
}
背景:
我正在使用 Swift 1.2(通过桥接头)成功地在一个项目上使用 GCDAsyncSocket
。
现在的挑战是它需要某种队列,因为它所连接的系统一次只能处理和return一个命令。
所以如果它连续调用方法,例如:
getSystemInfo()
getSystemStatus()
只有 getSystemInfo()
通过委托回调 return 发送,因为系统正忙于处理它,但是 getSystemStatus()
已成功发送 asynchronously
但未被处理控制器。我希望它能够使调用背靠背,并在控制器完成处理后让它们排队和处理,return返回先前的响应——基本上使过程同步。
问题:
正如您在下面的示例代码中看到的那样,didConnectToHost
委托回调,当它连接到控制器时,它调用 getSystemInfo()
然后 getSystemStatus()
背靠背,它应该从系统信息中获取结果后调用 getSystemStatus()
。
我一直在研究 NSCondition
、NSOperation
,甚至是 GCD,但我不确定最优雅的方法是什么。我不想再加入另一个队列处理器,因为已经为 GCDAsyncSocket
设置了队列。处理这个问题的最好、最优雅的方法是什么?
伪Class代码:
public class SendNet: NSObject, GCDAsyncSocketDelegate {
var socket:GCDAsyncSocket! = nil
func setupConnection(){
var error : NSError?
if (socket == nil) {
socket = GCDAsyncSocket(delegate: self, delegateQueue: dispatch_get_main_queue())
} else {
socket.disconnect()
}
if (!socket.connectToHost(host, onPort: port, withTimeout: 5.0, error: &error)){
println("Error: \(error)")
} else {
println("Connecting...")
}
}
public func socket(socket : GCDAsyncSocket, didConnectToHost host:String, port p:UInt16) {
println("Connected to \(host) on port \(p).")
self.socket = socket
getSystemInfo()
getSystemStatus()
}
func send(msgBytes: [UInt8]) {
var msgData = NSData(bytes: msgBytes, length: msgBytes)
socket.writeData(msgData, withTimeout: -1.0, tag: 0)
socket.readDataWithTimeout(-1.0, tag: 0)
}
func getSystemInfo() {
var sendBytes:[UInt8] = [0x0, 0x1, 0x2, 0x3]
send(sendBytes)
}
func getSystemStatus() {
var sendBytes:[UInt8] = [0x4, 0x5, 0x6, 0x7]
send(sendBytes)
}
public func socket(socket : GCDAsyncSocket!, didReadData data:NSData!, withTag tag:Int){
var msgData = NSMutableData()
msgData.setData(data)
var msgType:UInt16 = 0
msgData.getBytes(&msgType, range: NSRange(location: 2,length: 1))
println(msgType)
}
}
任何建议都将是很好的 -- 谢谢!
所以我决定为此使用 NSOperation。
使用以下代码创建了一个名为 SyncRequest.swift 的 class 文件:
import Foundation
class SyncRequest : NSOperation {
var socket:GCDAsyncSocket! = nil
var msgData:NSData! = nil
override var concurrent: Bool {
return false
}
override var asynchronous: Bool {
return false
}
private var _executing: Bool = false
override var executing: Bool {
get {
return _executing
}
set {
if (_executing != newValue) {
self.willChangeValueForKey("isExecuting")
_executing = newValue
self.didChangeValueForKey("isExecuting")
}
}
}
private var _finished: Bool = false;
override var finished: Bool {
get {
return _finished
}
set {
if (_finished != newValue) {
self.willChangeValueForKey("isFinished")
_finished = newValue
self.didChangeValueForKey("isFinished")
}
}
}
/// Complete the operation
func completeOperation() {
executing = false
finished = true
}
override func start() {
if (cancelled) {
finished = true
return
}
executing = true
main()
}
override func main() -> (){
println("starting...")
NSNotificationCenter.defaultCenter().addObserver(self, selector: "didReadData:", name: "DidReadData", object: nil)
sendData()
}
func sendData() {
socket.writeData(msgData, withTimeout: -1.0, tag: 0)
println("Sending: \(msgData)")
socket.readDataWithTimeout(-1.0, tag: 0)
}
func didReadData(notif: NSNotification) {
println("Data Received!")
NSNotificationCenter.defaultCenter().removeObserver(self, name: "DidReadData", object: nil)
completeOperation()
}
}
然后,当我需要向控制器发送内容时,我会执行以下操作:
// sync the request to the controller
let queue = NSOperationQueue() // sync request queue
let requestOperation = SyncRequest()
requestOperation.socket = socket // pass the socket to send through
requestOperation.msgData = msgData // pass the msgData to send
queue.maxConcurrentOperationCount = 1
queue.addOperation(requestOperation)
当数据来自您处理 GCDAsyncSocket 的 "didReadData" 委托的地方时,不要忘记发送 NSNotification。
public func socket(socket : GCDAsyncSocket!, didReadData data:NSData!, withTag tag:Int){
...
NSNotificationCenter.defaultCenter().postNotificationName("DidReadData", object: data)
...
}