ARC - strong和weak指针

 

ARC指南1 - strong和weak指针

 

 

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

 

1、简介java

ARC是自iOS 5以后增长的新特性,彻底消除了手动管理内存的烦琐,编译器会自动在适当的地方插入适当的retain、release、autorelease语句。你再也不须要担忧内存管理,由于编译器为你处理了一切ios

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

 

2、原理app

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

 

3、strong指针函数

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

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

 1.若是用户在文本框中输入mj这个字符串oop

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

 

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指针

 

4、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

 

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

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

 

[java] view plaincopy
  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修饰,如下两行代码是等价的:

[java] view plaincopy
  1. NSString *name = self.nameField.text;  
  2. __strong NSString *name = self.nameField.text;  

 

 

3.属性能够是strong或weak,写法以下

 

[java] view plaincopy
  1. @property (nonatomic, strong) NSString *name;  
  2. @property (nonatomic, weak) id delegate;  

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

 

 

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

 

 

6、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指针),但也没太大关系

 

7、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

 

1、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实际上不会执行任何转换操做。所以最好一次就完成转换,没有转换的文件能够考虑手工进行修改

 

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

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

 

3、禁止某些文件的ARC

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

 

 

 

ARC指南3 - @property

分类: iOS基础

本章介绍引入ARC后@property的使用,跟ARC以前的仍是很不同的

 

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

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

 

[java] view plaincopy
  1. @property (retain, nonatomic)  
变为

 

[java] view plaincopy
  1. @property (strong, nonatomic)  

2.在ARC以前,咱们常常在.m中使用分类拓展来增长私有的property

 

 

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

 

咱们能够直接在.m类实现中定义private实例变量,没必要写分类拓展了:

 

[java] view plaincopy
  1. @implementation MJViewController {  
  2.     NSArray *data;  
  3. }  
不过仍是要在viewDidUnload方法中将data设置为nil,由于data是个strong指针,当再也不使用一个对象时,应该设置为nil

 

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

2、IBOutlet

 

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

 

3、@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)仍然可使用 


 

最后一句,记忆规则,理解规则,善用规则。
相关文章
相关标签/搜索