繁体   English   中英

Objective-C自定义属性getter无限递归

[英]Objective-C custom property getter infinite recursion

我有一个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];

嗯,我想你想要这样的东西:

-(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 - > B - > C - > D的数据图并执行[D data]; D将检查自身,然后检查为C,它将检查自身,然后检查为B,它将检查自身,然后询问A.您将获得结果的第一个成功的非零值。

只需直接访问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属性声明它,那么您将不会返回副本。

解决了它。

我可以在对象的对象上递归调用自定义getter(但不能在对象本身上)。 那不是问题。

关键是当我释放对象时不在dealloc中使用自定义getter,否则将会多次返回(并因此释放)一些“数据”对象。

// 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];
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM