GCDAsyncSocket for synchronous requests with Swift 1.2

Background:

I have been using it GCDAsyncSocket

in a project successfully with Swift 1.2 (via bridge header).

Now the problem is that it needs some kind of queue because the system it connects to can only process and return one command at a time.

So if it calls methods back like:

getSystemInfo()
getSystemStatus()

      

Only the returned one is getSystemInfo()

returned via the delegate callback because the system was busy processing it, however it getSystemStatus()

was sent asynchronously

successfully but was not processed by the controller. I would like it to be able to make callbacks back and have them in the queue and process as soon as the controller has processed and returned the previous response - basically making the process synchronous.

Question:

As shown below in the code example below, the didConnectToHost

delegate callback, when it connects to the controller, it calls getSystemInfo()

, then getSystemStatus()

back, it should call getSystemStatus()

after it has received the system information results.

I've looked NSCondition

, NSOperation

even GCD, but I'm not sure what is the most elegant way to approach this. I don't want to put another queue processor in the mix as there is already a queue setup for GCDAsyncSocket

. What's the best, most elegant way to handle this?

Pseudo class code:

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)

      }
}

      

Any suggestions would be great - thanks!

+3


source to share


1 answer


So I decided to use NSOperation for this.

Created a class file SyncRequest.swift with the following code:

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

    }

}

      

Then, when I need to send something to the controller, I do the following:



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

      

Remember to send an NSNotification when data comes in from where you are handling the "didReadData" GCDAsyncSocket delegate.

public func socket(socket : GCDAsyncSocket!, didReadData data:NSData!, withTag tag:Int){

  ...
  NSNotificationCenter.defaultCenter().postNotificationName("DidReadData", object: data)
  ...

}

      

+2


source







All Articles