iOS--@property关键字

iOS中主要的属性修饰符有下面几种:

读写权限:readonly, readwrite

安全策略:nonatomic,atomic (决定编译器生成的getter和setter是否为原子操作)

内存管理:copy / assign / retain,strong / weak /  unsafe_unretained

方法名 :getter,setter

不常用:nonnull, null_resettable,nullable

按照MRC和ARC区分

MRC:copy / assign / retain / readwrite / readonly /nonatomic / atomic 等

ARC:copy / assign / strong / weak / readwrite / readonly /nonatomic / atomic 等

在声明 property 时,如果不指定关键字,编译器会为 property 生成默认的关键字

基本数据类型,默认关键字为:atomic,assign,readwrite

对象类型,默认关键字为       :atomic,strong,readwrite

下面介绍一下这些关键字

1、strong   (默认)

强引用。用于OC对象,为这种属性设置新值时,设置方法会先保留新值,并释放旧值,然后再把新值设置过去,属性引用对象的引用计数 +1。

2、weak

对对象的弱引用,不增加对象的引用计数,也不持有对象,当对象消失后指针自动指向nil,所以这里也就防止了野指针的存在。

1>delegate使用weak修饰:因为代理一般都是指向控制器,会造成循环引用,无法释放,造成内存泄露。比如tableview,代码中经常会有:

//控制器强引用self.view,self.view强引用tableView

[self.view addSubview:self.tableView];

//delegate 引用控制器,如果delegate用strong修饰会导致循环引用,无法释放,造成内存泄漏

self.tableView.delegate = self;

self.tableView.dataSource = self;

2>UI中控件经常使用weak的原因:

UI控件之所以可以使用弱指针,是因为控制器有强指针指向UIView

UIView 有强指针指向Subviews数组,数组中由强指针指向控件

一般来说,类 “内部”的属性设置为strong,类“外部”的属性设置为weak。说到底就是一个归属权的问题。使用weak通常为了解决循环引用的问题

3、assign

默认属性关键字。 assign用于非指针变量,一般用于基础类型和C数据类型,这些类型不是对象,统一由系统栈进行内存管理。

assign也能修饰OC对象,但是assign修饰的对象在被释放后,其指针依然存在,不会被置为nil——出现了野指针。当访问这个野指针时,指向了原地址,而原地址有两种情况:

第一种情况:原地址没有改变,代码运行通过,但很有可能有逻辑bug。

第二种情况:原地址已经改变,结果不可预测,多数crash,也有可能出现其他莫名错误。

但是用weak来修饰的话,对象释放的时候会把指针置为nil,从而避免了野指针的出现。

为什么基本数据类型就可以使用assign,这涉及到堆和栈的问题,基本数据类型会被分配到栈空间,而栈空间是由系统自动管理分配和释放的,就不会造成野指针的问题。

4、copy 拷贝  

拷贝。返回一个不可变对象。源对象是不可变对象是浅拷贝,类似 strong;当源对象是可变对象时执行的是单层深拷贝。对自定义对象使用copy时,自定义对象需要遵守NSCopying协议并实现copyWithZone方法。。详细见前面文章iOS--拷贝相关题 - 简书

使用copy的目的是,防止把可变类型的对象赋值给不可变类型的对象时,可变类型对象的值变化会无意间篡改不可变类型对象原来的值。

5、retain

适用于NSObject及其子类。release旧值,retain新值。

retain是指针复制(浅复制),引用计数加1,而不会导致内容被复制。

retain是MRC下的关键字,ARC下使用strong代替。

6、readwrite(默认)

读写属性。@synthesize自动生成setter和getter方法,可以通过点语法读取和设置属性的值。

7、readonly

只读属性。@synthesize只会自动合成getter方法。如果使用点语法为属性赋值,会编译错误:Assignment to readonly property。

8、getter=

指定获取属性的方法名

@property(nonatomic, getter=getName, copy)NSString *str;

self.str = @"getter=getName";

NSLog(@"%@",self.getName);

2020-07-10 14:39:30.160040+0800 iOS_property[91440:5164076] getter=getName


9、setter=

指定设置方法的方法名。

@property(nonatomic, setter=setName:, copy)NSString *str;

    [self setName:@"setter=setName:"];

    NSLog(@"%@",self.str);

