@property属性关键字

@property 的属性关键字有 nonatomicatomicreadonlywriteonlyreadwriteassignretaincopystrongweakunsafe_unretainednonnullnullablenull_resettable

下面介绍一些常用的关键字:
1.) nonatomicatomic
不写的话默认就是 atomic ,默认关键字。atomicnonatomic 的区别在于,系统自动生成的 getter/setter 方法不一样。如果你自己写 getter/setter,那 atomic/nonatomic/retain/assign/copy 这些关键字只起提示作用,写不写都一样。

对于atomic的属性,系统生成的 getter/setter 会保证 get、set 操作的完整性,不受其他线程影响。假设有一个atomic 的属性"name",如果线程 A 调[self setName:@"A"],线程 B 调[self setName:@"B"],线程 C 调[self name],那么所有这些不同线程上的操作都将依次顺序执行——也就是说,如果一个线程正在执行 getter/setter,其他线程就得等待。因此,属性 name 是读/写安全的。

但是,如果有另一个线程 D 同时在调[name release],那可能就会crash,因为 release 不受 getter/setter 操作的限制。也就是说,这个属性只能说是读/写安全的,但并不是线程安全的,因为别的线程还能进行读写之外的其他操作。线程安全需要开发者自己来保证。

如果 name 属性是 nonatomic 的,那么上面例子里的所有线程 A、B、C、D 都可以同时执行,可能导致无法预料的结果。如果是 atomic 的,那么 A、B、C 会串行,而 D 还是并行的。

2.)readonly
只读属性,有getter方法,但是直接调用setter方法会报错。
但是我们还是可以利用KVCreadonly属性赋值。

例如:定义一个ACLStudent的类,该类里面有一个firstName属性。

屏幕快照 2018-05-05 下午12.14.23.png

如果直接调用setter方法,会报错
3D8A9C23-8DE2-4AC7-AD09-AFCB33EB66A3.png

改用KVC来赋值,就可以修改成功


FF4A8CEC-7A33-4294-A544-7BFED67945E0.png

或者
3A335D7F-2B13-4119-8E7E-C113E6E9B4F6.png

当使用 setValue:forKey: 来设置对象的属性时,会以下面的优先顺序来寻找对应的 key

  1. 消息接收对象会查找是否存在满足 set<Key>: 格式的存取方法。
  2. 如果不存在满足条件的存取方法,且消息接收对象的类方法 + (BOOL)accessInstanceVariablesDirectly返回 YES,那么该对象会以 _<key>, _is<Key>, <key>, is<Key> 的顺序查找是否存在对应的key。
  3. 如果存在对应的存取方法或者找到对应的实例变量,那么就会改变该 key 所对应的值 value。必要的话,value 所对应的值会从对象中解析出来,如 Representing Non-Object Values 所描述的那样。
  4. 如果没有找到对应的存取方法或者实例变量,那么该消息对象的 setValue:forUndefinedKey: 将会调用。

对于上述第2点说明一下,如果我们不想让 setValue:forKey: 方法改变对象的属性值,那么重写其类方法 + (BOOL)accessInstanceVariablesDirectly返回 NO (该方法默认返回 YES,即在不存在满足条件的存取方法时,允许直接访问属性对应的实例变量);在搜索实例变量时,会首先检查带下划线的实例变量,然后检查不带下划线的实例变量。

对于上述第3点举例说明,如果要修改对象的属性 NSInteger studentId, 注意其是 NSInteger 类型,我们在调用 setValue:forKey: 方法时可以像这样

[self setValue:@(20) forKey:NSStringFromSelector(@selector(studentId))];

传入一个 NSNumber 对象也可以,Objective-C 会处理好一切。

对于上面的示例,使用 setValue:forKey: 实际修改的是 _firstName 实例变量的值。不要忘记,我们在声明一个 firstName 的属性时,编译器会为我们自动合成一个_firstName 的实例变量。

总结:

当我们声明一个 readonly 的属性,外部可能会通过 KVC 修改该属性值。
为了避免 KVC 修改属性值,须将定义属性所在类的类方法 + (BOOL)accessInstanceVariablesDirectly重写,使其返回 NO.

3.)strongweak
strong : 持有对象,引用计数+1;
weak : 不持有对象,引用计数不变,只适用于对象。比如代理(为了防止循环引用),UI控件(add到父视图上时,被父视图持有。对UI控件的引用,iOS会自动将其设置为弱变量(weak))

