Recently turning to iOS after having worked with Cocoa, I was startled to get a SIGABRT with the following error: “-[UIDeviceRGBColor copyWithZone:]: unrecognized selector sent to instance…” I had called “copy” on a UIColor.
I looked at the class references and, zounds, UIColor does not adopt any protocols, in contrast to NSColor.
Now, this is not a big deal. I was just attempting to be more efficient by taking active ownership of a color instance so as to discard it immediately after use. But I thought the purpose behind Apple’s omitting a garbage collector in iOS was to encourage developers to do exactly what I was doing, to keep a lean memory profile on the memory-starved, battery-challenged portable devices.
Any ideas on Apple’s rationale, or is there some error in my assumptions?
I don't understand why you think implementing the NSCopying
protocol would "encourage active memory management".
Since UIColor
is immutable (it implements no methods that change its internal state), there is no point making a copy. Just retain
it if you want to keep it around, and release
it when you're done. There is no need for anything else.
If you really wanted, you could add copying in a category:
@implementation UIColor (Copying) <NSCopying>
- (id)copyWithZone:(NSZone *)zone
{
return [self retain];
}
@end
But obviously that doesn't actually give you any new functionality. Apparently Apple didn't think it was worth the time when they implemented that class.
My app needs to work on both iOS5 (UIColor>>#copyWithZone
doesn't exist) and iOS6+ (UIColor>>#copyWithZone
exists) so I came up with the following:
@implementation UIColor(ios5CopyWithZone)
+ (void)initialize
{
// iOS5 dosn't include UIColor>>#copyWithZone so add it with class_addMethod.
// For iOS6+ class_addMethod fails as UIColor>>#copyWithZone already exists.
Class klass = [UIColor class];
Method methodToInstall = class_getInstanceMethod(klass, @selector(ios5CopyWithZone:));
class_addMethod(klass, @selector(copyWithZone:), method_getImplementation(methodToInstall), method_getTypeEncoding(methodToInstall));
}
// UIImage is immutable so can just return self.
// #retain to ensure we follow mem-management conventions
-(id)ios5CopyWithZone:(NSZone *)__unused zone
{
return [self retain];
}
@end
The code attempts to adds UIColor>>#copyWithZone
using the runtime's class_addMethod
. I don't know if this is any better than implementing UIColor>>#copyWithZone
directly in a category, however reading Apple's Avoid Category Method Name Clashes implies that it is bad practice to reimplement an existing framework method (that is UIColor>>#copyWithZone
in iOS6). However I realise that +initialize
could potentially trample on a framework's +initialize
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With