Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Accessing NSCache via subscript in Swift 3

Tags:

swift

A lot of devs like to extend NSCache to make it compatible with subscripts using something like the code snippet here, but this has stopped working in Swift 3. It's currently a known bug being tracked here on Swift.org. In the meantime, has anybody found another way to get the same result? I don't want to change my whole code base, but I also don't know how soon this bug will be addressed

// Allows using subscripts on NSCache, like a dictionary
extension NSCache {
subscript(key: AnyObject) -> AnyObject? {
    get {
        return object(forKey: key as! KeyType)
    }
    set {
        if let value: AnyObject = newValue {
            setObject(value as! ObjectType, forKey: key as! KeyType)
        } else {
            removeObject(forKey: key as! KeyType)
        }
    }
}
like image 646
Erik Avatar asked Sep 19 '16 12:09

Erik


1 Answers

Possible workarounds until SR-2104 is fixed:

Option 1

When you can substitute cache objects with arbitrary class, not inherited from NSCache, then you could wrap NSCache in a generic container, and forward necessary methods:

class WrappedCache<Key, Value> where Key: AnyObject, Value: AnyObject {

    let cache = NSCache<Key, Value>()

    subscript(key: Key) -> Value? {
        get {
            return cache.object(forKey: key)
        }
        set {
            if let newValue = newValue {
                cache.setObject(newValue, forKey: key)
            }
            else {
                cache.removeObject(forKey: key)
            }
        }
    }
}

You might get away passing inner cache value, if you must.

Option 2

When you must reference NSCache, and have limited number of specific cache types, you can specialize them, with each one having its own subscript implementation:

class NumberCache : NSCache<NSString, NSNumber> {

    subscript(key: NSString) -> NSNumber? {
        get {
            return object(forKey: key)
        }
        set {
            if let newValue = newValue {
                setObject(newValue, forKey: key)
            }
            else {
                removeObject(forKey: key)
            }
        }
    }
}
like image 196
paiv Avatar answered Sep 28 '22 19:09

paiv