2

The following code works perfectly well, but I am surprised, because I thought NSCache would require object keys & values, and would not take CGFloats. Can someone explain to me what is happening?

class A
    var cachedPoints = NSCache()

    func rAt(theta theta: CGFloat) -> CGFloat {        
        if let r = self.cachedPoints.objectForKey(theta) as? CGFloat {
            return r
        }
        // do some very expensive maths here...
        let r = self.veryExpensiveFunction(theta)
        self.cachedPoints.setObject(r, forKey: theta)
        return r
    }
}
Grimxn
  • 22,115
  • 10
  • 72
  • 85

1 Answers1

2

From Working with Cocoa Data Types in the "Using Swift with Cocoa and Objective-C" documentation:

Numbers

Swift automatically bridges certain native number types, such as Int and Float, to NSNumber.
...
It also allows you to pass a value of type Int, for example, to an argument expecting an NSNumber.

The documentation mentions Int, UInt, Float, Double, Bool as types which are automatically bridged to NSNumber, but apparently this works for CGFloat as well (if "Foundation" is imported). So in

self.cachedPoints.setObject(r, forKey: theta)

both r and theta are wrapped into NSNumber instances and then passed to the setObject() method which takes two parameters of type AnyObject.

There is also a bridging in the reverse direction, but that is less well documented (or I could not find it). You can cast an instance of NSNumber to CGFloat (or Int, Float, ...)

let num : NSNumber = ...
let x = num as CGFloat

and the result is the same as if you called doubleValue (or floatValue, depending on the architecture) on the number instance. In

let obj : AnyObject = ...
let y = obj as? CGFloat // CGFloat?

the object is optionally cast to NSNumber and – if that was successful – converted to CGFloat as in the previous example.

And that is what happens in

if let r = self.cachedPoints.objectForKey(theta) as? CGFloat { ... }

If the return value from objectForKey() is an NSNumber then it is converted to CGFloat and assigned to r. Otherwise, the optional binding fails.

Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • Many thanks! I had originally used NSNumber, but it looked so clunky compared to `Dictionary` usage I just decided to try. Looks like I need to re-read the books again! – Grimxn Nov 02 '15 at 18:55