Skip to content

Commit 4127d6b

Browse files
committed
更新 *重写带 copy 关键字的 setter* 的答案
首先,if 的确比对象 copy 要快。 另外,判断对象是否相同是为了保证代码执行的正确性。在非 ARC 环境下,如果穿入对象 retain count 为 1,不做判断的话,release 之后对象内存释放,下一步 copy 也会出错。
1 parent e71a4b1 commit 4127d6b

File tree

1 file changed

+4
-99
lines changed

1 file changed

+4
-99
lines changed

01《招聘一个靠谱的iOS》面试题参考答案/《招聘一个靠谱的iOS》面试题参考答案(上).md

Lines changed: 4 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -411,114 +411,19 @@ self.mutableArray = array;
411411
```
412412

413413

414-
至于***如何重写带 copy 关键字的 setter***这个问题,
415-
416-
417-
如果抛开本例来回答的话,如下:
418-
419-
420-
421-
```Objective-C
422-
- (void)setName:(NSString *)name {
423-
//[_name release];
424-
_name = [name copy];
425-
}
426-
```
427-
428-
不过也有争议,有人说“苹果如果像下面这样干,是不是效率会高一些?”
429-
414+
***重写带 copy 关键字的 setter***:
430415

431416
```Objective-C
432417
- (void)setName:(NSString *)name {
433418
if (_name != name) {
434-
//[_name release];//MRC
419+
#if __has_feature(objc_arc)
420+
[_name release];
421+
#endif
435422
_name = [name copy];
436423
}
437424
}
438425
```
439426

440-
441-
442-
这样真得高效吗?不见得!这种写法“看上去很美、很合理”,但在实际开发中,它更像下图里的做法:
443-
444-
![enter image description here](http://i.imgur.com/UwV9oSn.jpeg)
445-
446-
克强总理这样评价你的代码风格:
447-
448-
![enter image description here](http://i.imgur.com/N77Lkic.png)
449-
450-
我和总理的意见基本一致:
451-
452-
453-
> 老百姓 copy 一下,咋就这么难?
454-
455-
456-
457-
458-
你可能会说:
459-
460-
461-
之所以在这里做`if判断` 这个操作:是因为一个 if 可能避免一个耗时的copy,还是很划算的。
462-
(在刚刚讲的:《如何让自己的类用 copy 修饰符?》里的那种复杂的copy,我们可以称之为 “耗时的copy”,但是对 NSString 的 copy 还称不上。)
463-
464-
465-
但是你有没有考虑过代价:
466-
467-
468-
> 你每次调用 `setX:` 都会做 if 判断,这会让 `setX:` 变慢,如果你在 `setX:`写了一串复杂的 `if+elseif+elseif+...` 判断,将会更慢。
469-
470-
要回答“哪个效率会高一些?”这个问题,不能脱离实际开发,就算 copy 操作十分耗时,if 判断也不见得一定会更快,除非你把一个“ @property他当前的值 ”赋给了他自己,代码看起来就像:
471-
472-
```Objective-C
473-
[a setX:x1];
474-
[a setX:x1]; //你确定你要这么干?与其在setter中判断,为什么不把代码写好?
475-
```
476-
477-
或者
478-
479-
480-
```Objective-C
481-
[a setX:[a x]]; //队友咆哮道:你在干嘛?!!
482-
```
483-
484-
> 不要在 setter 里进行像 `if(_obj != newObj)` 这样的判断。(该观点参考链接:[ ***How To Write Cocoa Object Setters: Principle 3: Only Optimize After You Measure*** ](http://vgable.com/blog/tag/autorelease/)
485-
486-
487-
488-
什么情况会在 copy setter 里做 if 判断?
489-
例如,车速可能就有最高速的限制,车速也不可能出现负值,如果车子的最高速为300,则 setter 的方法就要改写成这样:
490-
491-
492-
```Objective-C
493-
-(void)setSpeed:(int)_speed{
494-
if(_speed < 0) speed = 0;
495-
if(_speed > 300) speed = 300;
496-
_speed = speed;
497-
}
498-
```
499-
500-
501-
502-
回到这个题目,如果单单就上文的代码而言,我们不需要也不能重写 name 的 setter :由于是 name 是只读属性,所以编译器不会为其创建对应的“设置方法”,用初始化方法设置好属性值之后,就不能再改变了。( 在本例中,之所以还要声明属性的“内存管理语义”--copy,是因为:如果不写 copy,该类的调用者就不知道初始化方法里会拷贝这些属性,他们有可能会在调用初始化方法之前自行拷贝属性值。这种操作多余而低效)。
503-
504-
那如何确保 name 被 copy?在初始化方法(initializer)中做:
505-
506-
```Objective-C
507-
- (instancetype)initWithName:(NSString *)name
508-
age:(NSUInteger)age
509-
sex:(CYLSex)sex {
510-
if(self = [super init]) {
511-
_name = [name copy];
512-
_age = age;
513-
_sex = sex;
514-
_friends = [[NSMutableSet alloc] init];
515-
}
516-
return self;
517-
}
518-
519-
```
520-
521-
522427

523428
###6. @property 的本质是什么?ivar、getter、setter 是如何生成并添加到这个类中的
524429

0 commit comments

Comments
 (0)