iOS : 一个区分很大的面试题

这是 sunny博客的一道面试题,还挺值得一说的,主要考基础扎实不扎实。

考察一个面试者基础咋样,基本上问一个 @property 就够了:

@property 后面可以有哪些修饰符?
什么情况使用 weak 关键字,相比 assign 有什么不同?
怎么用 copy 关键字?
这个写法会出什么问题: @property (copy) NSMutableArray *array;
如何让自己的类用 copy 修饰符?如何重写带 copy 关键字的 setter?
这一套问题区分度比较大,如果上面的问题都能回答正确,可以延伸问更深入点的:

@property 的本质是什么?ivar、getter、setter 是如何生成并添加到这个类中的
@protocol 和 category 中如何使用 @property
runtime 如何实现 weak 属性
每个人擅长的领域不一样,我们一般会从简历上找自己写擅长的技术聊,假如自己并不是很熟,最好别写出来或扯出来,万一面试官刚好非常精通这里就露馅了。

1.@property 后面可以有哪些修饰符?
  • atomic, nonatomic
    原子,非原子,用来保障属性的线程安全的,一般用nonatomic
    因为 atomic 一方面也不能保证一定是线程安全的,另一方面消耗性能太大。
    如果不修饰,则默认是atomic
  • readonly, readwrite
    只读,或者可读可写,顾明思意,readonly 的话不允许外部进行值的修改
  • strongweak, assign, copyunsafe_unretained
    这里只大概说下 weak, 和 assign, 因为有的人会问这两个有什么区别
    一般情况下 weak 用来修饰对象类型,而 assign 来修饰一般数据类型, id 类型看情况用,是因为 weak 修饰的对象在释放后被自动置为 nil,而 assign 不会有这部操作,所以语法上 assign 也是可以修饰对象类型,但这样很容易野指针,所以一般用 weak 修饰,但是 weak 从语法上就不能修饰一般数据类型
  • setter, getter
    用来指定特定的 set 方法 和 get 方法
  • nonnull, null_resettable, nullable
    nonnullweak 不可以同时存在
    就算有 nonnull 修饰,属性依然可以设置为 nil, 只不过有个警告而已....

2.什么情况使用 weak 关键字,相比 assign 有什么不同?

一般weak使用的地方有:

  • 防止循环引用
    最典型的就是 delegate 一般要设置为 assign/weak ,和 block 内引用的的变量要在 block 之前 weak 申明一下
  • 被 xib 引用的
    xib 连线的的就是强引用,所以用 weak 就可以了

weak 和 assign 的小区别:
哎呀上面刚说了...复制一下吧....

一般情况下 weak 用来修饰对象类型,而 assign 来修饰一般数据类型, id 类型看情况用。是因为 weak 修饰的对象在释放后被自动置为 nil,而 assign 不会有这部操作,所以语法上 assign 也是可以修饰对象类型,但这样很容易野指针,所以一般用 weak 修饰,但是 weak 从语法上就不能修饰一般数据类型


3.怎么用 copy 关键字?

要知道怎么要用copy关键字我们首先得知道深浅拷贝的概念:

  • 浅拷贝:不产生新的内存空间,只是多一个指针,指向拷贝内容地址
  • 深拷贝:产生新的内存空间,并把拷贝内容复制到新的内存空间中

然后我们在看下 copy 关键字使用场景:

  • 一般最多的是我们给属性类型是 NSStringNSArrayNSDictionary, 这些用 copy 修饰 。
    因为这几个类型有分别对应的 mutable 属性,而在我们写代码的时候经常会有要把 mutable 属性的值赋给 不可变属性,譬如:

    self.str1 = @"";
    NSMutableString *mutStr1 = [NSMutableString stringWithString:@"str1"];
    _str1 = mutStr1;
    
    [mutStr1 appendString:@" - mutStr1"];
    

我们的初衷是给 _str1 赋值为 @"str1" , 这种场景下,
如果 str1strong 关键字修饰的,那么打印会发现 _str1 的 值为 @"str1 - mutStr1" , 并且 _str1 的地址就是 mutStr1 的地址,
如果 str1copy 关键字修饰的,那么打印会发现 _str1 的 值为 @"str1" , 并且 _str1 的地址是一个新的地址,
显然第二种结果才是我们想要的, 所以NSStringNSArrayNSDictionary这些属性用copy来修饰。

扩展一下:
反过来NSMutableStringNSMutableArrayNSMutableDictionary 却不能用 copy 修饰,因为 copy 深拷贝后的值是一个 非mutable 的,这样你再增删改就会直接崩溃。

