当我拥有自己的具有合成属性的init方法时:
@property (copy, nonatomic) NSString *bookName;
@property (strong, nonatomic) NSMutableArray *book;
当我想用我自己的自定义初始化程序进行初始化时,我会看到这样写:
-(id) initWithName: (NSString *)name
{
self = [super init]
if (self) {
bookName = [NSString stringWithString: name];
book = [NSMutableArray array];
}
return self;
}
现在我想澄清一些事情。我知道为什么它使用stringWithString方法,因为它不是仅仅将地址传递给传入的字符串,而是创建一个新对象,以便它拥有字符串本身。难道我也不能这样写:
self.bookName = name;
这样做应该使用合成方法并实际创建一个新对象吗?基本上两者都完成了同样的事情。我问,因为有其他方法显示两种方式,所以我只是想确保没有其他问题可以使用这种或那种方式突然出现。它们似乎都以不同的方式做同样的事情(使用合成方法与直接修改类变量但在内存中为它创建一个新对象)。
我还要指出这是在ARC环境中。
答案 0 :(得分:4)
(请注意,我假设上面是ARC代码;否则它是不正确的。)
您几乎应该始终使用访问者来访问您的ivars(即使在ARC中)。但是,关于init
是否应该使用访问者或直接访问其ivars存在一些争议。我在这场争论中已经改变了立场,但IMO并不是一个明显的决定。
不允许init
使用访问器的主要参数是未来(未知)子类可能会在访问器中创建副作用。您通常不希望在init
期间发生副作用。例如,当您将某些内容设置为其初始值时,您可能不希望发布更改通知,并且您的对象可能处于“未定义状态”,此时此类读取将很危险。
尽管如此,虽然这个论点最终影响了我,但我从未在多个团队的各种规模的项目中遇到过这种情况。我曾经多次遇到开发人员在retain
中设置他们的ivars时失败init
(如上所述,如果不是ARC则会崩溃)。这就是为什么很长一段时间我甚至在init
中建议使用访问器。但理论上它确实会带来危险,特别是如果你是一个闭源框架作家(即Apple)。因此,对于我自己的代码,我现在避免init
中的访问者。如果我在较早的保留/释放代码上与更年轻的团队合作,我可能仍会让他们在init
中使用访问者。根据我的经验,它只是避免了这么多崩溃。
但是,您应该避免在dealloc
中调用访问者,这一点没有争议。这肯定会在摧毁你的物体的过程中导致奇怪的副作用。
答案 1 :(得分:1)
你是对的,因为bookName
被声明为copy
,分配self.bookName
会传入传入的字符串的副本。我不确定复制将通过与[NSString stringWithString: name]
完全相同的代码路径,但它将实现创建原始字符串副本的相同目的,使您免受用户传入可变对象的意外后果并改变其后面的值你的背。
答案 2 :(得分:1)
因为声明的属性是copy
然后是,所以他们正在做同样的事情。
然而,很多时候它是strong
,然后两种方法之间会有区别,所以第一种方法就是“正确”的方法。