2020-07-10 14:42:28.162017+0800 iOS_property[91536:5166626] setter=setName:

10、unsafe_unretained

用于修饰对象类型,声明一个弱引用,和用assign修饰对象类型一样,当所修饰的对象销毁时,该属性不会被置为nil。

11、atomic(默认)

原子的。提供多线程安全,在多线程环境下,原子操作是必要的,atomic会给对象加锁(对象的setter和getter函数里)假设多个线程访问同一属性,所有不同线程上的操作都将依次顺序执行。atomic读写线程安全,但不是绝对安全,atomic只是给getter和setter加了个锁,只能保证代码进入getter或者setter函数内部时是安全的,一旦出了getter和setter,atomic无法保障多线程安全了。还有如果修饰的是集合类型属性,对集合属性的读写是安全的,但集合内添加移除元素就不保证安全了。

因为iOS中使用同步锁的开销比较大,会影响性能,所以有特殊要求安全性高的才使用atomic,一般属性声明都是nonatomic。

12、nonatomic

非原子性,指出访问器不是原子操作。在多线程环境下,解析的访问器提供一个对属性的安全访问,从获取器得到的返回值或者通过设置器设置的值可以一次完成,即便是别的线程也正在对其进行访问。如果你不指定 nonatomic ,在自己管理内存的环境中,解析的访问器保留并自动释放返回的值,如果指定了 nonatomic ,那么访问器只是简单地返回这个值,对属性赋值的时候不加锁,多线程并发访问会提高性能。但是如有多线程同时访问同一个非原子的属性,可能会出现无法预料的结果,如果没有使用多线程间的通讯编程,nonatomic是一个非常好的选择。

13、nonnull

对象不能为nil;当赋值为nil时编译器会给出警告。

NS_ASSUME_NONNULL_BEGIN   //之间的属性都被认为是nonnull的NS_ASSUME_NONNULL_END

14、nullable

对象可以为nil;属性默认是nullable的。


————————————————————————————————————————

部分面试题

1、关于weak 与assign

weak:弱引用, ARC后出现,只可以修饰对象(delegate和block等引用类型),就是指针类型,不会改变引用对象的计数;不能修饰基本数据类型,否则会报错:Property with 'weak' attribute must be of object type。weak引用的对象释放后,指针会被自动置为 nil,不会出现野指针,也避免循环引用。

assign:通常用于修饰基本数据类型。如果修饰对象,不会改变引用对象的计数,引用的对象释放后指针不会自动被置空而产生野指针问题,此时向对象发消息会崩溃。

2、关于copy与strong

NSString、NSArray、NSDictionary常用copy,为什么不用strong?

见文章iOS--拷贝相关题 - 简书


3、weak如何实现自动赋nil

Runtime维护了一个weak表,用于存储指向某个对象的所有weak指针。weak表其实是一个哈希表,Key是所指对象的地址,Value是weak指针的地址(这个地址的值是所指对象的地址)的数组因为一个对象可能被多个弱引用指针指向,所以这里Value是一个数组。

当这个对象引用计数为 0 时就会dealloc。假如 weak 指向的对象内存地址是address,那么就会以address为Key, 在这个 weak 表中搜索,找到以address为Key的指向这个对象的weak 指针的数组,遍历数组将weak指针设置为 nil。

weak实现原理可概括四步:

一、初始化时:runtime会调用objc_initWeak函数,初始化一个新的weak指针指向对象的地址。

二、添加引用时:objc_initWeak函数会调用 objc_storeWeak() 函数, objc_storeWeak() 的作用是更新指针指向,创建对应的弱引用表。

三、对象释放。

1. objc_release

2. 因为引用计数为0所以执行dealloc

3. _objc_rootDealloc

4. object_dispose

5. objc_destructInstance

6. objc_clear_deallocating

四、对象释放时,调用objc_clear_deallocating函数。

1、objc_clear_deallocating函数首先根据对象地址获取所有weak指针的数组;

2、然后遍历这个数组把其中的weak指针设为nil;

3、把这个记录从weak表中删除;

4、从引用计数表中清理废弃对象的地址作为键值的记录

https://opensource.apple.com/source/objc4/objc4-646/runtime/objc-weak.h

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