image.png
image2.png
  • 自定义类的对象用 copy 修饰
    这就需要我们给自定义类实现 NSCopying 协议

4.这个写法会出什么问题: @property (copy) NSMutableArray *array;

哎呀上面也刚说了...再复制一下吧....

反过来NSMutableString,NSMutableArray,NSMutableDictionary 却不能用 copy 修饰,因为 copy 深拷贝后的值是一个 非mutable 的,这样你再增删改就会直接崩溃。

其实只要理解了深浅拷贝,这些很容易理解,就不详细举例子了


5.如何让自己的类用 copy 修饰符?如何重写带 copy 关键字的 setter?

要想自己的类能用 copy 修饰符,就要给实现 NSCopying 协议, 要是有 mutable 需求的就实现 NSMutableCopying

如何重写带copy关键字的setter :

假如我们有一个类实现了 NSCopying 协议:

@interface CopyClass : NSObject <NSCopying>
@property (nonatomic, strong) NSString *str1;
@property (nonatomic, strong) NSString *str2;
@end

@implementation CopyClass 
- (id)copyWithZone:(nullable NSZone *)zone
{
    CopyClass *copyObject = [[CopyClass alloc] init];
    copyObject.str1 = copyObject.str1;
    copyObject.str2 = copyObject.str2;
    return copyObject;
}
@end

那么我们在外部调用假如是这样的:

@property (nonatomic, copy) CopyClass *myCopyB;

调用的地方:

CopyClass *copyA = [[CopyClass alloc] init];
copyA.str1 = @"str1";
copyA.str2 = @"str2";

self.myCopyB = copyA;

一般如果属性带 copy 关键字 ,那么 setter 的默认实现就是类似这样:

-(void)setMyCopyB:(CopyClass *)myCopyB
{
    _myCopyB = [myCopyB copy];
}

那这道题说如何重写带 copy 关键字的 setter,该咋写咋写呗,这还能玩出花来?不太懂这第二问的意思.....


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

__@property 的本质就是 ivar + getter + setter __
我们往一个类里添加一个属性,然后用runtime方法去观察,就可以知道,这个类的
objc_ivar_list 里添加了对应的变量,methodLists 添加了对应的 sette 和 getter

那么ivar、getter、setter 是如何生成并添加到这个类中的
编译期,编译器会自动生成这个属性的 setter 和 getter 代码,并且向类中添加对应的实例变量,生成的结果和属性的声明是否有setter、getter关键字,还有@synthesize指定的变量名有关系。

也就是说我们每次在增加一个属性,系统都会在 ivar_list中添加一个成员变量的描述,在 method_list中增加 setter 与 getter 方法的描述,在属性列表中增加一个属性的描述,然后计算该属性在对象中的偏移量,然后给出 setter 与 getter 方法对应的实现,在 setter 方法中从偏移量的位置开始赋值,在 getter 方法中从偏移量开始取值,为了能够读取正确字节数,系统对象偏移量的指针类型进行了类型强转.


7.@protocol 和 category 中如何使用 @property

我们知道在类里定义一个属性时,会在该类的ivar_list添加ivar描述,会在method_list添加该属性的seter和geter方法描述,在property_list中添加一个属性描述。

但在@protocol 和 category 中如果定义一个 @property 时,只会在property_list中添加一个属性描述,method_list 和 ivar_list中都不会有相关的描述添加。

所以要想@protocol 和 category 中的 @property 有意义,就必须在类中或category中,实现这个@property的setter和getter。

但是 ivar_list 是没有该属性对应的 ivar, 所以 setter 中你是没法赋值的, 这时候就要用到 objc_setAssociatedObject 了,在 setter 中用 objc_setAssociatedObject 赋值,并在 getter 中用 objc_getAssociatedObject 取值,这样就变相完成了@protocol 和 category 中属性的设置


8.runtime 如何实现 weak 属性

首先我们要知道 weak 关键字的一些点:

  • 不添加引用计数,既不持有,只是单纯的指向
  • 释放的时候会置为nil

存放weak对象映射的表是由一个自旋锁管理的哈希表,当有 weak 引用时,会把 weak 对象指向的对象那个内存地址作为 weak 表的 key, 然后 value 就是 weak 对象的地址,当指向的那个对象被释放的时候, 会拿着被释放对象的地址来在 weak 里查,查到的对应的 weak 对象就会被置为nil, 然后从 weak 表中删除。


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,335评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,895评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,766评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,918评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,042评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,169评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,219评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,976评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,393评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,711评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,876评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,562评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,193评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,903评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,699评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,764评论 2 351

推荐阅读更多精彩内容