我有一个Objective-C类,它实现了数据树的节点。它的属性对公众是只读的,而类的私有扩展(这里未显示)实现了属性的setter,因此manager类可以创建树。
// Interface
@interface DataSet : NSObject {
NSString *name;
NSString *data;
@private
DataSet *parent;
NSMutableArray *children;
}
@property (nonatomic, readonly, copy) NSString *name;
@property (nonatomic, readonly, copy) NSString *data;
我想为其中一个属性实现一个自定义getter,如果属性为nil,它将向上走,直到找到一个祖先节点,该节点具有该属性的非零值。
我的问题是实现getter而不会导致getter调用自身的无限递归。
// Implementation
@interface DataSet ()
@property (nonatomic, retain) DataSet *parent;
@property (nonatomic, retain) NSMutableArray *children;
@end
@implementation DataSet
@synthesize name;
// do not @synthesize data
@synthesize parent, children;
// custom getter walks up tree to find first non-nil 'data' property
- (NSString*) data {
NSString *result = nil;
DataSet *set = self;
while (set != nil && result == nil) {
result = [set data]; // <=== INFINITE RECURSION HERE
set = set.parent;
}
return result;
}
我搜索了这个和其他论坛,但没有找到我在这里尝试做的任何例子。有人有什么建议吗?
此外,如果getter中的最后一行是
return [result copy];
答案 0 :(得分:5)
-(NSString *) data {
// Determine result from current instance data.
NSString *result = ....;
// If nothing, ask parent instance of this instance.
if (result == nil) {
result = [parent data];
}
// Might still be nil if parent returns nothing.
return result;
}
嗯,实际上看到你有一个包含一些纹理数据的data
变量,可以这样做:
-(NSString *) data {
// If data is nil, ask parent instance for a value, otherwise return a copy.
return data == nil ? [parent data] : [data copy];
}
因此,DataSet的每个实例都不需要循环。他们所做的只是与他们的直接父母一起检查。这样,如果您有A - &gt;的数据图表。 B - &gt; C - &gt; D并执行[D data];
D将检查自身然后作为C,它将检查自身然后作为B,它将检查自己然后询问A.您将获得结果的第一个成功的非零值。
答案 1 :(得分:3)
直接访问ivar:
// custom getter walks up tree to find first non-nil 'data' property
- (NSString*) data {
NSString *result = nil;
DataSet *set = self;
while (set != nil && result == nil) {
result = set->data;
set = set->parent;
}
return [result copy];
}
这可以避免调用属性访问器,从而避免递归。
是的,最后一行应该是return [result copy];
,因为您声明您的属性具有copy
属性。如果您没有使用copy
属性声明它,那么您将不会返回副本。
答案 2 :(得分:0)
解决了它。
我可以在对象的父上递归调用自定义getter(但不能在对象本身上)。那不是问题。
当我释放对象时,关键是不要在dealloc中使用自定义getter,否则将会多次返回(并因此释放)某些“data”对象。
// custom getter - if data is nil on this object,
// find the first non-nil value in its list of ancestors
- (NSString*) data {
NSString *result = data;
if (result == nil && parent != nil)
result = [parent data];
return result;
}
- (void) dealloc {
NSInteger count = [children count];
for (NSInteger index = count - 1; index >= 0; --index) {
DataSet *child = [children objectAtIndex:index];
[children removeLastObject];
[child release];
}
[children release];
// DON'T call custom getter if data is nil
// or we'll get one of its ancestors' data object, release it,
// then later release it again when releasing the ancestor
if (data != nil)
[self.data release];
[self.name release];
[super dealloc];
}