I've defined a class where I'd like a public property to appear as though it is backed by an NSArray
. That is simple enough, but in my case the actual backing ivar is an NSMutableArray
:
我定义了一个类,我希望公共属性看起来像NSArray的支持。这很简单,但在我的情况下,实际的支持ivar是一个NSMutableArray:
@interface Foo
{
NSMutableArray* array;
}
@property (nonatomic, retain) NSArray* array;
@end
In my implementation file (*.m
) I @synthesize
the property but I immediately run into warnings because using self.words
is the same as trying to modifying an NSArray
.
在我的实现文件(*.m)中,我@synthesize这个属性,但是我马上会遇到警告,因为使用self。单词和试图修改NSArray是一样的。
What is the correct way to do this?
正确的方法是什么?
Thanks!
谢谢!
6 个解决方案
#1
21
I would declare a readonly
NSArray
in your header and override the getter for that array to return a copy of a private NSMutableArray
declared in your implementation. Consider the following.
我将在header中声明一个readonly NSArray,并覆盖该数组的getter,以返回在实现中声明的私有NSMutableArray的副本。考虑以下。
Foo.h
foo。
@interface Foo
@property (nonatomic, retain, readonly) NSArray *array;
@end
Foo.m
Foo.m
@interface Foo ()
@property (nonatomic, retain) NSMutableArray *mutableArray
@end
#pragma mark -
@implementation Foo
@synthesize mutableArray;
- (NSArray *)array
{
return [[self.mutableArray copy] autorelease];
}
@end
#2
14
Basically, put the NSArray property in a category in your header file and the NSMutableArray property in the class extension in your implementation file. Like so...
基本上,将NSArray属性放在头文件的类别中,在实现文件的类扩展中使用NSMutableArray属性。像这样…
Foo.h:
foo。:
@interface Foo
@end
@interface Foo (Collections)
@property (nonatomic, readonly, strong) NSArray *someArray;
@end
Foo.m
Foo.m
@interface Foo ()
@property (nonatomic, readwrite, strong) NSMutableArray *someArray;
@end
#3
5
Simple:
简单:
1) Don't use a property when it ain't one.
1)不要在没有财产的情况下使用。
2) Code simplifies to:
2)简化了代码:
- (NSArray *)currentArray {
return [NSArray arraywithArray:mutableArray]; // need the arrayWithArray - otherwise the caller could be in for surprise when the supposedly unchanging array changes while he is using it.
}
- (void)setArray:(NSArray *)array {
[mutableArray setArray:array];
}
When the object is alloced create the array, when it dies, dealloc the array.
当对象被分配时,创建数组,当它死亡时,dealloc数组。
When large effects happen at the mere use of a '.' operator, its easy to overlook hugely inefficient code. Accessors are just that. Also - if someone calls aFoo.array - the contract is to get access to foo's array members - but really its just a copy at the time of the call. The difference is real enough that it caused bugs in the other implentations posted here.
当巨大的影响发生在仅仅使用a '。操作人员,很容易忽略极其低效的代码。访问器。另外,如果有人打电话给aFoo。数组——合同是访问foo的数组成员——但实际上它只是调用时的一个副本。两者的差别实在是太大了,以至于导致了其他的错误。
#4
4
Update: this answer is not valid anymore. Use one of suggested solutions below.
更新:这个答案不再有效。使用下面建议的解决方案之一。
These days you can do the following:
现在你可以做到以下几点:
Foo.m:
Foo.m:
@implementation Foo {
NSMutableArray* _array;
}
@end
Foo.h:
foo。:
@interface Foo
@property (readonly, strong) NSArray* array;
@end
You can still address mutable _array by ivar from the inside of implementation and outside it will be accessible via immutable property. Unfortunately this doesn't guarantee that others can't cast it to NSMutableArray and modify. For better protection from idiots you must define accessor method and return immutable copy, however that might be very expensive in some cases.
您仍然可以通过ivar从实现的内部来处理可变的_array,并且可以通过不可变的属性访问它。不幸的是,这并不能保证其他人不能将其转换为NSMutableArray和modify。为了更好地保护您的idiots,您必须定义accessor方法并返回不可变副本,但是在某些情况下这可能非常昂贵。
I would actually agree with one of the comments above that it's better to use simple accessor methods if you need to return some read-only data, it's definitely less ambiguous.
我实际上同意上面的一个评论,如果您需要返回一些只读数据,那么最好使用简单的访问器方法,这绝对不那么模糊。
#5
2
That's because your property must match the actual ivar's class type.
这是因为您的属性必须与ivar的类类型相匹配。
A possible solution/workaround:
一种可能的解决方案/方法:
//Foo.h:
@interface Foo
{
NSMutableArray* mutableArray;
}
@property (readwrite, nonatomic, retain) NSArray* array;
//or manual accessor declarations, in case you're picky about wrapper-properties.
@end
//Foo.m:
@interface Foo ()
@property (readwrite, nonatomic, retain) NSMutableArray* mutableArray;
@end
@implementation
@synthesize mutableArray;
@dynamic array;
- (NSArray *)array {
return [NSArray arrayWithArray:self.mutableArray];
}
- (void)setArray:(NSArray *)array {
self.mutableArray = [NSMutableArray arrayWithArray:array];
}
@end
You're adding a private mutableArray
property in a class extension and making the public array
simply forward to your private mutable one.
您在一个类扩展中添加了一个私有的mutableArray属性,并将公共数组简单地转发给私有的可变数组。
With the most recent language extensions of ObjC I tend to remove the
在最近的语言扩展的ObjC中,我倾向于删除。
{
NSMutableArray* mutableArray;
}
ivar block entirely, if possible.
如果可能的话,完全使用ivar块。
And define the ivar thru the synthesization, as such:
并定义ivar thru的合成,如:
@synthesize mutableArray = _mutableArray;
which will generate a NSMutableArray *_mutableArray;
instance for you.
它将生成一个NSMutableArray *_mutableArray;实例。
#6
0
Simplest answer: your property type (NSArray) doesn't match your instance variable type (NSMutableArray).
最简单的回答:您的属性类型(NSArray)与实例变量类型(NSMutableArray)不匹配。
This is yet another good reason that you shouldn't define your own backing variables. Let @synthesize set up your instance variables; don't do it by hand.
这也是您不应该定义自己的后备变量的另一个好理由。让@synthesize设置实例变量;不要用手做。
#1
21
I would declare a readonly
NSArray
in your header and override the getter for that array to return a copy of a private NSMutableArray
declared in your implementation. Consider the following.
我将在header中声明一个readonly NSArray,并覆盖该数组的getter,以返回在实现中声明的私有NSMutableArray的副本。考虑以下。
Foo.h
foo。
@interface Foo
@property (nonatomic, retain, readonly) NSArray *array;
@end
Foo.m
Foo.m
@interface Foo ()
@property (nonatomic, retain) NSMutableArray *mutableArray
@end
#pragma mark -
@implementation Foo
@synthesize mutableArray;
- (NSArray *)array
{
return [[self.mutableArray copy] autorelease];
}
@end
#2
14
Basically, put the NSArray property in a category in your header file and the NSMutableArray property in the class extension in your implementation file. Like so...
基本上,将NSArray属性放在头文件的类别中,在实现文件的类扩展中使用NSMutableArray属性。像这样…
Foo.h:
foo。:
@interface Foo
@end
@interface Foo (Collections)
@property (nonatomic, readonly, strong) NSArray *someArray;
@end
Foo.m
Foo.m
@interface Foo ()
@property (nonatomic, readwrite, strong) NSMutableArray *someArray;
@end
#3
5
Simple:
简单:
1) Don't use a property when it ain't one.
1)不要在没有财产的情况下使用。
2) Code simplifies to:
2)简化了代码:
- (NSArray *)currentArray {
return [NSArray arraywithArray:mutableArray]; // need the arrayWithArray - otherwise the caller could be in for surprise when the supposedly unchanging array changes while he is using it.
}
- (void)setArray:(NSArray *)array {
[mutableArray setArray:array];
}
When the object is alloced create the array, when it dies, dealloc the array.
当对象被分配时,创建数组,当它死亡时,dealloc数组。
When large effects happen at the mere use of a '.' operator, its easy to overlook hugely inefficient code. Accessors are just that. Also - if someone calls aFoo.array - the contract is to get access to foo's array members - but really its just a copy at the time of the call. The difference is real enough that it caused bugs in the other implentations posted here.
当巨大的影响发生在仅仅使用a '。操作人员,很容易忽略极其低效的代码。访问器。另外,如果有人打电话给aFoo。数组——合同是访问foo的数组成员——但实际上它只是调用时的一个副本。两者的差别实在是太大了,以至于导致了其他的错误。
#4
4
Update: this answer is not valid anymore. Use one of suggested solutions below.
更新:这个答案不再有效。使用下面建议的解决方案之一。
These days you can do the following:
现在你可以做到以下几点:
Foo.m:
Foo.m:
@implementation Foo {
NSMutableArray* _array;
}
@end
Foo.h:
foo。:
@interface Foo
@property (readonly, strong) NSArray* array;
@end
You can still address mutable _array by ivar from the inside of implementation and outside it will be accessible via immutable property. Unfortunately this doesn't guarantee that others can't cast it to NSMutableArray and modify. For better protection from idiots you must define accessor method and return immutable copy, however that might be very expensive in some cases.
您仍然可以通过ivar从实现的内部来处理可变的_array,并且可以通过不可变的属性访问它。不幸的是,这并不能保证其他人不能将其转换为NSMutableArray和modify。为了更好地保护您的idiots,您必须定义accessor方法并返回不可变副本,但是在某些情况下这可能非常昂贵。
I would actually agree with one of the comments above that it's better to use simple accessor methods if you need to return some read-only data, it's definitely less ambiguous.
我实际上同意上面的一个评论,如果您需要返回一些只读数据,那么最好使用简单的访问器方法,这绝对不那么模糊。
#5
2
That's because your property must match the actual ivar's class type.
这是因为您的属性必须与ivar的类类型相匹配。
A possible solution/workaround:
一种可能的解决方案/方法:
//Foo.h:
@interface Foo
{
NSMutableArray* mutableArray;
}
@property (readwrite, nonatomic, retain) NSArray* array;
//or manual accessor declarations, in case you're picky about wrapper-properties.
@end
//Foo.m:
@interface Foo ()
@property (readwrite, nonatomic, retain) NSMutableArray* mutableArray;
@end
@implementation
@synthesize mutableArray;
@dynamic array;
- (NSArray *)array {
return [NSArray arrayWithArray:self.mutableArray];
}
- (void)setArray:(NSArray *)array {
self.mutableArray = [NSMutableArray arrayWithArray:array];
}
@end
You're adding a private mutableArray
property in a class extension and making the public array
simply forward to your private mutable one.
您在一个类扩展中添加了一个私有的mutableArray属性,并将公共数组简单地转发给私有的可变数组。
With the most recent language extensions of ObjC I tend to remove the
在最近的语言扩展的ObjC中,我倾向于删除。
{
NSMutableArray* mutableArray;
}
ivar block entirely, if possible.
如果可能的话,完全使用ivar块。
And define the ivar thru the synthesization, as such:
并定义ivar thru的合成,如:
@synthesize mutableArray = _mutableArray;
which will generate a NSMutableArray *_mutableArray;
instance for you.
它将生成一个NSMutableArray *_mutableArray;实例。
#6
0
Simplest answer: your property type (NSArray) doesn't match your instance variable type (NSMutableArray).
最简单的回答:您的属性类型(NSArray)与实例变量类型(NSMutableArray)不匹配。
This is yet another good reason that you shouldn't define your own backing variables. Let @synthesize set up your instance variables; don't do it by hand.
这也是您不应该定义自己的后备变量的另一个好理由。让@synthesize设置实例变量;不要用手做。