Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios swift中的KVO绑定失败_Ios_Swift_Exc Bad Access_Key Value Observing - Fatal编程技术网

Ios swift中的KVO绑定失败

Ios swift中的KVO绑定失败,ios,swift,exc-bad-access,key-value-observing,Ios,Swift,Exc Bad Access,Key Value Observing,这个错误让我真的很沮丧。我使用KVO的方式如下: dynamic var product: NSNumber? { get { return (defaults.objectForKey("product") != nil ? defaults.integerForKey("product") : nil) } set(newValue) { if newValue != product { willChangeVa

这个错误让我真的很沮丧。我使用KVO的方式如下:

dynamic var product: NSNumber? {
    get {
        return (defaults.objectForKey("product") != nil ? defaults.integerForKey("product") : nil)
    }
    set(newValue) {
        if newValue != product {
            willChangeValueForKey("product")
            if let value = newValue {
                defaults.setInteger(value.integerValue, forKey: "product")
            } else {
                defaults.removeObjectForKey("product")
            }
            didChangeValueForKey("product")
            reader.product = newValue?.integerValue
            refresh()
        }
    }
}

override class func automaticallyNotifiesObserversForKey(key: String) -> Bool {
    return true
}
另一个对象修改属性,如下所示:

    info.product = NSNumber(short: prodId)
调用时,结果是以下错误:

    Thread 1: EXC_BAD_ACCESS(code=1, address = 0x0)
和堆栈跟踪:

#0  0x37c4cf66 in objc_msgSend ()
#1  0x2acca772 in NSKeyValuePushPendingNotificationPerThread ()
#2  0x2acbae3c in NSKeyValueWillChange ()
#3  0x2aca7c04 in -[NSObject(NSKeyValueObserverNotification) willChangeValueForKey:] ()
#4  0x2acdafc0 in _NSSetObjectValueAndNotify ()
#5  0x002a3c44 in Module.MyView.pickerView (Module.MyView)(ObjectiveC.UIPickerView, didSelectRow : Swift.Int, inComponent : Swift.Int) -> () at /<***>/MyView.swift:122

编辑此解决方案最初有效,但后来的更改使其无效

我刚刚找到了一个解决办法,对我来说,这似乎真的很愚蠢。我所要做的就是像这样移动
willChangeValueForKey
didChangeValueForKey
方法调用

dynamic var product: NSNumber? {
    get {
        return (defaults.objectForKey("product") != nil ? defaults.integerForKey("product") : nil)
    }
    set(newValue) {
        willChangeValueForKey("product")
        if newValue != product {
            if let value = newValue {
                defaults.setInteger(value.integerValue, forKey: "product")
            } else {
                defaults.removeObjectForKey("product")
            }
            reader.product = newValue?.integerValue
            refresh()
        }
        didChangeValueForKey("product")
    }
}
猜猜看,我会说实现是聪明的。如果它没有将调用
willChangeValueForKey
视为mutator方法中的第一件事,那么它会在进入mutator之前调用它,并破坏调用。移动了这些调用后,代码现在不会进行那些默认调用,并且所有调用都正常工作

required init(coder aDecoder: NSCoder) {
}

deinit {
    if annotation != nil {
        Static.info.removeObserver(self, forKeyPath: "product")
    }
}

override func observeValueForKeyPath(keyPath: String, ofObject object: AnyObject, change: [NSObject : AnyObject], context: UnsafeMutablePointer<Void>) {
    switch keyPath {
    case "product":
        dispatch_async(dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0)) {
            self.refreshText()
            self.refreshImages()
        }

    default:
        super.observeValueForKeyPath(keyPath, ofObject: object, change: change, context: context)
    }
}

override var annotation: MKAnnotation! {
    get {
        return super.annotation
    }
    set(newAnnotation) {
        if annotation != nil {
            Static.info.removeObserver(self, forKeyPath: "product")
        }
        super.annotation = newAnnotation
        if let annot = newAnnotation as? MyAnnotation {
            Static.info.addObserver(self, forKeyPath: "product", options: NSKeyValueObservingOptions.allZeros, context: nil)
            self.refreshText()
            self.refreshImages()
        }
    }
}

这听起来既聪明又愚蠢。其他意见?

编辑此解决方案最初有效,但后来的更改使其无效

我刚刚找到了一个解决办法,对我来说,这似乎真的很愚蠢。我所要做的就是像这样移动
willChangeValueForKey
didChangeValueForKey
方法调用

dynamic var product: NSNumber? {
    get {
        return (defaults.objectForKey("product") != nil ? defaults.integerForKey("product") : nil)
    }
    set(newValue) {
        willChangeValueForKey("product")
        if newValue != product {
            if let value = newValue {
                defaults.setInteger(value.integerValue, forKey: "product")
            } else {
                defaults.removeObjectForKey("product")
            }
            reader.product = newValue?.integerValue
            refresh()
        }
        didChangeValueForKey("product")
    }
}
猜猜看,我会说实现是聪明的。如果它没有将调用
willChangeValueForKey
视为mutator方法中的第一件事,那么它会在进入mutator之前调用它,并破坏调用。移动了这些调用后,代码现在不会进行那些默认调用,并且所有调用都正常工作

required init(coder aDecoder: NSCoder) {
}

deinit {
    if annotation != nil {
        Static.info.removeObserver(self, forKeyPath: "product")
    }
}

override func observeValueForKeyPath(keyPath: String, ofObject object: AnyObject, change: [NSObject : AnyObject], context: UnsafeMutablePointer<Void>) {
    switch keyPath {
    case "product":
        dispatch_async(dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0)) {
            self.refreshText()
            self.refreshImages()
        }

    default:
        super.observeValueForKeyPath(keyPath, ofObject: object, change: change, context: context)
    }
}

override var annotation: MKAnnotation! {
    get {
        return super.annotation
    }
    set(newAnnotation) {
        if annotation != nil {
            Static.info.removeObserver(self, forKeyPath: "product")
        }
        super.annotation = newAnnotation
        if let annot = newAnnotation as? MyAnnotation {
            Static.info.addObserver(self, forKeyPath: "product", options: NSKeyValueObservingOptions.allZeros, context: nil)
            self.refreshText()
            self.refreshImages()
        }
    }
}

这听起来既聪明又愚蠢。其他意见?

您必须确保致电didChangeValueForKey:willChangeValueForKey:。您不需要重写getter和setter来触发KVO通知。我不知道extact实现,但是看看你的类,如果info类必须触发产品更改通知,那么它会是这样的

 class MyInfoClass {
  var product: NSNumber?{
      willSet{
        self.willChangeValueForKey("product")
      }
      didSet{
        self.didChangeValueForKey("product")
      }
    }

  override class func automaticallyNotifiesObserversForKey(key: String) -> Bool {
    if key == "product"{
      return true
    }else{
      return automaticallyNotifiesObserversForKey(key)
    }
  }
}
class MyInfoClass:NSObject{
  dynamic var product: NSNumber?
}
但是,如果您希望使用动态,则不需要覆盖kvo方法自动通知服务器查询:,也不需要触发willChangeValueForKey:didChangeValueForKey:。请注意,您的类应该是NSObject的子类。在这种情况下,您的类将简单地如下所示

 class MyInfoClass {
  var product: NSNumber?{
      willSet{
        self.willChangeValueForKey("product")
      }
      didSet{
        self.didChangeValueForKey("product")
      }
    }

  override class func automaticallyNotifiesObserversForKey(key: String) -> Bool {
    if key == "product"{
      return true
    }else{
      return automaticallyNotifiesObserversForKey(key)
    }
  }
}
class MyInfoClass:NSObject{
  dynamic var product: NSNumber?
}

您必须确保调用didChangeValueForKey:willChangeValueForKey:。您不需要重写getter和setter来触发KVO通知。我不知道extact实现,但是看看你的类,如果info类必须触发产品更改通知,那么它会是这样的

 class MyInfoClass {
  var product: NSNumber?{
      willSet{
        self.willChangeValueForKey("product")
      }
      didSet{
        self.didChangeValueForKey("product")
      }
    }

  override class func automaticallyNotifiesObserversForKey(key: String) -> Bool {
    if key == "product"{
      return true
    }else{
      return automaticallyNotifiesObserversForKey(key)
    }
  }
}
class MyInfoClass:NSObject{
  dynamic var product: NSNumber?
}
但是,如果您希望使用动态,则不需要覆盖kvo方法自动通知服务器查询:,也不需要触发willChangeValueForKey:didChangeValueForKey:。请注意,您的类应该是NSObject的子类。在这种情况下,您的类将简单地如下所示

 class MyInfoClass {
  var product: NSNumber?{
      willSet{
        self.willChangeValueForKey("product")
      }
      didSet{
        self.didChangeValueForKey("product")
      }
    }

  override class func automaticallyNotifiesObserversForKey(key: String) -> Bool {
    if key == "product"{
      return true
    }else{
      return automaticallyNotifiesObserversForKey(key)
    }
  }
}
class MyInfoClass:NSObject{
  dynamic var product: NSNumber?
}

我无法重现您的问题(可能是因为我没有
reader
对象或
refresh()
函数),但您的代码正在为
产品生成两个(嵌套)KVN。如果
automaticallyNotifiesObserversForKey
返回
true
(这意味着
产品将自动发生KVN),则不应手动为该属性发布KVN

有两种选择:

  • 您可以关闭
    产品的自动KVN,然后自己动手:

    dynamic var product: NSNumber? {
        get {
            return defaults.objectForKey("product") as? NSNumber
        }
        set {
            if newValue != product {
                willChangeValueForKey("product")
                if let value = newValue {
                    defaults.setInteger(value.integerValue, forKey: "product")
                } else {
                    defaults.removeObjectForKey("product")
                }
                didChangeValueForKey("product")
                // reader.product = newValue?.integerValue
                // refresh()
            }
        }
    }
    
    override class func automaticallyNotifiesObserversForKey(key: String) -> Bool {
        if key == "product" {
            return false
        }
        return super.automaticallyNotifiesObserversForKey(key)   // prudent to call super rather than just returning `true`
    }
    
    dynamic var product: NSNumber? {
        get {
            return defaults.objectForKey("product") as? NSNumber
        }
        set {
            if newValue != product {
                if let value = newValue {
                    defaults.setInteger(value.integerValue, forKey: "product")
                } else {
                    defaults.removeObjectForKey("product")
                }
                // reader.product = newValue?.integerValue
                // refresh()
            }
        }
    }
    
    // we don't need this at all if all we're going to do is to return the super value
    //
    // override class func automaticallyNotifiesObserversForKey(key: String) -> Bool {
    //     return super.automaticallyNotifiesObserversForKey(key)
    // }
    
  • 您可以让自动KVN保持打开状态,然后不要自己执行:

    dynamic var product: NSNumber? {
        get {
            return defaults.objectForKey("product") as? NSNumber
        }
        set {
            if newValue != product {
                willChangeValueForKey("product")
                if let value = newValue {
                    defaults.setInteger(value.integerValue, forKey: "product")
                } else {
                    defaults.removeObjectForKey("product")
                }
                didChangeValueForKey("product")
                // reader.product = newValue?.integerValue
                // refresh()
            }
        }
    }
    
    override class func automaticallyNotifiesObserversForKey(key: String) -> Bool {
        if key == "product" {
            return false
        }
        return super.automaticallyNotifiesObserversForKey(key)   // prudent to call super rather than just returning `true`
    }
    
    dynamic var product: NSNumber? {
        get {
            return defaults.objectForKey("product") as? NSNumber
        }
        set {
            if newValue != product {
                if let value = newValue {
                    defaults.setInteger(value.integerValue, forKey: "product")
                } else {
                    defaults.removeObjectForKey("product")
                }
                // reader.product = newValue?.integerValue
                // refresh()
            }
        }
    }
    
    // we don't need this at all if all we're going to do is to return the super value
    //
    // override class func automaticallyNotifiesObserversForKey(key: String) -> Bool {
    //     return super.automaticallyNotifiesObserversForKey(key)
    // }
    

  • 我无法重现您的问题(可能是因为我没有
    reader
    对象或
    refresh()
    函数),但您的代码正在为
    产品生成两个(嵌套)KVN。如果
    automaticallyNotifiesObserversForKey
    返回
    true
    (这意味着
    产品将自动发生KVN),则不应手动为该属性发布KVN

    有两种选择:

  • 您可以关闭
    产品的自动KVN,然后自己动手:

    dynamic var product: NSNumber? {
        get {
            return defaults.objectForKey("product") as? NSNumber
        }
        set {
            if newValue != product {
                willChangeValueForKey("product")
                if let value = newValue {
                    defaults.setInteger(value.integerValue, forKey: "product")
                } else {
                    defaults.removeObjectForKey("product")
                }
                didChangeValueForKey("product")
                // reader.product = newValue?.integerValue
                // refresh()
            }
        }
    }
    
    override class func automaticallyNotifiesObserversForKey(key: String) -> Bool {
        if key == "product" {
            return false
        }
        return super.automaticallyNotifiesObserversForKey(key)   // prudent to call super rather than just returning `true`
    }
    
    dynamic var product: NSNumber? {
        get {
            return defaults.objectForKey("product") as? NSNumber
        }
        set {
            if newValue != product {
                if let value = newValue {
                    defaults.setInteger(value.integerValue, forKey: "product")
                } else {
                    defaults.removeObjectForKey("product")
                }
                // reader.product = newValue?.integerValue
                // refresh()
            }
        }
    }
    
    // we don't need this at all if all we're going to do is to return the super value
    //
    // override class func automaticallyNotifiesObserversForKey(key: String) -> Bool {
    //     return super.automaticallyNotifiesObserversForKey(key)
    // }
    
  • 您可以让自动KVN保持打开状态,然后不要自己执行:

    dynamic var product: NSNumber? {
        get {
            return defaults.objectForKey("product") as? NSNumber
        }
        set {
            if newValue != product {
                willChangeValueForKey("product")
                if let value = newValue {
                    defaults.setInteger(value.integerValue, forKey: "product")
                } else {
                    defaults.removeObjectForKey("product")
                }
                didChangeValueForKey("product")
                // reader.product = newValue?.integerValue
                // refresh()
            }
        }
    }
    
    override class func automaticallyNotifiesObserversForKey(key: String) -> Bool {
        if key == "product" {
            return false
        }
        return super.automaticallyNotifiesObserversForKey(key)   // prudent to call super rather than just returning `true`
    }
    
    dynamic var product: NSNumber? {
        get {
            return defaults.objectForKey("product") as? NSNumber
        }
        set {
            if newValue != product {
                if let value = newValue {
                    defaults.setInteger(value.integerValue, forKey: "product")
                } else {
                    defaults.removeObjectForKey("product")
                }
                // reader.product = newValue?.integerValue
                // refresh()
            }
        }
    }
    
    // we don't need this at all if all we're going to do is to return the super value
    //
    // override class func automaticallyNotifiesObserversForKey(key: String) -> Bool {
    //     return super.automaticallyNotifiesObserversForKey(key)
    // }
    

  • 我决定尝试另一种方法

    dynamic var product: NSNumber? = NSUserDefaults.standardUserDefaults().objectForKey("product") as? NSNumber
    
    override func observeValueForKeyPath(keyPath: String, ofObject object: AnyObject, change: [NSObject : AnyObject], context: UnsafeMutablePointer<Void>) {
        switch keyPath {
        case "product":
            if let value = product {
                defaults.setInteger(value.integerValue, forKey: "product")
            } else {
                defaults.removeObjectForKey("product")
            }
    
        default:
            break
        }
    }
    
    init() {
        self.addObserver(self, forKeyPath: "product", options: NSKeyValueObservingOptions.allZeros, context: nil)
    }
    
    deinit {
        self.removeObserver(self, forKeyPath: "product")
    }
    
    动态var产品:NSNumber?=NSUserDefaults.standardUserDefaults().objectForKey(“产品”)作为?数字对象
    重写func observeValueForKeyPath(键路径:字符串,对象对象:AnyObject,更改:[NSObject:AnyObject],上下文:UnsafeMutablePointer){
    开关键路径{
    案例“产品”:
    如果let值=乘积{
    defaults.setInteger(value.integerValue,forKey:“产品”)
    }否则{
    默认值。removeObjectForKey(“产品”)
    }
    违约:
    打破
    }
    }
    init(){
    addObserver(self,forKeyPath:“产品”,选项:NSKeyValueObservingOptions.allZeros,上下文:nil)
    }
    脱硝{
    self.removeObserver(self,forKeyPath:“产品”)
    }
    

    这种变化的结果是完全相同的;代码在消息分派期间崩溃。唯一的优点是,我认为这是比原来更干净的代码。

    我决定尝试另一种方法

    dynamic var product: NSNumber? = NSUserDefaults.standardUserDefaults().objectForKey("product") as? NSNumber
    
    override func observeValueForKeyPath(keyPath: String, ofObject object: AnyObject, change: [NSObject : AnyObject], context: UnsafeMutablePointer<Void>) {
        switch keyPath {
        case "product":
            if let value = product {
                defaults.setInteger(value.integerValue, forKey: "product")
            } else {
                defaults.removeObjectForKey("product")
            }
    
        default:
            break
        }
    }
    
    init() {
        self.addObserver(self, forKeyPath: "product", options: NSKeyValueObservingOptions.allZeros, context: nil)
    }
    
    deinit {
        self.removeObserver(self, forKeyPath: "product")
    }
    
    动态var产品:NSNumber?=NSUserDefaults.standardUserDefaults().objectForKey(“产品”)作为?数字对象
    重写func observeValueForKeyPath(键路径:字符串,对象对象:AnyObject,更改:[NSObject:AnyObject],上下文:UnsafeMutablePointer){
    开关键路径{
    案例“产品”:
    如果let值=乘积{
    defaults.setInteger(value.integerValue,forKey:“产品”)
    }否则{
    默认值。removeObjectForKey(“产品”)
    }
    违约:
    打破
    }
    }
    init(){
    addObserver(self,forKeyPath:“产品”,选项:NSKeyValueObservingOptions.allZeros,上下文:nil)
    }
    脱硝{
    self.removeObserver(self,forKeyPath:“produ