Objective c 关于目标c对象的自定义init方法/指针的一般说明

Objective c 关于目标c对象的自定义init方法/指针的一般说明,objective-c,pointers,initialization,Objective C,Pointers,Initialization,当我有自己的init方法时,其合成属性如下: @property (copy, nonatomic) NSString *bookName; @property (strong, nonatomic) NSMutableArray *book; 当我想用自己的自定义初始值设定项初始化时,我会这样写: -(id) initWithName: (NSString *)name { self = [super init] if (self) { boo

当我有自己的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环境中进行的

您是正确的,因为
bookName
声明为
copy
,分配
self.bookName
将生成传入字符串的副本。我不确定复制是否会经过与
[NSString stringWithString:name]
完全相同的代码路径,但它会达到创建原始字符串副本的相同目的,保护您免受用户传入可变对象并在背后更改其值的意外后果。

因为声明的属性是
copy
然后是,他们正在做同样的事情

但是,很多时候,这是一个
strong
,然后这两种方法之间会有差异,因此第一种方法是“正确”的方法。

(请注意,我假设上面的是ARC代码;否则它是不正确的。)

您几乎应该始终使用访问器访问IVAR(即使在ARC中)。然而,
init
应该使用访问器还是直接访问它的IVAR存在一些争议。在这场争论中,我已经改变了立场,但在我看来,这不是一个明显的决定

不允许
init
使用访问器的主要理由是未来(未知)子类可能会在访问器中产生副作用。您通常不希望在
init期间发生副作用。例如,当您将某个对象设置为其初始值时,您可能不想发布更改通知,并且您的对象可能处于“未定义状态”,此时读取可能会有危险

也就是说,虽然这一争论最终影响了我,但我从未在多个团队的众多不同规模的项目中遇到过这种情况。我曾多次遇到开发人员在
init
中设置IVAR时未能
保留
(如上所述,如果不是ARC,则会崩溃)。这就是为什么在很长一段时间里,我甚至建议在
init
中使用访问器。但从理论上讲,这确实会造成危险,特别是如果你是一个封闭源代码的框架编写者(即苹果公司)。因此,对于我自己的代码,我现在在
init
中避免了访问器。如果我与一个更初级的团队一起处理旧的保留/发布代码,我可能仍然会让他们在
init
中使用访问器。在我的经历中,它避免了这么多的碰撞

但是,您应该避免在
dealloc
中调用访问器,这一点没有争议。这肯定会在破坏你的目标的过程中产生怪诞的副作用。