I have a class that represents a structure.
This class called Object
has the following properties
@property (nonatomic, strong) NSArray *children;
@property (nonatomic, assign) NSInteger type;
@property (nonatomic, strong) NSString *name;
@property (nonatomic, weak) id parent;
children
is an array of other Object
s. parent
is a weak reference to an object parent.
I am trying to do copy and paste a branch of this structure. If a root object is selected, parent
is nil, obviously. If the object is not the root, it has a parent.
To be able to do so, the objects of kind Object
have to conform to NSCopying
and NSCoding
protocols.
This is my implementation of these protocols on that class.
-(id) copyWithZone: (NSZone *) zone
{
Object *obj = [[Object allocWithZone:zone] init];
if (obj) {
[obj setChildren:_children];
[obj setType:_type];
[obj setName:_name];
[obj setParent:_parent];
}
return obj;
}
- (void)encodeWithCoder:(NSCoder *)coder {
[coder encodeObject:@(self.type) forKey:@"type"];
[coder encodeObject:self.name forKey:@"name"];
NSData *childrenData = [NSKeyedArchiver archivedDataWithRootObject:self.children];
[coder encodeObject:childrenData forKey:@"children"];
[coder encodeConditionalObject:self.parent forKey:@"parent"]; //*
}
- (id)initWithCoder:(NSCoder *)coder {
self = [super init];
if (self) {
_type = [[coder decodeObjectForKey:@"type"] integerValue];
_name = [coder decodeObjectForKey:@"name"];
_parent = [coder decodeObjectForKey:@"parent"]; //*
NSData *childrenData = [coder decodeObjectForKey:@"children"];
_children = [NSKeyedUnarchiver unarchiveObjectWithData:childrenData];
_parent = nil;
}
return self;
}
You may have notice that I have no reference to retrieve or storing self.parent
on initWithCoder:
and encodeWithCoder:
and because of that, every sub object of an object comes with parent = nil.
I simply don't know how to store that. Simply because of this. Suppose I have this structure of Object
.
ObjectA > ObjectB > ObjectC
When encoderWithCoder:
starts its magic encoding ObjectA
, it will also encode, ObjectB
and ObjectC
but when it starts encoding ObjectB
it finds a parent reference pointing to ObjectA
and will start that again, creating a circular reference that hangs the application. I tried that.
How do I encode/restore that parent reference?
What I need is to store an object and by the time of restore, to restore a new copy, identical to what was stored. I don't want to restore the same object that was stored, but rather, a copy.
NOTE: I have added the lines marked with //*
as suggested by Ken, but _parent
is nil on initWithCoder:
for objects that should have a parent