iOS 属性关键字(二)

原子性

  • 原子性就nonatomic和atomic两个关键字

atomic与nonatomic

  • atomic是默认的原子操作关键字,atomic也就代表其具有原子性

  • atomic 属性关键字会给该 property 的 getter和setter方法加锁,但不能保证线程一定安全并且会带来更多损耗。

  • 而nonatomic就是非原子性的,不会给setter,getter方法加锁,这也是我们默认的方法

  • 原因:

    1. 使用atomic也无法保证线程一定能安全了
    2. 对于涉及到多线程安全的场景,我们常常是自己去额外加同步
    3. 这样也可以加快运行速度

为什么会出现线程不安全

  • 这部分主要要看哲神的博客:从atomic关键字说到多线程安全(内含iOS给代码加锁方法总结)
  • 补充下地址总线的知识:地址总线 (Address Bus;又称:位址总线) 属于一种电脑总线 (一部份),是由CPU 或有DMA 能力的单元,用来沟通这些单元想要存取(读取/写入)电脑内存元件/地方的实体位址。数据总线的宽度,随可寻址的内存组件大小而变,决定有多少的内存可以被访问。
  • atomic所说的线程安全只是保证了getter和setter存取方法的线程安全,并不能保证整个对象是线程安全的。
  • 这里推荐的哲神的文章其中对于地址总线方面的看法还是一个猜想,到底怎么样也是没人知道

读写权限

  • 读写权限这一块很好理解,就是一个readwrite以及一个readonly
  • readwrite:其修饰的属性拥有“获取方法”(getter)与“设置方法”(setter)。
  • readonly:其修饰的属性仅拥有获取方法。
  • 这一块可以联想到runtime源码中,关于一个对象结构体中要有rw以及ro结构体,他们其实就是readwrite以及readonly的区别

内存管理

  • 终于到重头戏了,其实对于上面这两个部分,敲过一段时间的iOS开发者心里都会有数,像原子性,无脑nonatomic,像读写权限,一般直接默认不写,真正有难度,比较复杂的都在内存管理部分
  • 下面先把最重要的四个:assgin,strong,weak,copy讲一下

内存管理四天王——ASWC

assgin

  • assgin用于基本数据类型的默认属性关键字,它等于就是啥也没干,不会使得引用计数加一,赋值的时候就是简单的赋值,简单来说,就是用于不需要非对象
  • 这里要讲清楚一个概念,在探究内存管理属性关键字的时候,会大量涉及到引用计数+1的概念,这里要注意,都指的是赋值的时候会不会引用计数加一。
  • 什么意思呢?之前有是看了看组里大一的同学学习,印象很深的有一个同学写了个NSInteger *obj = xxxx
  • 这样的写法可能是来自于认为以NS开头的都是OC对象,可惜的是,如果查看过NSInteger的定义,就这么一句:typedef long NSInteger;
  • 所以,我们讲到的基本数据类型其实就是非对象的数据类型,学到现在,你看到已经知道,指针是存在栈区,对象本身是存在堆区,两者本身不是连在一起的
  • 而指针里面会存着对象的地址,也就是指针指向了对象
  • 霹雳吧啦讲了一大堆,我们拉回来看下assgin的作用,由于是直接赋值,不改变引用计数,这就限制了我们只能用它来来修饰非对象
  • 假如我们使用它来修饰一个对象,首先会报警告【Assigning retained object to unsafe property; object will be released after assignment】;我们假设有A,B两个指针指向某个对象,在有引用计数管理的情况下,其引用计数不为0就不会释放,而如果我们用的是assgin,就会导致该对象直接被释放了。A,B指针没有被置nil,出现野指针
  • 而用它来修饰基本数据类型,由于它们都是被分配在栈上的,栈的内存由系统总结自动处理回收

strong

  • strong是对象的默认内存管理关键字,在学过ARC中的strong修饰符后,基本就不会有什么问题了
  • 是对象的默认属性关键字,此特质表明该属性定义了一种“持有关系”,为这种属性设置新值时,设置方法会先保留(retain)新值,并释放(release)旧值,然后再将新值设置上去。
  • 这个感觉真没啥好说的,看学长面试讲到strong都很尬

