iOS中的限定符

一、变量限定符

ARC为变量提供了四种生命周期限定符

  • __strong

    这是默认的限定符,无需显示引入。只要有强引用指向,对象就会长时间驻留在内存中。

  • __weak

    这表明引用不会保持被引用对象的存活。当没有强引用指向对象时,弱引用会被置为nil。对象被回收的时候,__weak具有安全性,即指针将自动设置为nil。

  • __unsafe_unretained

    与__weak类似,只是当没有强引用指向对象时,不会被置为nil。

  • __autoreleasing

    用于由引用使用id *传递的消息参数,它预期了autorelease方法会在传递参数的方法中被调用。

使用这些限定符的基本格式如下:

变量类型 * 限定符类型 变量名

举例说明如下:

    /**
     创建对象后,引用计数为1,并且对象p1在引用期间不会被回收
     */
    Person * __strong p1 = [[Person alloc] init];
    /**
     创建对象后,引用计数为0,对象会被立即释放,且对象p2被置为nil
     */
    Person * __weak p2 = [[Person alloc] init];
    /**
     创建对象后,引用计数为1,对象会被立即释放,但p3不会被置为nil
     */
    Person * __unsafe_unretained p3 = [[Person alloc] init];
    /**
     创建对象后,引用计数为1,当方法返回时,对象会被立即释放
     */
    Person * __autoreleasing p4 = [[Person alloc] init];

二、属性限定符

属性限定符一共有六个:

  • strong

    默认限定符,指定了__strong关系

  • weak

    指定了__weak关系

  • assign

    这不是新的限定符,但是其含义发生了改变。在ARC之前,assign是默认的的持有关系限定符,在启动了ARC之后,assign表示了__unsafe_unretained关系

  • copy

    暗指了__strong关系。此外,它还暗指了setter中的复制语义的常规行为

  • retain

    指定了__strong关系

  • unsafe_unretained

    指定了__unsafe_unretained关系

【注意】 因为assignunsafe_unretained只进行值复制并没有任何实质性的检查,所以他们只应该用于值类型(BOOLNSInteger等),应避免将他们用于引用类型,尤其是指针类型,如(NSString *UIView *等)

限定符在开发中的使用

一、照片模型

创建一个名为YSTPhoto类,里面titleurlcomments等等属性,同时在类.m文件里实现它的dealloc方法,来观察对象从创建到最终释放的生命周期过程。

新建YSTPhoto类,提供3个属性值

@interface YSTPhoto : NSObject

/**
 照片的url地址
 */
@property (nonatomic, strong) NSURL *url;

/**
 照片的名字
 */
@property (nonatomic, copy) NSString *title;

/**
 照片的评论数
 */
@property (nonatomic, strong) NSArray *comments;

@end
@implementation YSTPhoto

- (void)dealloc{
    NSLog(@"YSTPhoto is dealloced!");
}

@end

二、绑定插座变量

Storyboard中添加一个标签resultLabel和四个按钮,然后在ViewController中对按钮进行事件的绑定,每次触发按钮点击事件后,将相应的结果显示在resultLabel上。

故事板

三、方法实现

在每一个方法中做如下事情:

  1. 创建一个YSTPhoto对象,并打印对象;
  2. 设置对象图片的title
  3. resultLabel中显示该对象的引用是否为nil。如果不是nil,则显示title

实现createStrongPhoto方法

- (IBAction)createStrongPhoto:(id)sender {
    //方法一进入的时候打印当前方法名
    NSLog(@"%s enter", __PRETTY_FUNCTION__);
    //__strong 修饰
    YSTPhoto *__strong photo = [[YSTPhoto alloc] init];
    NSLog(@"strong photo: %@", photo);
    photo.title = @"Strong Photo";
    
    NSMutableString *ms = [[NSMutableString alloc] init];
    [ms appendString:(photo == nil? @"Photo is nil" : @"Photo is not nil")];
    [ms appendString:@"\n"];
    if (photo != nil) {
        [ms appendString:photo.title];
    }
    self.resultLabel.text = ms;
    //方法执行结束前打印当前方法名
    NSLog(@"%s exit", __PRETTY_FUNCTION__);
}

/**
打印结果如下:
 2017-07-04 17:28:13.370 变量限定符的使用[8550:287995] -[ViewController createStrongPhoto:] enter
2017-07-04 17:28:13.370 变量限定符的使用[8550:287995] strong photo: <YSTPhoto: 0x608000220540>
2017-07-04 17:28:13.371 变量限定符的使用[8550:287995] -[ViewController createStrongPhoto:] exit
2017-07-04 17:28:13.371 变量限定符的使用[8550:287995] YSTPhoto is dealloced!
 */

实现createWeakPhoto方法

