iOSInterviewQuestions icon indicating copy to clipboard operation
iOSInterviewQuestions copied to clipboard

21题“不推荐在 init 方法中使用点语法”

Open SandyluCH opened this issue 7 years ago • 6 comments

在提到“不推荐在 init 方法中使用点语法”之后,说了原因之后举了个例子:

在基类 Person 的默认初始化方法中,可能会将姓氏设为空字符串。此时若使用点语法( self.lastName )也即 setter 设置方法,那么调用将会是子类的设置方法

经过测试,运行代码[[Person alloc] init]并不会调用子类的setter方法,而是会输出🔴类名与方法名:-[Person setLastName:](在第25行),描述:根本不会调用这个方法,请查证。

SandyluCH avatar Mar 22 '17 09:03 SandyluCH

那你在父类的init方法里面有木有调用点语法(self.lastName = xxx)额...

983563622 avatar Mar 23 '17 01:03 983563622

我也试过了. 和他是一样的结果. 在Person类init里调用setter, 应该不会到子类里找实现, 只会向上找吧? 你是不是说运行代码[[ChenPerson alloc] init], 在Person的init里的self.lastName = @"XXX";不会走Person中的setter, 而是调用子类ChenPerson中的setter? 这样的话就和这个例子上面的题目联系起来了...说明super最后调用的是self

JpacheGitHub avatar Apr 06 '17 11:04 JpacheGitHub

这句话,出自《Effective Objective-C 2.0》的第7条“Access Instance Variables Primarily Directly When Accessing Them Internally”章节结尾处的第二条规律总结:

Within initializers and dealloc, always read and write data directly through instance variables.

在初始化方法和dealloc内部,总是直接读写实例变量。

原书引出这条规律,是因为章节前面内容说到:“写操作用setter,读操作用实例变量。但是有一个例外情况”,也就是说,写操作不用setter,而要用实例变量的情况。于是,才举了子类覆写父类setter方法的例子,来说明原因。

至于这个题目的解答中,出现的这句话:

这也就是为什么说“不推荐在 init 方法中使用点语法”,如果想访问实例变量 iVar 应该使用下划线( _iVar ),而非点语法( self.iVar )。

这跟[self class],[super class],没有直接因果关系。纯属神来一笔。这里的class,既不是属性,也不是实例变量,而是一个方法。

另外,原书的例子跟@ChenYilong的例子一样,但代码有一处问题。

-  (void)setLastName:(NSString*)lastName {
if (![lastName isEqualToString:@"Smith"]) { 
[NSException raise:NSInvalidArgumentException format:@"Last name must be Smith"]; } self.lastName = lastName;
}

setter里面,用到self.xxx,会导致死循环。

cool8jay avatar Apr 10 '17 08:04 cool8jay

所以 在Person父类初始化时调用self.语法对name进行set时会调用子类的setter方法么

lt541013990 avatar Jul 07 '17 07:07 lt541013990

唐巧的《不要在init和dealloc函数中使用accessor》http://blog.devtang.com/2011/08/10/do-not-use-accessor-in-init-and-dealloc-method/

ahahe avatar Sep 24 '17 13:09 ahahe