weak

  • 此特质表明该属性定义了一种“非持有关系”。为这种属性设置新值时,设置方法既不保留(retain)新值,也不释放(release)旧值。此特质同assign类似,然而在属性对象所指的对象遭到摧毁(dealloc)时,属性值也会清空(置nil)。
  • weak要深挖就参看我runtime系列文章中相关部分就行

copy

  • 终于到重头戏copy了,我们好好研究下
  • 此特质表达的所属关系与strong类似。然而设置方法并不保留新值,而是将其拷贝(copy)
  • 这一部分推荐看哲神的详解iOS开发中复制对象
  • NSString、NSArray、NSDictionary 等等经常使用copy关键字,是因为他们有对应的可变类型:NSMutableString、NSMutableArray、NSMutableDictionary;
  • 理解:这里我认为意思就是由于NSString存在可变类型NSMutableString,那么假设我们整了一个NSString类型的属性A,又有一个NSMutableString类型的可变字符串B,我们把B赋给A;假如我们的A使用strong的话,他就是直接指针赋值,A,B指向同一块内存,这样我们修改B,同时就会修改A;而当我们使用的是copy的时候,这样我们A持有就是一个B的不可变副本,那么不管B怎么改,A都是不变的

杂鱼小虾

  • retain:在ARC时代,strong等于retain,引用计数会加一
  • unsafe_unretained:此特质的语义和assign相同,但它适用于“对象类型”,该特质表达一种“非持有关系”,当目标对象销毁时,属性值不会自动清空(unsafe),这一点与weak有区别。

总结

默认关键字

  • 基本数据:atomic,readwrite,assign
  • 普通的 OC 对象: atomic,readwrite,strong

weak与assgin的区别

  • weak 策略在属性所指的对象遭到摧毁时,系统会将 weak 修饰的属性对象的指针指向 nil,在 OC 给 nil 发消息是不会有什么问题的;如果使用 assign 策略在属性所指的对象遭到摧毁时,属性对象指针还指向原来的对象,由于对象已经被销毁,这时候就产生了野指针,如果这时候在给此对象发送消息,很容造成程序奔溃
  • assigin 可以用于修饰非 OC 对象,而 weak 必须用于 OC 对象。

查漏补缺:

  • strong、weak、retain、assgin、copy、unsafe_unretained

retain:释放旧对象,提高输入对象的引用计数+1,将输入对象的值赋值于旧对象,只能用户声明OC对象

@property (nonatomic, retain) Room *room;
- (void)setRoom:(Room *)room // room = r
{
    // 只有房间不同才需用release和retain
    if (_room != room) {  
        // 将以前的房间释放掉 -1,将旧对象释放
        [_room release];

        // MRC中需要手动对房间的引用计数器+1
        [room retain];

        _room = room;
    }
}

strong:强引用,它是ARC特有。在MRC时代没有,相当于retain。由于MRC时代是靠引用计数器来管理对象什么时候被销毁所以用retain,而ARC时代管理对象的销毁是有系统自动判断,判断的依据就是该对象是否有强引用对象。如果对象没有被任何地方强引用就会被销毁。所以在ARC时代基本都用的strong来声明代替了retain。只能用于声明OC对象(ARC特有)
苹果官网对strong的解释代码:

Precondition:object is a valid pointer to a __strong object which is adequately aligned for a pointer. value is null or a pointer to a valid object.

Performs the complete sequence for assigning to a __strong object of non-block type [[*]]. Equivalent to the following code:

void objc_storeStrong(id *object, id value) {
  id oldValue = *object;
  value = [value retain];
  *object = value;
  [oldValue release];
}

assgin:简单的赋值操作,不会更改引用计数,用于基本的数据类型声明。

weak:弱引用,表示该属性是一种“非拥有关系”。为这种属性设置新值时既不会保留新值也不会释放旧值,类似于assgin。 然而在对象被摧毁时,属性也会被清空(nil out)。这样可以有效的防止崩溃(因为OC中给没有对象地址的指针发送消息不会崩溃,而给有内存地址但地址中是空对象的指针发消息会崩溃,野指针),该声明必须作用于OC对象。对于 weak 对象会放入一个 hash 表中。 用 weak 指向的对象内存地址作为 key,当此对象的引用计数为0的时候会 dealloc,假如 weak 指向的对象内存地址是a,那么就会以a为键, 在这个 weak 表中搜索,找到所有以a为键的 weak 对象,从而设置为 nil。(ARC特有),strong 和 weak的指针,根本区别在于,strong执行了retain操作,而weak没有。

