So, Apple’s documentation says that CIImage
conforms to Equatable
. I would take this to mean that the following unit test would pass. However, it doesn’t. I’m interested in why.
func test_CIImageEqualityShouldWork() {
let bundle = NSBundle(forClass: PrototypeTests.self)
guard let path = bundle.pathForResource("testImage", ofType: "png") else { return }
guard let image = UIImage(contentsOfFile: path) else { return }
let thingy1 = CIImage(image: image)
let thingy2 = CIImage(image: image)
XCTAssert(thingy1 == thingy2)
}
The image exists, the guard
statements both pass, but the assert fails, they aren’t equal.
Out of interest, I’ve tried creating the UIImage
twice and comparing those too. That also fails.
All NSObject
subclasses conform to Equatable
, and the ==
function
calls the isEqual:
method on the objects.
The isEqual:
method
of NSObject
simply compares the object pointers, i.e. o1 == o2
holds if o1
and o2
refer the same object instance.
See for example Interacting with Objective-C APIs:
Swift provides default implementations of the == and === operators and adopts the Equatable protocol for objects that derive from the NSObject class. The default implementation of the == operator invokes the isEqual: method, and the default implementation of the === operator checks pointer equality. You should not override the equality or identity operators for types imported from Objective-C.
The base implementation of the isEqual: provided by the NSObject class is equivalent to an identity check by pointer equality.
Many NSObject
subclasses override the isEqual:
method (e.g. NSString
,
NSArray
, NSDate
, ...) but not CIImage
:
let thingy1 = CIImage(image: image)
let thingy2 = CIImage(image: image)
creates two different CIImage
instances and these compare as "not equal".