3

我在头文件的类中声明了一个属性;

@property (readonly) NSArray *pages

这就是我希望它公开的方式。不过在内部,我将把它分配为 NSMutableArray,这样我就可以从中添加/删除东西。但要做到这一点,我每次都必须输入 cast 。有一个更好的方法吗?谢谢

4

2 回答 2

3

你的方法真的很糟糕。如果您坚持使用动态内容公开可变数组,则修改您的 getter 以返回不可变副本,否则您将在快速枚举期间获得奇怪的副作用和突变异常。

于 2012-09-26T00:51:24.223 回答
2

对此没有解决方案。您必须每次都进行投射,或使用不同的属性。这是第二种方法的示例:

@interface MyClass : NSObject
@property (nonatomic, strong, readonly) NSArray *pages;
-(void)addObject:(id)obj;
@end

@interface MyClass()
@property (nonatomic, strong, readwrite) NSMutableArray *mPages;
@end

@implementation MyClass
-(id) init {
    self = [super init]
    if (self){
        _mPages = [NSMutableArray array];
    }
    return self;
}
-(NSArray*)pages {
    return [NSArray arrayWithArray:self.mPages];
}
-(void)addObject:(id)obj {
    [self.mPages addObject:obj];
}
@end


int main(int argc, char *argv[]) {
    @autoreleasepool {
        MyClass *m = [MyClass new];
        [m addObject:@"x"];     // the collection is mutable
        NSLog(@"%@",[m pages]); // but only accessible as an immutable copy
    }
}

如果您经常访问集合,这将是昂贵的,并且可能与内部可变集合不同步(在您迭代副本时可能会发生变异)。

复制可以避免返回伪装成不可变类(NSArray)的内部可变实例(NSMutableArray),但这会带来以下风险:

  • 客户端可以转换为 mutable 并更改它。
  • 内部副本可能会发生变异。如果您正在迭代,这将使应用程序崩溃,或者可能导致索引超出范围异常。

请注意,以下成语不能解决问题:

@interface MyClass : NSObject
@property (nonatomic, strong, readonly) NSArray *pages;
@end

@interface MyClass()
@property (nonatomic, strong, readwrite) NSMutableArray *pages;
@end

这使您可以设置变量,但不能将其用作与接口中声明的类不同的类。换句话说,它迫使您在每次使用时都进行强制转换:

[(NSMutableArray*)pages addObject:@"x"];
于 2012-09-26T00:45:47.703 回答