Best practice when implementing copyWithZone:

I am trying to clarify some things in my head about the implementation of copyWithZone: can anyone comment on the following ...

 // 001: Crime is a subclass of NSObject. - (id)copyWithZone:(NSZone *)zone { Crime *newCrime = [[[self class] allocWithZone:zone] init]; if(newCrime) { [newCrime setMonth:[self month]]; [newCrime setCategory:[self category]]; [newCrime setCoordinate:[self coordinate]]; [newCrime setLocationName:[self locationName]]; [newCrime setTitle:[self title]]; [newCrime setSubtitle:[self subtitle]]; } return newCrime; } // 002: Crime is not a subclass of NSObject. - (id)copyWithZone:(NSZone *)zone { Crime *newCrime = [super copyWithZone:zone]; [newCrime setMonth:[self month]]; [newCrime setCategory:[self category]]; [newCrime setCoordinate:[self coordinate]]; [newCrime setLocationName:[self locationName]]; [newCrime setTitle:[self title]]; [newCrime setSubtitle:[self subtitle]]; return newCrime; } 

At 001:

  • Is it better to write the class name directly [[Crime allocWithZone:zone] init] or use [[[self Class] allocWithZone:zone] init] ?

  • Is it possible to use [self month] to copy iVars or should I directly access iVars, ie _month ?

+72
objective-c iphone cocoa-touch
Mar 28 2018-12-12T00:
source share
4 answers
  • You should always use [[self class] allocWithZone:zone] to make sure you create a copy using the appropriate class. The example you give for 002 shows why: Subclasses will call [super copyWithZone:zone] and expect to return an instance of the corresponding class, rather than an instance of the superclass.

  • I access ivars directly, so I donโ€™t have to worry about any side effects that I can add to the device properties (like generating notifications) later. Keep in mind that subclasses can override any method. In your example, you are sending two additional messages to ivar. I would execute it as follows:

the code:

 - (id)copyWithZone:(NSZone *)zone { Crime *newCrime = [super copyWithZone:zone]; newCrime->_month = [_month copyWithZone:zone]; newCrime->_category = [_category copyWithZone:zone]; // etc... return newCrime; } 

Of course, whether you copy ivars, save them, or just assign them, should reflect what setters do.

+92
Mar 28 2018-12-12T00:
source share

By default, the copyWithZone: method copy behavior with the provided SDK objects is a shallow copy. This means that if you call the copyWithZone: on NSString object, it will create a shallow copy, but not a deep copy. The difference between shallow and deep copy:

A shallow copy of an object copies links only to objects in the original array and places them in a new array.

A deep copy will actually copy the individual objects contained in the object. This is accomplished by sending each individual object in a copyWithZone: message in your custom class method.

INSHORT: To get a shallow copy, you call retain or strong for all instance variables. To get a deep copy, you call copyWithZone: for all instance variables in the custom class implementation copyWithZone: Now it is your choice.

+5
Apr 15 '15 at 15:06
source share

This is my model.

 #import <Foundation/Foundation.h> @interface RSRFDAModel : NSObject @property (nonatomic, assign) NSInteger objectId; @property (nonatomic, copy) NSString *name; @property (nonatomic, strong) NSArray<RSRFDAModel *> *beans; @end #import "RSRFDAModel.h" @interface RSRFDAModel () <NSCopying> @end @implementation RSRFDAModel -(id)copyWithZone:(NSZone *)zone { RSRFDAModel *model = [[[self class] allocWithZone:zone] init]; model.objectId = self.objectId; model.name = self.name; model.beans = [self.beans mutableCopy]; return model; } @end 
0
Aug 12 '16 at 7:29
source share

How about this one that implements a deep copy:

 /// Class Foo has two properties: month and category - (id)copyWithZone:(NSZone *zone) { Foo *newFoo; if ([self.superclass instancesRespondToSelector:@selector(copyWithZone:)]) { newFoo = [super copyWithZone:zone]; } else { newFoo = [[self.class allocWithZone:zone] init]; } newFoo->_month = [_month copyWithZone:zone]; newFoo->_category = [_category copyWithZone:zone]; return newFoo; } 
0
Aug 08 '17 at 3:18
source share



All Articles