I would like to a create convenience initiator by cloning an existing object with a mutation, while keeping the original object intact.
For example:
Given a Person object person1
with a name (Tom
) and age (10
)
I would like to clone the person1
object, but with 0 age.
I have following code in Obj-C, but not sure if there's a better way to do it:
Person.h
@interface Person : NSObject
@property (nonatomic, readonly) NSString *name;
@property (nonatomic, readonly) NSUInteger age;
- (instancetype)initWithName:(NSString *)name age:(NSUInteger)age;
- (instancetype)cloneWithZeroAge;
@end
Person.m
@implementation Person
- (instancetype)initWithName:(NSString *)name age:(NSUInteger)age
{
if (self = [super init]) {
_name = name;
_age = age;
}
return self;
}
- (instancetype)cloneWithZeroAge
{
if (self) {
// mutate age to 0
return [self initWithName:_name age:0];
}
return self;
}
@end
Let's start with the constructor. For you specific scenario it doesn't make much difference, but in order to be functionally independent, you better ensure that the name
gets a copy of the data passed. You also want to specify this part as memory storage modifier of the property, so the contract is apparent to the client code:
@interface Person : NSObject
@property (copy, nonatomic, readonly) NSString *name;
...
@end
@implementation Person
- (instancetype)initWithName:(NSString *)name age:(NSUInteger)age
{
if (self = [super init]) {
_name = [name copy];
_age = age;
}
return self;
}
Now for the actual "copy" method. In order to be more consistent with existing NSCopying
protocol and Objective-C naming convention, and, which is more important, the memory management ownership convention, you should start the method name with the word "copy", so the calling side knows it's responsible for releasing the object. The most important part now, is that if you want to keep the original object untouched, you have to allocate and create a new object. In your implementation, however, you just change the self
into the new object entirely. Here is how I would implement such a method:
- (instancetype)copyWithZeroAge {
Person *copy = [[Person alloc] initWithName:_name age:0];
return copy;
}
If you prefer to keep the name
property memory modifier strong
instead of copy
, don't forget to copy the instance:
- (instancetype)copyWithZeroAge {
Person *copy = [[Person alloc] initWithName:[_name copy]
age:0];
return copy;
}