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

我一直在研究 NSConditionNSOperation,甚至是 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)
  ...

}