不同的是, 当一个对象不再有strong类型的指针指向它的时候 它会被释放 ,即使还有weak型指针指向它。

一旦最后一个strong型指针离去 ,这个对象将被释放,所有剩余的weak型指针都将被清除。

weak修饰的对象被别的变量释放,那么弱变量会被自动设置为nil,这样可以有效地防止崩溃

4.) retainassignunsafe_unretained
assign : 修饰基础数据类型和C数据类型,当被释放后,变量不会被自动置为nil,会变成野指针。
unsafe_unretained :unsafe_unretained从命名就可以看出意义所在,unsafe即是不会自动设置为nil,如果对象被释放了,再进行访问,程序会crash;unretainedweak类似,不会影响对象的引用计数
retain :释放旧对象,创建新对象。 引用计数会+1,强引用。
copy : 拷贝一个新的对象,新对象的引用计数+1,释放旧对象。

5.) copy
首先我们看一下对象和指针,看图

指针和对象

中间这个 “=” 符号 将2段代码连在一起, 充当一个桥梁作用:

第一: 允许 p 指针 指向这个对象占用的内存区域的首地址(可以简洁的理解为 允许p指针指向对象)

第二: 将这个对象地址赋值给p指针

第三:后续所有对 “对象“的操作,都可以通过对p指针进行间接操作来完成。

copymutableCopy
copy 就是浅拷贝,mutableCopy就是深拷贝吗?
任何对象都可以执行 copymutableCopy

看一下官方关于深拷贝和浅拷贝的解释图:


浅拷贝和深拷贝

结论:
1.浅复制,复制的是指向对象的指针,并不会复制对象本身,不会创建一个新的对象;
2.,深复制,复制的是对象本身,会创建一个新的对象。

对引用计数的影响:
浅copy,类似strong,持有原始对象的指针,会使retainCount加一。浅copy和strong引用的区别仅仅是浅copy多执行一步copyWithZone:方法。

深copy,会创建一个新的对象,不会对原始对象的retainCount变化。

使用原则:

\ copy mutableCopy
不可变对象 原来的对象,不可变 新对象 ,可变
可变对象 新对象,不可变 新对象,可变

1.针对不可变对象调用copy返回该对象本身,调用mutableCopy返回一个可变对象(新的);

2.针对可变对象调用copy返回一个不可变对象(新的),调用mutableCopy返回另外一个可变对象(新的)。

3.针对集合类对象(NSArray,NSMutableArray,NSDictionary,NSMutableDictionary,NSSet等)进行深拷贝,拷贝的是对象本身,变成一个新的对象,但是集合里面的元素,进行的是浅拷贝,拷贝的是地址。

注意:
使用copy,需要该对象遵循NSCopying协议;
使用mutableCopy,需要该对象遵循NSMutableCopying协议,否则会crash在copyWithZonemutableCopyWithZone 方法上。

例:
UIView及其父类 并没有像 数组 字典 字符串这些类一样 遵守 NSCopying, NSMutableCopying 协议,下面代码程序会crash。


.h里面
.m里面
崩溃日志
@property(nonatomic, copy)NSMutableArray *myCopyArray;

 self.myCopyArray = [NSMutableArray arrayWithObjects:@"1",@"2",@"3", nil];
 [self.myCopyArray removeObjectAtIndex:0];

运行后crash:
 -[__NSArrayI removeObjectAtIndex:]: unrecognized selector sent to instance 0x14fc18f20

所以使用的时候,要注意对象是可变的还是不可变的。

关于 copy 和 block

Block为什么使用copy修饰

参考:
链接:https://www.jianshu.com/p/b90a7c57c34e

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

推荐阅读更多精彩内容

  • 1.ios高性能编程 (1).内层 最小的内层平均值和峰值(2).耗电量 高效的算法和数据结构(3).初始化时...
    欧辰_OSR阅读 29,293评论 8 265
  • 江湖风云卷,各路侠客行。 轻推风生掌,横扫人马惊。 笑映刀剑影,拈花飞流星。 声如环佩鸣,步似点水蜓。 盈盈舞妙姿...
    春来木棉开阅读 262评论 1 0
  • 今日大事记 一、看病去。丈母娘头疼,担心脑梗复发了,所以我和爱人带她到医院看病。上午8点多我们就到了中心医院,不好...
    甲午之印阅读 131评论 0 0