iosswiftnsdateswift-extensionsexc-bad-instruction

Swift Extension exception Execution was interrupted, reason: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)


I have tried to do an extension to NSDate. What I wanted is a flag indicating if the NSDate has to be removed later

So I have tried this in playground

//: Playground - noun: a place where people can play

import UIKit

var str = "Hello, playground"



extension NSDate {
    private struct RemovalInformation {
        static var removed: Bool = false
    }
    var removed: Bool {
        get {
            return (objc_getAssociatedObject(self, &RemovalInformation.removed) as! Bool)
        }
        set(newValue) {
            objc_setAssociatedObject(self, &RemovalInformation.removed, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
        }
    }
}

let date = NSDate()
print( "The Date is: \(date)")

if(date.removed == true) {
    print ("removed")
}

But line if(date.removed == true) produces an error I have no clue how to deal with: "EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)"

enter image description here


Solution

  • objc_getAssociatedObject returns nil if no object has been associated to the NSDate, and then the forced cast as! Bool crashes. (It would also crash if an associated object has been set, but its value is not convertible to Bool.)

    You can make the property optional:

    var removed: Bool? {
        get {
            return objc_getAssociatedObject(self, &RemovalInformation.removed) as? Bool
        }
        set(newValue) {
            objc_setAssociatedObject(self, &RemovalInformation.removed, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
        }
    }
    

    or provide a default value, e.g. using the nil-coalescing operator ??:

    var removed: Bool {
        get {
            return objc_getAssociatedObject(self, &RemovalInformation.removed) as? Bool ?? false
        }
        set(newValue) {
            objc_setAssociatedObject(self, &RemovalInformation.removed, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
        }
    }
    

    Note that &RemovalInformation.removed only serves as a memory address identifying the associated object uniquely. The contents of that static property and its type is irrelevant and not used at all. In particular, the object association is not "initialized" with the value of that property.