苹果官网对weak的说明
id objc_storeWeak(id *object, id value);
Precondition: object is a valid pointer which either contains a null pointer or has been registered as a __weak >object. value is null or a pointer to a valid object.

If value is a null pointer or the object to which it points has begun deallocation, object is assigned null and >unregistered as a __weak object. Otherwise, object is registered as a __weak object or has its registration >updated to point to value.

Returns the value of object after the call.

copy:不同于其他声明,copy会根据声明的属性是否是可变类型而进行不同操作。如果对象是一个不可变对象,例如NSArray NSString 等,那么copy等同于retain、strong。如果对象是一个可变对象,例如:NSMutableArray,NSMutableString等,它会在内存中重新开辟了一个新的内存空间,用来 存储新的对象,和原来的对象是两个不同的地址,引用计数分别为1. 这就是所谓的深拷贝浅拷贝,浅拷贝只是copy了对象的内存地址,而深拷贝是重新在内存中开辟新空间,新空间对象值与拷贝对象的值一样。但是是完全不同的2个内存地址。 例如copy修饰的类型为 NSString不可变对象时,copy可以保护其封装性,当赋值对象是一个 NSMutableString 类时(NSMutableString是 NSString 的子类,表示一种可修改其值的字符串),此时若是不用copy修饰拷贝字符串,那么赋值该对象之后,赋值对象字符串的值就可能会在其他地方被修改,修改后赋值后对象也会改变,造成值不对。所以,这时就要拷贝一份“不可变” (immutable)的字符串,确保对象中的字符串值不会无意间变动。只要实现属性所用的对象是“可变的” (mutable),就应该在设置新属性值时拷贝一份。

unsafe_unretained:和weak 差不多,唯一的区别便是,对象即使被销毁,指针也不会自动置空, 对象被销毁后指针指向的是一个无用的内存地址(野地址)。如果对象销毁后后还使用此指针,程序会抛出 BAD_ACCESS 的异常。 所以一般不使用unsafe_unretained。目前我还未在实际项目中使用过该声明。(ARC特有)

  • 2.4 readOnly、readWrite、getter=、setter=

readOnly表示属性仅能读不能设置其值。告诉编译器只生成getter方法不生成setter方法。

readWrite默认值,表示属性可读可写。编译器会自动生成getter setter方法

getter=指定属性gettter方法的方法名

@property (nonatomic, strong, getter=getMyDic) NSMutableDictionary *dic;

setter=指定属性setter方法的方法名

@property (nonatomic, strong,setter=myArray:) NSMutableArray *arr;

2.5__unsafe_unretained、__weak、__strong

__unsafe_unretained

NSMutableArray __unsafe_unretained *array = [[NSMutableArray alloc]init];
[array addObject:@"123"];

使用__unsafe_unretained修饰符的变量与使用__weak修饰符的变量一样,因为自己生成并持有的对象不能继续为自己持有,所以生成的对象会立即被释放。也就是说在执行完init方法以后,对象指针所指向的内存就已经释放掉了,但因为用的__unsafe_unretained修饰指针并没不像__weak的指针那样,将指针自动置为nil,它依然指向原来的地址,可是这块地址的内存已经被系统回收了,再访问就是非法的,也就是野指针,再执行后面的addObject方法自然会出错了。

__weak
主要用于解决循环引用,用__weak修饰的变量 当对象释放后,指针自动设置为nil,当后面继续使用该指针变量的时候不会造成crash,更不会造成强引用使该释放的对象无法释放,造成内存泄露。

__weak typeof(self) weakSelf = self;

__strong
相反与__weak,主要用于当使用某个对象是,希望它没有提前被释放。强引用该对象使其无法释放。例如在block内部,希望block调用时该对象不会被提前释放造成错误。可以使用强引用。

TestAlertView *alertView = [TestAlertView new];
alertView = ^()
{
  //当block内部需要使用本身这个局部对象时,需要用强引用方式,让alertView在传递完block后不会被释放依然可以执行setTitle操作
   __strong typeof(alertView) strongAlertView = alertView;
  [strongAlertView setTitle:@"1234"];

}
[alertView show];

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