如何停止GCDAsyncUdpSocket发送命令?

时间:2017-10-23 10:12:14

标签: ios swift gcdasyncsocket gcdasyncudpsocket

我正在使用GCDAsyncUdpSocket在我的应用程序和一些智能家居硬件之间进行通信,我遇到了停止某个功能的问题。逻辑是这样的:

  1. 发送命令
  2. 如果您没有收到硬件的反馈,它会尝试多次发送
  3. 当应用收到反馈时,会发布通知DidReceiveDataForRepeatSendingHandler(以及userInfo中的设备信息)
  4. 例如,假设我有一个可以对3个命令做出反应的窗帘:打开,关闭和停止...并且该窗帘当前已关闭。 我按下Open(并且没有收到反馈),在此过程中我改变主意,所以我按下Stop。现在,该应用程序将同时发送两个命令。

    所以不用多说了,这是代码:

    class RepeatSendingHandler: NSObject {
    
    var byteArray: [UInt8]!
    var gateway: Gateway!
    var repeatCounter:Int = 1
    
    var device:Device!
    
    var appDel:AppDelegate!
    var error:NSError? = nil
    
    var sameDeviceKey: [NSManagedObjectID: NSNumber] = [:]
    var didGetResponse:Bool = false
    var didGetResponseTimer:Foundation.Timer!
    
    //
    // ================== Sending command for changing value of device ====================
    //
    init(byteArray:[UInt8], gateway: Gateway, device:Device, oldValue:Int) {
        super.init()
        appDel = UIApplication.shared.delegate as! AppDelegate
    
        self.byteArray = byteArray
        self.gateway = gateway
        self.device = device
    
        NotificationCenter.default.addObserver(self, selector: #selector(RepeatSendingHandler.didGetResponseNotification(_:)), name: NSNotification.Name(rawValue: NotificationKey.DidReceiveDataForRepeatSendingHandler), object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(sameDevice(_:)), name: NSNotification.Name(rawValue: NotificationKey.SameDeviceDifferentCommand), object: nil)
    
    
        sendCommand()
    
    }
    
    func updateRunnableList(deviceID: NSManagedObjectID) {
        RunnableList.sharedInstance.removeDeviceFromRunnableList(device: deviceID)
    }
    
    //   Did get response from gateway
    func didGetResponseNotification (_ notification:Notification) {
        if let info = (notification as NSNotification).userInfo! as? [String:Device] {
            if let deviceInfo = info["deviceDidReceiveSignalFromGateway"] {
                if device.objectID == deviceInfo.objectID {
                    didGetResponse = true
                    didGetResponseTimer = nil
                    NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NotificationKey.DidReceiveDataForRepeatSendingHandler), object: nil)
                }
            }
        }
    }
    
    func sameDevice(_ notification: Notification) {
        print("NOTIFICATION RECEIVED for device with ID: ", self.device.objectID, "\n")
        if let info = notification.userInfo as? [NSManagedObjectID: NSNumber] {
            sameDeviceKey = info
        }
    }
    
    func sendCommand () {
        if sameDeviceKey != [device.objectID: device.currentValue] { print("keys have DIFFERENT values") } else { print("keys have SAME values") }
    
        if sameDeviceKey != [device.objectID: device.currentValue] {
    
            if !didGetResponse {
                if repeatCounter < 4 {
    
                    print("Sending command. Repeat counter: ", repeatCounter)
    
                    SendingHandler.sendCommand(byteArray: byteArray, gateway: gateway)
                    didGetResponseTimer = Foundation.Timer.scheduledTimer(timeInterval: 2, target: self, selector: #selector(RepeatSendingHandler.sendCommand), userInfo: nil, repeats: false)
                    repeatCounter += 1
    
                } else {
                    didGetResponseTimer = nil
                    updateRunnableList(deviceID: device.objectID)
                    CoreDataController.shahredInstance.saveChanges()
                    NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NotificationKey.DidReceiveDataForRepeatSendingHandler), object: nil)
                    NotificationCenter.default.post(name: Notification.Name(rawValue: NotificationKey.RefreshDevice), object: self)
                }
            }else{
                didGetResponseTimer = nil
                updateRunnableList(deviceID: device.objectID)
                CoreDataController.shahredInstance.saveChanges()
                NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NotificationKey.DidReceiveDataForRepeatSendingHandler), object: nil)
                NotificationCenter.default.post(name: Notification.Name(rawValue: NotificationKey.RefreshDevice), object: self)
            }
        } else {
            print("Command canceled")
            didGetResponseTimer = nil
            return
        }
    
     }   
    

    在我保存设备的ViewController上,我称之为:

        func openCurtain(_ gestureRecognizer:UITapGestureRecognizer){
        let tag = gestureRecognizer.view!.tag
        let address = [UInt8(Int(devices[tag].gateway.addressOne)),UInt8(Int(devices[tag].gateway.addressTwo)),UInt8(Int(devices[tag].address))]
    
        if devices[tag].controlType == ControlType.Curtain {
                let setDeviceValue:UInt8 = 0xFF
                let deviceCurrentValue = Int(devices[tag].currentValue)
                devices[tag].currentValue = 0xFF // We need to set this to 255 because we will always display Channel1 and 2 in devices. Not 3 or 4. And this channel needs to be ON for image to be displayed properly
                let deviceGroupId = devices[tag].curtainGroupID.intValue
                CoreDataController.shahredInstance.saveChanges()
                DispatchQueue.main.async(execute: {
                    RunnableList.sharedInstance.checkForSameDevice(device: self.devices[tag].objectID, newCommand: NSNumber(value: setDeviceValue))
                    _ = RepeatSendingHandler(byteArray: OutgoingHandler.setCurtainStatus(address, value: setDeviceValue, groupId:  UInt8(deviceGroupId)), gateway: self.devices[tag].gateway, device: self.devices[tag], oldValue: deviceCurrentValue)
                })
            }
    }
    

    我做的是我创建了一个单独的类,其中我有一个字典,其中Device的ManagedObjectID作为键,我们发送的命令是它的值。因此,每当我们为已经在列表中的设备发送命令时,我都会发布一个通知SameDeviceDifferentCommand,其中包含userInfo,其中包含设备的ManagedObjectID和旧命令。我在RepeatSendingHandler上使用它来填充sameDeviceKey字典。这就是我试图区分应该停止哪个功能的方法。

    public class RunnableList {
    
    open static let sharedInstance = RunnableList()
    
    var runnableList: [NSManagedObjectID: NSNumber] = [:]
    
    func checkForSameDevice(device: NSManagedObjectID, newCommand: NSNumber) {
    
        if runnableList[device] != nil && runnableList[device] != newCommand {
                let oldDataToSend = [device: runnableList[device]!]
                NotificationCenter.default.post(name: Notification.Name(rawValue: NotificationKey.SameDeviceDifferentCommand), object: self, userInfo: oldDataToSend)
                print("Notification sent for device with ID: ", device, "\n")
        }
    
        runnableList[device] = newCommand
        print("Device with ID: ", device, "received a new command", newCommand, "\n")
    }
    
    func removeDeviceFromRunnableList(device: NSManagedObjectID) {
        runnableList.removeValue(forKey: device)
        print("Removed from list device with ID: ", device)
    }
    
    }
    

    然而,有时它确实应该这样做,有时却没有。使用一堆打印件,我试图看到一切都发生在哪个顺序,似乎有时即使sameDeviceKey从通知中获取它的值 - 看起来它使用旧的(零)值,直到repeatCounter最大化。我不明白为什么。

    有人能解释发生了什么,和/或建议比我提供的解决方案更好的解决方案吗?

    (我删除了一些额外的代码,因为它与逻辑/问题无关)。请记住,我是一名大三学生,我对此比较陌生。

0 个答案:

没有答案