1

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

  1. 发送命令
  2. 如果您没有收到来自硬件的反馈,它会尝试再发送几次
  3. 当应用收到反馈时,会发布通知 DidReceiveDataForRepeatSendingHandler(连同 userInfo 中的设备信息)

例如,假设我有一个可以对 3 个命令做出反应的窗帘:打开、关闭和停止……并且该窗帘当前是关闭的。我按打开(并且没有收到反馈),在此过程中我改变主意,所以我按停止。现在应用程序将同时发送这两个命令。

所以事不宜迟,代码如下:

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

我所做的是我创建了一个单独的类,其中我有一个字典,其中设备的 ManagedObjectID 作为键,我们发送的命令就是它的值。因此,每当我们为已在列表中的设备发送命令时,我都会发布通知 SameDeviceDifferentCommand,其中包含设备的 ManagedObjectID 和旧命令的 userInfo。我在 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 从通知中获取它的值 - 看起来它使用旧(nil)值,直到 repeatCounter 最大化。我不懂为什么。

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

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

4

0 回答 0