我正在使用GCDAsyncUdpSocket在我的应用程序和一些智能家居硬件之间进行通信,我遇到了停止某个功能的问题。逻辑是这样的:
例如,假设我有一个可以对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最大化。我不明白为什么。
有人能解释发生了什么,和/或建议比我提供的解决方案更好的解决方案吗?
(我删除了一些额外的代码,因为它与逻辑/问题无关)。请记住,我是一名大三学生,我对此比较陌生。