Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why don’t iOS classes adopt copyWithZone protocol to encourage active mem mgt?

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?

like image 483
Wienke Avatar asked Mar 18 '12 16:03

Wienke


2 Answers

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.

like image 64
Kurt Revis Avatar answered Nov 09 '22 10:11

Kurt Revis


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.

like image 27
Nick Ager Avatar answered Nov 09 '22 10:11

Nick Ager