• ARC


     

    ARC指南1 - strong和weak指针

     

    提示:本文中所说的"实例变量"即是"成员变量","局部变量"即是"本地变量"

     

    一、简介

    ARC是自iOS 5之后增加的新特性,完全消除了手动管理内存的烦琐,编译器会自动在适当的地方插入适当的retain、release、autorelease语句。你不再需要担心内存管理,因为编译器为你处理了一切

    注意:ARC 是编译器特性,而不是 iOS 运行时特性(除了weak指针系统),它也不是垃圾收集器。因此 ARC 和手动内存管理性能是一样的,有时还能更加快速,因为编译器还可以执行某些优化

     

    二、原理

    ARC 的规则非常简单:只要有变量指向对象,对象就会存在内存。当指针指向新值,或者指针不再存在时,相关联的对象就会自动释放。这条规则对于实例变量、synthesize属性、局部变量都是适用的

     

    三、strong指针

    控制器中有个文本输入框框属性

    @property (nonatomic, assign) IBOutlet UITextField *nameField;  

     1.如果用户在文本框中输入mj这个字符串

    那么就可以说,nameField的text属性是NSString对象的指针,也就是拥有者,该对象保存了文本输入框的内容

     

    2.如果执行了如下代码

    1. NSString *name = self.nameField.text;  
    一个对象可以有多个拥有者,在上面代码中,name变量同样也是这个NSString对象的拥有者,也就是有两个指针指向同一个对象

     

    3.随后用户改变了输入框的内容,比如

    此时nameFeild的text属性就指向了新的NSString对象。但原来的NSString对象仍然还有一个所有者(name变量),因此会继续保留在内存中

     

    4.当name变量获得新值,或者不再存在时(如局部变量方法返回时、实例变量对象释放时),原先的NSString对象就不再拥有任何所有者,retain计数降为0,这时对象会被释放

    如,给name变量赋予一个新值

    1. name = @"Jake";  

     

     

    我们称name和nameField.text指针为"Strong指针",因为它们能够保持对象的生命。默认所有实例变量和局部变量都是Strong指针

     

    四、weak指针

    weak型的指针变量仍然可以指向一个对象,但不属于对象的拥有者

    1.执行下面的代码

    __weak NSString *name = self.nameField.text;  


     

    name变量和nameField.text属性都指向同一个NSString对象,但name不是拥有者

     

    2.如果文本框的内容发生变化,则原先的NSString对象就没有拥有者,会被释放,此时name变量会自动变成nil,称为空指针

    weak型的指针变量自动变为nil是非常方便的,这样阻止了weak指针继续指向已释放对象,避免了野指针的产生,不然会导致非常难于寻找的Bug,空指针消除了类似的问题

     

    3.weak指针主要用于“父-子”关系,父亲拥有一个儿子的strong指针,因此父亲是儿子的所有者;但为了阻止所有权循环,儿子需要使用weak指针指向父亲。典型例子是delegate模式,你的ViewController通过strong指针(self.view)拥有一个UITableView, UITableView的dataSource和delegate都是weak指针,指向你的ViewController

     

    五、strong和weak指针的使用注意

    1.下面代码是有问题的:

     

    1. __weak NSString *str = [[NSString alloc] initWithFormat:@"1234"];  
    2. NSLog(@"%@", str); // 打印出来是"(null)"  
    str是个weak指针,所以NSString对象没有拥有者,在创建之后就会被立即释放。Xcode还会给出警告("Warning: Assigning retained object to weak variable; object will be released after assignment")

     

     

    2.一般的指针变量默认就是strong类型的,因此一般我们对于strong变量不加__strong修饰,以下两行代码是等价的:

    1. NSString *name = self.nameField.text;  
    2. __strong NSString *name = self.nameField.text;  

     

     

    3.属性可以是strong或weak,写法如下

     

    1. @property (nonatomic, strong) NSString *name;  
    2. @property (nonatomic, weak) id delegate;  

    4.以下代码在ARC之前是可能会行不通的,因为在手动内存管理中,从NSArray中移除一个对象时,这个对象会发送一条release消息,可能会被立即释放。随后NSLog()打印该对象就会导致应用崩溃

     

     

    1. id obj = [array objectAtIndex:0];  
    2. [array removeObjectAtIndex:0];  
    3. NSLog(@"%@", obj);  
    在ARC中这段代码是完全合法的,因为obj变量是一个strong指针,它成为了对象的拥有者,从NSArray中移除该对象也不会导致对象被释放

     

     

    六、ARC小结

    1.有了ARC,我们的代码可以清晰很多,你不再需要考虑什么时候retain或release对象。唯一需要考虑的是对象之间的关联,也就是哪个对象拥有哪个对象?

    2.ARC也有一些限制:

    1> 首先ARC只能工作于Objective-C对象,如果应用使用了Core Foundation或malloc()/free(),此时还是需要你来手动管理内存

    2> 此外ARC还有其它一些更为严格的语言规则,以确保ARC能够正常地工作

    3.虽然ARC管理了retain和release,但并不表示你完全不需要关心内存管理的问题。因为strong指针会保持对象的生命,某些情况下你仍然需要手动设置这些指针为nil,否则可能导致应用内存不足。无论何时你创建一个新对象时,都需要考虑谁拥有该对象,以及这个对象需要存活多久

    4.ARC还能很好地结合C++使用,这对游戏开发是非常有帮助的。对于iOS 4,ARC有一点点限制(不支持weak指针),但也没太大关系

     

    七、ARC使用注意总结

     

    1.不能直接调用dealloc方法,不能调用retain,release,autorelease,retainCount方法,包括@selector(retain)的方式也不行
    2.可以用dealloc方法来管理一些资源,但不能用来释放实例变量,也不能在dealloc方法里面去掉[super dealloc]方法,在ARC下父类的dealloc同样由编译器来自动完成
    3.Core Foundation类型的对象仍然可以用CFRetain,CFRelease这些方法
    4.不能再使用NSAllocateObject和NSDeallocateObject对象
    5.不能在C结构体中使用对象指针,如果有类似功能可以创建一个Objective-C类来管理这些对象
    6.在id和void*之间没有简便的转换方法,同样在Objective-C和Core Foundation类型之间的转换都需要使用编译器制定的转换函数
    7.不能再使用NSAutoreleasePool对象,ARC提供了@autoreleasepool块来代替它,这样更有效率
    8.不能使用内存存储区(不能再使用NSZone)
    9.不能以new为开头给一个属性命名
    10.声明IBOutlet时一般应当使用weak,除了对StoryBoard这样nib中间的顶层对象要用strong
    11.weak相当于老版本的assign,strong相当于retain

     

     

    ARC指南2 - ARC的开启和禁止

    分类: iOS基础

    要想将非ARC的代码转换为ARC的代码,大概有2种方式:

    1.使用Xcode的自动转换工具

    2.手动设置某些文件支持ARC

     

    一、Xcode的自动转换工具

    Xcode带了一个自动转换工具,可以将旧的源代码转成ARC模式

    1.ARC是LLVM 3.0编译器的特性,而现有工程可能使用老的GCC 4.2或LLVM-GCC编译器,因此首先需要设置使用LLVM 3.0编译器:

    (现使用的XCode4.5,LLVM 3.0已经升级到LLVM 4.1)

    最好也选上Warnings中的Other Warning Flags 为 -Wall,这样编译器就会检查所有可能的警告,有助于我们避免潜在的问题

     

    2.Build Options下面的Run Static Analyzer选项也最好启用,这样每次Xcode编译项目时,都会运行静态代码分析工具来检查我们的代码

     

    3.设置"Objective-C Automatic Reference Counting"选项为YES,不过Xcode自动转换工具会自动设置这个选项,这里只是说明一下如何手动设置

     

    4.打开Xcode的自动转换工具

     

    5.Xcode会显示一个新窗口,让你选择哪些文件需要转换

    点击Check按钮,Xcode可能会弹出对话框提示项目不能转换为ARC,需要你准备好转换(这里暂时省略详细说明)

     

    6.如果没有什么警告、错误了,就会弹出一下提示窗口:

     

    7.点击Next,几秒钟后,Xcode会提示所有文件的转换预览,显示源文件的所有改变。左边是修改后的文件,右边是原始文件。在这里你可以一个文件一个文件地查看Xcode的修改,以确保Xcode没有改错你的源文件:

    点击Save即可完成转换

     

    8.自动转换之后,Xcode会移除所有retain、release、autorelease调用,这可能会导致代码出现其它警告、无效语法等,这些都需要自己手工进行修改

    注意:Xcode的自动转换工具最好只使用一次,多次使用可能会出现比较诡异的问题。假如你第一次转换没有转换所有的文件,当你稍后试图再次转换剩余的文件时,Xcode实际上不会执行任何转换操作。因此最好一次就完成转换,没有转换的文件可以考虑手工进行修改

     

    二、手动开启某些文件的ARC

    在Compiler Flags一列加上-fobjc-arc就表示开启这个.m文件的ARC

     

    三、禁止某些文件的ARC

    在Compiler Flags一列加上-fno-objc-arc就表示禁止这个.m文件的ARC

     

     

    ARC指南3 - @property

    分类: iOS基础

    本章介绍引入ARC后@property的使用,跟ARC之前的还是很不一样的

     

    一、.h和.m文件的变化说明

    1.对于.h头文件,主要是将属性定义由retain变为strong

     

    1. @property (retain, nonatomic)  
    变为

     

    1. @property (strong, nonatomic)  

    2.在ARC之前,我们经常在.m中使用分类拓展来增加私有的property

     

     

    1. @interface MJViewController ()  
    2. @property (nonatomic, retain) NSArray *data;  
    3. @end  
    这样做主要是简化实例对象的手动内存管理,让property的setter方法自动管理原来对象的释放,以及新对象的retain。但是有了ARC,这样的代码就不再需要了。一般来说,仅仅为了简化内存管理,是不再需要使用property的,虽然你仍然可以这样做,但直接使用实例变量是更好的选择。只有那些属于public的实例变量,才应该定义为property

     

    我们可以直接在.m类实现中定义private实例变量,不必写分类拓展了:

     

    1. @implementation MJViewController {  
    2.     NSArray *data;  
    3. }  
    不过还是要在viewDidUnload方法中将data设置为nil,因为data是个strong指针,当不再使用一个对象时,应该设置为nil

     

    1. - (void)viewDidUnload {  
    2.     [super viewDidUnload];  
    3.     data = nil;  
    4. }  

    二、IBOutlet

     

    在ARC中,所有IBOutlet属性都推荐使用weak, 这些view对象已经属于View Controller的view hierarchy,不需要再次定义为strong。因此,这些定义为weak的IBOutlet属性都不需要在IBOutlet中设置为nil

     

    三、@property的修饰符小结

    • strong : 该属性值对应 __strong 关键字,即该属性所声明的变量将成为对象的持有者,等同于"retain"
    • weak : 该属性对应 __weak 关键字,与 __weak 定义的变量一致,该属性所声明的变量将没有对象的所有权,并且当对象被释放之后,对象将被自动赋值nil,记住IBOutlet应该使用weak
    • unsafe_unretained : 等效于__unsafe_unretaind关键字声明的变量,等同于之前的"assign",iOS 5之前的系统用该属性代替 weak 来使用
    • copy : 和之前的copy一样,复制一个对象并创建strong关联
    • assign : 对象不能使用assign,但原始类型(BOOL、int、float)仍然可以使用

     

    ARC之strong,weak 解释

     

    先一句话总结:strong类保持他们拥有对象的活着,weak类他们拥有的对象被人家一牵就牵走,被人家一干就干死。(strong是一个好大哥所以strong,呵呵,weak是一个虚大哥所以weak,呵呵)

     

    比如有一个对象是string类,实例是@“hello”

    现有两个strong的string指针大哥a和b都指向了hello,现在b大哥把改成了指向@“hi”。那么这时候a大哥指向的值是什么呢,答案还是“hello”。然后,a大哥看hi不错,也指向了hi,那么现在hello就被都抛弃了,也就从内存中删除了。因为a大哥是strong的,既是retain或者copy的,这两个东西是可以使对象保存在计算机内存里的,所以如果即使b大哥抛弃hello,a大哥是有资本使@“hello”继续活下去。

     

    而现在又有两个对象strong的c大哥和weak的d大哥,都指向hello,现在c大哥另有所爱,指向了之前的b大哥,同时a大哥也指向了b大哥,既现在没有strong大哥指向hello。那么现在这个weak的d大哥指向的对象就是一个屁啦,既nil。

     

    strong和weak的区别
    strong表示保留它指向的堆上的内存区域不再指向这块区域了。
    也就是说我强力指向了一个区域,我们不再指向它的条件只有我们指向nil或者我自己也不在内存上,没有人strong指向我了,weak表示如果还没有人指向它了,它就会被清除内存,同时被指向nil,因为我不能读取不存在的东西。
    weak只在IOS5.0使用
    这并不是垃圾回收,我们用reference count表示堆上还有多少strong指针,当它变为0就马上释放。
     
     
     

    iOS5 ARC,IBOutlets 应该定义strong还是weak

      (2012-12-27 16:50:06)
    标签: 

    objective-c

     

    it

     
    原帖:http://blog.csdn.net/yiyaaixuexi/article/details/7864974
     

    写这篇文章的缘由,是因为我泡在stackoverflow上翻帖子,看到一个名为Should IBOutlets be strong or weak under ARC? 的帖子很热,而我对被采纳为标准答案的回答也有一些话要补充,我想对于每一个初识ARC模式的人来说,都会有这个疑问,所以不妨我也来和大家探讨一下。

     

    有人问,在ARC下,IBOutlets到底应该定义成strong 还是 weak ?支持这个答案的人最多,答案仅是摘自官方文档的一个片段:

     

    From a practical perspective, in iOS and OS X outlets should be defined as declared properties. Outlets should generally be weak, except for those from File’s Owner to top-level objects in a nib file (or, in iOS, a storyboard scene) which should be strong. Outlets that you create will therefore typically be weak by default, because:

    • Outlets that you create to, for example, subviews of a view controller’s view or a window controller’s window, are arbitrary references between objects that do not imply ownership.

    • The strong outlets are frequently specified by framework classes (for example, UIViewController’s view outlet, or NSWindowController’s window outlet).

      @property (weak) IBOutlet MyView *viewContainerSubview;
      @property (strong) IBOutlet MyOtherClass *topLevelObject;
      

    大意是说,在 ARC 中,一般outlet属性都推荐使用 weak,应该使用 strong 的 outlet 是 File's Owner连接到 nib 的顶层对象。 

    什么是 File's Owner连接到 nib 的顶层对象呢?说白话一点,就是自定义的view,不是直接作为main view里面一个sub view直接显示出来,而是需要通过实例化创建出来的。你自己实例化,当然需要strong了,不然谁还替你保留对象所有权呢?

     

    以上的分析都没有错,但是总觉得少了点什么。对于到底是weak 还是 strong,归根结底,还是要刨到对对象所有权的问题上,但是不便于总结出浅显易懂的规律性使用法则。于是,就会有一个又一个的特例打破文档所总结的常规,不明白规则的根是什么,还是会碰到麻烦的。

     

    我来举一个简单的例子,创建一个程序入口指向navigation controller的工程,导航栏上拖2个按钮:

    右侧按钮用于控制相机按钮的显示与否,按照文档的指示,我们在程序中定义这两个按钮应为weak属性

     

    1. #import   
    2.   
    3. @interface TestViewController : UIViewController  
    4. {  
    5.     BOOL isShowing;  
    6. }  
    7.   
    8. @property (nonatomic,weak)IBOutlet UIBarButtonItem *controlBtn;  
    9. @property (nonatomic,weak)IBOutlet UIBarButtonItem *cameraBtn;  
    10.   
    11. -(IBAction)controlAction:(id)sender;  
    12. @end  


     

    用右侧按钮,控制相机按钮的隐藏和显示:

     

    1. #import "TestViewController.h"  
    2.   
    3. @interface TestViewController ()  
    4.   
    5. @end  
    6.   
    7. @implementation TestViewController  
    8. @synthesize cameraBtn,controlBtn;  
    9.   
    10. - (void)viewDidLoad  
    11. {  
    12.     [super viewDidLoad];  
    13.     // Do any additional setup after loading the view, typically from a nib.  
    14.     isShowing = YES;  
    15. }  
    16.   
    17. - (void)viewDidUnload  
    18. {  
    19.     [super viewDidUnload];  
    20.     // Release any retained subviews of the main view.  
    21. }  
    22.   
    23. - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation  
    24. {  
    25.     return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);  
    26. }  
    27.   
    28. -(IBAction)controlAction:(id)sender  
    29. {  
    30.     if (isShowing) {  
    31.         self.controlBtn.title = @"显示相机";  
    32.         self.navigationItem.leftBarButtonItem = nil;  
    33.         isShowing = NO;  
    34.     }else {  
    35.         self.controlBtn.title = @"隐藏相机";  
    36.         self.navigationItem.leftBarButtonItem = cameraBtn;  
    37.         isShowing = YES;  
    38.     }  
    39. }  
    40. @end  


     

    实验结果是,第一次隐藏了相机按钮后,就再也显示不出来了。原因很简单,cameraBtn指向了空,我们丢失了cameraBtn的对象所有权。

    解决问题的办法有两个:

    1.不在xib或者storyboard上拖相机按钮,而是用代码创建,自己控制对象所有权

    2.将 cameraBtn 定义为strong

     

    我想强调的当然是第二种方法,当然了,改成strong后,相应的也需要配合ARC做下工作:

     

    1. - (void)viewDidUnload  
    2. {  
    3.     [super viewDidUnload];  
    4.     // Release any retained subviews of the main view.  
    5.     self.cameraBtn = nil;  
    6. }  

     

     

     

    顺便提一下ARC其他属性的规则:

     

    • strong:等同于"retain",属性成为对象的拥有者

    • weak:属性是 weak pointer,当对象释放时会自动设置为 nil

    • unsafe_unretained:等同于之前的"assign",只有 iOS 4 才应该使用

    • copy:和之前的 copy 一样,复制一个对象并创建 strong 关联

    • assign:对象不能使用 assign,但原始类型(BOOL、int、float)仍然可以使用 


     

    最后一句,记忆规则,理解规则,善用规则。

     

     

     

  • 相关阅读:
    Half Nice Years Gym
    LCM from 1 to n
    Educational Codeforces Round 70 (Rated for Div. 2)
    Rating(概率DP) HDU
    Josephina and RPG(概率DP) ZOJ
    数据结构实验之串二:字符串匹配(字符串哈希)
    点分治——入门学习笔记
    使用ASP.NET Core 3.x 构建 RESTful API P15 处理故障
    使用ASP.NET Core 3.x 构建 RESTful API P13 P14 获取父子关系的资源
    使用ASP.NET Core 3.x 构建 RESTful API P11 P12 ActionResult of T 以及 AutoMapper
  • 原文地址:https://www.cnblogs.com/iOS-mt/p/4174757.html
Copyright © 2020-2023  润新知