- (IBAction)createWeakPhoto:(id)sender {
    NSLog(@"%s enter", __PRETTY_FUNCTION__);
    YSTPhoto *__weak photo = [[YSTPhoto alloc] init];
    NSLog(@"weak photo: %@", photo);
    photo.title = @"Weak Photo";
    NSMutableString *ms = [[NSMutableString alloc] init];
    [ms appendString:(photo == nil? @"Photo is nil" : @"Photo is not nil")];
    [ms appendString:@"\n"];
    if (photo != nil) {
        [ms appendString:photo.title];
    }
    self.resultLabel.text = ms;
    NSLog(@"%s exit", __PRETTY_FUNCTION__);
}

/**
打印结果如下:
2017-07-04 17:36:20.692 变量限定符的使用[8690:293630] -[ViewController createWeakPhoto:] enter
2017-07-04 17:36:20.693 变量限定符的使用[8690:293630] YSTPhoto is dealloced!
2017-07-04 17:36:20.693 变量限定符的使用[8690:293630] weak photo: (null)
2017-07-04 17:36:20.694 变量限定符的使用[8690:293630] -[ViewController createWeakPhoto:] exit
*/

实现createStrongToWeakPhoto方法

- (IBAction)createStrongToWeakPhoto:(id)sender {
    NSLog(@"%s enter", __PRETTY_FUNCTION__);
    YSTPhoto *__strong sphoto = [[YSTPhoto alloc] init];
    NSLog(@"Strong Photo: %@", sphoto);
    sphoto.title = @"Strong Photo, Assigned to weak";
    YSTPhoto *__weak wphoto = sphoto;
    NSLog(@"Weak Photo: %@", wphoto);
    
    NSMutableString *ms = [[NSMutableString alloc] init];
    [ms appendString:(wphoto == nil? @"Photo is nil" : @"Photo is not nil")];
    [ms appendString:@"\n"];
    if (wphoto != nil) {
        [ms appendString:wphoto.title];
    }
    self.resultLabel.text = ms;
    NSLog(@"%s exit", __PRETTY_FUNCTION__);
}

/**
打印结果如下:
2017-07-04 17:43:49.639 变量限定符的使用[8810:298477] -[ViewController createStrongToWeakPhoto:] enter
2017-07-04 17:43:49.640 变量限定符的使用[8810:298477] Strong Photo: <YSTPhoto: 0x608000031920>
2017-07-04 17:43:49.641 变量限定符的使用[8810:298477] Weak Photo: <YSTPhoto: 0x608000031920>
2017-07-04 17:43:49.641 变量限定符的使用[8810:298477] -[ViewController createStrongToWeakPhoto:] exit
2017-07-04 17:43:49.642 变量限定符的使用[8810:298477] YSTPhoto is dealloced!
*/

实现createUnsafeUnretainedPhoto方法

- (IBAction)createUnsafeUnretainedPhoto:(id)sender {
    NSLog(@"%s enter", __PRETTY_FUNCTION__);
    YSTPhoto *__unsafe_unretained photo = [[YSTPhoto alloc] init];
    NSLog(@"__unsafe_unretained photo: %@", photo);
    photo.title = @"__unsafe_unretained Photo";
    NSMutableString *ms = [[NSMutableString alloc] init];
    [ms appendString:(photo == nil? @"Photo is nil" : @"Photo is not nil")];
    [ms appendString:@"\n"];
    if (photo != nil) {
        [ms appendString:photo.title];
    }
    self.resultLabel.text = ms;
    NSLog(@"%s exit", __PRETTY_FUNCTION__);
}

/**
打印结果如下:
2017-07-04 18:12:05.914 变量限定符的使用[9330:318662] -[ViewController createUnsafeUnretainedPhoto:] enter
2017-07-04 18:12:05.915 变量限定符的使用[9330:318662] YSTPhoto is dealloced!
2017-07-04 18:12:05.915 变量限定符的使用[9330:318662] *** -[YSTPhoto setTitle:]: message sent to deallocated instance 0x60000002bba0
(lldb) 
*/

对以上的测试结果进行分析如下:

  1. __strong引用确保了对象在其作用域内不被销毁,对象只会在方法调用完成后被回收;
  2. __weak引用对引用计数没有贡献,对象会被立即回收,甚至在其被用于紧邻的下一个语句前;
  3. createStrongToWeak方法中,虽然__weak引用不会增加引用计数,但是之前创建的__strong引用确保了对象不会再方法结束前释放;
  4. createUnsafeUnretainedPhoto中,对象会被立即释放,但是由于内存还没有被回收,这个引用还可以使用,不会报错;但是,当再次调用这个对象的时候,内存已经重新分配了,这样就导致了非法访问,程序直接崩溃。在打印结果中,-[YSTPhoto setTitle:]: message sent to deallocated instance 0x60000002bba0这正是因为内存已经被回收了,所以在调用setter方法的时候,就提示找不到。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,163评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,301评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,089评论 0 352
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,093评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,110评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,079评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,005评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,840评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,278评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,497评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,667评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,394评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,980评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,628评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,649评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,548评论 2 352

推荐阅读更多精彩内容