我打算使用NSMutableDictionary
属性来存储游戏数据(例如得分,设置等......)。
@property (nonatomic, copy) NSMutableDictionary *gameData;
在研究为什么我找到this discussion的属性没有“mutablecopy”选项时,接受的答案表明:
正确的做法是不要让可变数组成为属性
在现代Objective-C中将可变集合作为属性处理的最佳方法是什么?
答案 0 :(得分:7)
对于类来说,暴露集合对象的可变属性是一种很少的模式,因为它似乎打破了封装。
然而是可能有意义的场合:例如,您可以为一些内部管理的集合返回一个KVO代理(使用KVC's mutableArrayValueForKey:
)。
在这些情况下,是否将getter声明为属性或普通方法并不重要。如果是属性,它不应该是copy
属性。
为了使这更清楚,这是一个例子。我们有一个声明一个公共getter的类:
@interface Foo : NSObject
@property (strong, readonly) NSMutableArray *publicBars;
@end
该实现管理一个名为_bars
的封装的私有可变数组:
@implementation Foo
{
NSMutableArray *_bars;
}
此数组的元素由KVC to-many accessors公开:
- (NSUInteger)countOfBars
{
return [_bars count];
}
- (id)objectInBarsAtIndex:(NSUInteger)idx
{
return _bars[idx];
}
- (void)insertObject:(id)object inBarsAtIndex:(NSUInteger)idx
{
if (_bars == nil)
_bars = [NSMutableArray array];
[_bars insertObject:object atIndex:idx];
}
- (void)removeObjectFromBarsAtIndex:(NSUInteger)idx
{
[_bars removeObjectAtIndex:idx];
}
这是花哨的部分:我们通过返回a KVC proxy that reflects and mutates the internal state而不暴露内部ivars来实现公共财产。它仅使用上面定义的公共访问器来更改内部数组。
- (NSMutableArray *)publicBars
{
return [self mutableArrayValueForKey:@"bars"];
}
@end
我们可以使用代理来更改内部集合:
Foo *foo = [[Foo alloc] init];
NSMutableArray *bars = foo.publicBars;
[bars addObject:@1];
[bars addObject:@2];
[bars removeObjectAtIndex:0];
// Now the internal _bars array is @[ @2 ].
在Cocoa中有这种和类似模式的实际例子。例如,有-[NSTextView textStorage]
返回内部后备存储(从NSMutableAttributedString
派生的对象)。虽然不是集合对象,但它是一个可变对象,它将突变传递给它的宿主对象,即文本视图。
答案 1 :(得分:1)
恕我直言,你可以很好地使用一个可变属性 - 因为Objective-C中的属性不仅用于封装,还用于内存管理(通过ARC)。
但是,您应该将此属性保留在实现文件中,并将其作为不可变的,只读的部分公开给其他类。
//your_header_file.h
@interface YouClass : NSObject
@property (readonly) NSDictionary *gameState;
@end
//your_implementation_file.m
@interface YouClass ()
@property (nonatomic, strong) NSMutableDictionary *gameState;
@end
@implementation SomeClass
//deal with mutable state here
@end
编辑:
此外,由于可变集合通常是非线程安全的,因此请确保始终从同一线程更改它们。
答案 2 :(得分:1)
可变属性的问题是其他类可以在没有所有者注意的情况下更改集合的内容。一个好的设计看到只有一个类负责一个特定的任务,在这种情况下存储游戏数据。
我要做的是将可变字典变为strong
私有属性,并以下列形式向外界提供访问者方法:
- (void)storeObject:(id)object forSetting:(NSString *)settingName;
- (id)objectForSetting:(NSString *)settingName;
如果你真的需要外部类能够设置字典作为一个整体,那么 - 确定这确实是必要的 - 你仍然可以使它成为一个不可变的属性, ,set时,从不可变字典中的项创建内部可变字典的新实例。但我认为你应该能够围绕这种必要性进行设计。