iOS5的strong,weak,unsafe_unretained ARC自动管理内存

来源:互联网 发布:淘宝设置客服 编辑:程序博客网 时间:2024/05/17 19:57

一、iOS5的strong,weak,unsafe_unretained

原文链接http://blog.csdn.net/sillyboytao/article/details/7664847

1.简单讲strong等同retain;

weak比assign多了一个功能,当对象消失后自动把指针变成nil,好处不言而喻。

2.iOS5中加入了新知识,就是ARC,其实我并不是很喜欢它,因为习惯了自己管理内存。但是学习还是很有必要的。
在iOS开发过程中,属性的定义往往与retain, assign, copy有关,我想大家都很熟悉了,在此我也不介绍,网上有很多相关文章。 
现在我们看看iOS5中新的关键字strong, weak, unsafe_unretained. 可以与以前的关键字对应学习strong与retain类似,weak与unsafe_unretained功能差不多(有点区别,等下回介绍,这两个新关键字与assign类似)。在iOS5中用这些新的关键字,就可以不用手动管理内存了,从java等其它语言转过来的程序员非常受用。

3.strong关键字与retain类似,用了它,引用计数自动+1,用实例更能说明一切。

(1)strong与strong

声明属性:

  1. @property (nonatomic, strong) NSString *string1;     

  2. @property (nonatomic, strong) NSString *string2;    

并定义:

  1. @synthesize string1;     

  2. @synthesize string2;    

 输出结果:

  1. self.string1 = @"String 1";     

  2. self.string2 = self.string1;     

  3. self.string1 = nil;    

  4. NSLog(@"String 2 = %@", self.string2);   

结果是:String 2 = String 1
分析:由于string2是strong定义的属性,所以引用计数+1,使得它们所指向的值都是@"String 1", 如果你对retain熟悉的话,这理解并不难。

(2)strong与weak
声明属性: 

  1. @property (nonatomic, strong) NSString *string1;     

  2. @property (nonatomic, weak) NSString *string2;   

并定义 :

  1. @synthesize string1;     

  2. @synthesize string2;    

输出结果:

  1. self.string1 = [[NSString alloc] initWithUTF8String:"string 1"];     

  2. self.string2 = self.string1;     

  3. self.string1 = nil;    

  4. NSLog(@"String 2 = %@", self.string2);   

结果是:String 2 = null 
分析:由于self.string1与self.string2指向同一地址,且string2没有retain内存地址,而self.string1=nil释放了内存,所以string1为nil。声明为weak的指针,指针指向的地址一旦被释放,这些指针都将被赋值为nil。这样的好处能有效的防止野指针。在c/c++开发过程中,为何大牛都说指针的空间释放了后,都要将指针赋为NULL. 在这儿用weak关键字帮我们做了这一步。 

(3)strong与unsafe_unretained 
从名字可以看出,unretained且unsafe,由于是unretained所以与weak有点类似,但是它是unsafe的,什么是unsafe的呢,下面看实例。 
声明属性:

  1. @property (nonatomic, strong) NSString *string1;     

  2. @property (nonatomic, unsafe_unretained) NSString *string2;   

并定义 :

  1. @synthesize string1;     

  2. @synthesize string2; 


输出结果:

  1. self.string1 = [[NSString alloc] initWithUTF8String:"string 1"];     

  2. self.string2 = self.string1;     

  3. self.string1 = nil;    

  4. NSLog(@"String 2 = %@", self.string2);    


分析:请注意,在此我并没有叫你猜会有什么输出,因为根本不会有输出,你的程序会crash掉。 
原因是什么,其实就是野指针造成的,所以野指针是可怕的。为何会造成野指针呢?同于用unsafe_unretained声明的指针,由于self.string1=nil已将内存释放掉了,但是string2并不知道已被释放了,所以是野指针。然后访问野指针的内存就造成crash.  所以尽量少用unsafe_unretained关键字。 

4.strong,weak, unsafe_unretained往往都是用来声明属性的,如果想声明临时变量就得用__strong,  __weak, __unsafe_unretained,  __autoreleasing, 其用法与上面介绍的类似。 
还是看看实例吧。
(1)__strong,__weak,__unsafe_unretained

  1. __strong NSString *yourString = [[NSString alloc] initWithUTF8String:"your string"];     

  2. __weak  NSString *myString = yourString;     

  3. yourString = nil;     

  4. __unsafe_unretained NSString *theirString = myString;    

  5. //现在所有的指针都为nil   

再看一个: 

  1. __strong NSString *yourString = [[NSString alloc] initWithUTF8String:"string 1"];     

  2. __weak  NSString *myString = yourString;     

  3. __unsafe_unretained NSString *theirString = myString;    

  4. yourString = nil;     

  5. //现在yourString与myString的指针都为nil,而theirString不为nil,但是是野指针。   



在这儿也说一下字符串相关的,如果NSString *str = @"str test";这样将声明一个字符串常量,这样声明的不受上面所说的限制。 
如: 

  1. __strong NSString *yourString = @"test string";     

  2. __weak  NSString *myString = yourString;     

  3. yourString = nil;     

  4. //现在myString还是有值的    


NSString *str = [[NSString alloc]  initWithString:@"test"];
这样返回的也是字符串常量, 效果与 NSString *str = @"test";是一样的。  但得遵循苹果内存管理,在非ARC的情况下还是要调用release,其实不需要调用也不会内存泄漏。 

(2)__autoreleasing的用法介绍: 
在c/c++,objective-c内存管理中有一条是:谁分配谁释放。 __autoreleasing则可以使对像延迟释放。比如你想传一个未初始化地对象引用到一个方法当中,在此方法中初始化此对像,那么这种情况将是__autoreleasing表演的时候。看个示例: 


  1. -(void) generateErrorInVariable(__autoreleasing NSError **)paramError

  2. {     

  3.     NSArray *objects = [[NSArray alloc] initWithObjects:@"A simple error", nil];    

  4.     NSArray *keys = [[NSArray alloc] initWithObjects:NSLocalizedDescriptionKey, nil];    

  5.     NSDictionary *errorDictionary = [[NSDictionary alloc] initWithObjects:objects forKeys:keys];    

  6.     *paramError = [[NSError alloc] initWithDomain:@"MyApp" code:1 userInfo:errorDictionary];    

  7. }    

  8. -(void)test    

  9. {    

  10.     NSError *error = nil;     

  11.     [self generateErrorInVariable:&error];    

  12.     NSLog(@"Error = %@", error);    

  13. }    


被编译器翻译后就变为: 

  1. -(void)test    

  2. {    

  3.     NSError *error = nil;     

  4.     NSError * __autoreleasing tmp = error;    

  5.     [self generateErrorInVariable:&tmp];    

  6.     error = tmp;    

  7.     NSLog(@"Error = %@", error);    

  8. }   


这样即便在函数内部申请的空间,在函数外部也可以使用,同样也适合谁分配谁释放的原则。 
同样下面的代码也是类似原因, 只不过在没有开启ARC的情况下适用: 

  1. -(NSString *)stringTest    

  2. {    

  3.     NSString *retStr = [NSString stringWithString:@"test"];    

  4.         

  5.     return [[retStr retain] autorelease];    

  6. }    



开启ARC后,应改为:经过测试下面这种方法是可行的,不过都不建意这样写代码, __autoreleasing官网的例子是用在传引用参数当中(像上面那个NSError)。所以最好不要像下面这样用 

  1. -(NSString *)stringTest    

  2. {    

  3.     __autoreleasing NSString *retStr = [NSString alloc] initWithString:@"test"];    

  4.         

  5.     return retStr;    

  6. }    

  7.   

  8. - (NSString *)stringTest __attribute__((ns_returns_autoreleased)){ NSString *retStr = [NSString alloc] initWithString:@"test"];return retStr;}    


与上面功能相似。返回一个autorelease。 

(3)关于methord family, 如果方法名是以alloc, init, copy, mutablecopy,new字符开头的,那么它们的返回值会被retain的,其它的默认就是autorelease返回的。下面介绍一下返回值的例子: 

  1. - (id) foo __attribute((ns_returns_retained));   //返回值retain +1, init,new,alloc,copy,mutablecopy default are this    

  2. - (id) foo __attribute((ns_returns_not_retained));  //返回指针弱引用,    

  3. - (id) foo __attribute((ns_returns_autoreleased));  //返回autorlease,  except default, are this    


init开头的方法有一个规定,一定要返回id或父类,子类的指针,不然要有warning. 
这儿是原话: 
init methods must be instance methods and must return an Objective-C pointer type. Additionally, a program is ill-formed if it declares or contains a call to an init method whose return type is neither id nor a pointer to a super-class or sub-class of the declaring class (if the method was declared on a class) or the static receiver type of the call (if it was declared on a protocol). 
当然你也可以打破这个规定,如果你这样声明方法: 

  1. - (void)initStr __attribute__((objc_method_family(none)));    


那么就是正确的。 

就介绍这么多了,有不对之处望指正。 
reference:http://clang.llvm.org/docs/AutomaticReferenceCounting.html 
转自:http://blog.csdn.net/favormm/article/details/7023322



二、ARC自动管理内存

1.ARC简介

原文链接  http://blog.csdn.net/ioszhaobin/article/details/7541597

ARC模式是一种自动管理内存的模式,不用手动管理,它全称是:Automatic Reference Counting。创建的时候在创建目录名的页面下面有三个可以打勾的地方,第二个,如果勾上就说明是ARC了,当然,一个项目,要用到很多开源的库,类,他们在编写的时候不是ARC模式,但不要紧,当你把开源的东西拖到项目终后,可以把他们改成ARC模式的文件,打开文件管理,找到TARGETS,它里面的Build Phases,再点Complie Sources,然后双击你要改的类,如果只想对某个.m文件不适应ARC,可以只针对该类文件加上对于单个文件,你可以使用-fno-objc-arc来为某个你希望使用手动管理内存的文件来禁用ARC。

2.ARC详细介绍

原文链接 http://hi.baidu.com/zhuliang90/item/a36648e42ab812d12a09a4f1

此文章由Tom翻译,首发于csdn的blog,任何人都可以转发,但是请保留原始链接和翻译者得名字。多谢!

Automatic Reference Counting (ARC) 是一个编译期的技术,利用此技术可以简化Objective-C编程在内存管理方面的工作量。

这里我把此技术翻译为自动内存计数器管理技术。ARC技术是随着XCode4.2一起发布的,在缺省工程模板中,你可以指定你的工程是否支持ARC技术,如果你不指定工程支持ARC技术,在代码中你必须使用管理内存的代码来管理内存。

(1)概述

自动计数(ARC)是一个编译期间工作的能够帮你管理内存的技术,通过它,程序人员可以不需要在内存的retain,释放等方面花费精力。

ARC在编译期间为每个Objective-C指针变量添加合适的retain, release, autorelease等函数,保存每个变量的生存周期控制在合理的范围内,以期实现代码上的自动内存管理。

In order for the compiler to generate correct code, ARC imposes some restrictions on the methods you can use, and on how you use toll-free bridging (see ); ARC also introduces new lifetime qualifiers for object references and declared properties.

你可以使用编译标记-fobjc-arc来让你的工程支持ARC。ARC在Xcode4.2中引入,在Mac OS X v10.6,v10.7 (64位应用),iOS 4,iOS 5中支持,Xcode4.1中不支持这个技术.

如果你现在的工程不支持ARC技术,你可以通过一个自动转换工具来转换你的工程(工具在Edit->Convert menu),这个工具会自动所有工程中手动管理内存的点转换成合适自动方式的(比如移除retain, release等)。这个工具会转换工程中所有的文件。当然你可以转换单个文件。

(2)ARC提供自动内存管理的功能

ARC使得你不需要再思考何时使用retain,release,autorelease这样的函数来管理内存,它提供了自动评估内存生存期的功能,并且在编译期间自动加入合适的管理内存的方法。编译器也会自动生成dealloc函数。一般情况下,通过ARC技术,你可以不顾传统方式的内存管理方式,但是深入了解传统的内存管理是十分有必要的。

下面是一个person类的一个声明和实现,它使用了ARC技术。

@interface Person : NSObject
@property (nonatomic, strong) NSString *firstName;
@property (nonatomic, strong) NSString *lastName;
@property (nonatomic, strong) NSNumber *yearOfBirth;
@property (nonatomic, strong) Person *spouse;
@end

@implementation Person
@synthesize firstName, lastName, yearOfBirth, spouse;
@end

(有关strong的帮助,请参考本文“一、” )

使用ARC,你可以像下面的方式实现contrived函数:

- (void)contrived
{
Person *aPerson = [[Person alloc] init];
[aPerson setFirstName:@"William"];
[aPerson setLastName:@"Dudney"];
[aPerson:setYearOfBirth:[[NSNumber alloc] initWithInteger:2011]];
NSLog(@"aPerson: %@", aPerson);
}

ARC管理内存,所以这里你不用担心aPerson和NSNumber的临时变量会造成内存泄漏。

你还可以像下面的方式来实现Person类中的takeLastNameFrom:方法,

- (void)takeLastNameFrom:(Person *)person
{
 NSString *oldLastname = [self lastName];
[self setLastName:[person lastName]];
NSLog(@"Lastname changed from %@ to %@", oldLastname, [self lastName]);
}

ARC可以保证在NSLog调用的时候,oldLastname还存在于内存中。

ARC中的新规则

为了ARC能顺利工作,特增加如下规则,这些规则可能是为了更健壮的内存管理,也有可能为了更好的使用体验,也有可能是简化代码的编写,不论如何,请不要违反下面的规则,如果违反,将会得到一个编译期错误。

  • 下面的这些函数:dealloc,retain, release, retainCount, autorelease。禁止任何形式调用和实现(dealloc可能会被实现),包括使@selector(retain), @selector(release)等的隐含调用。

    你可能会实现一个和内存管理没有关系的dealloc,譬如只是为了调用[systemClassInstance setDelegate:nil] ,但是请不要调用[super dealloc] ,因为编译器会自动处理这些事情。

  • 你不可以使用NSAllocateObject或者NSDeallocateObject.

    使用申请一块内存后,其他的都可以交给运行期的自动管理了。

  • 不能在C语言中的结构中使用Objective-c中的类的指针。

    请使用类类管理数据。

  • @autoreleasepool被引入,你可以使用这个效率更高的关键词。

  • 不能使用memory zones.

    NSZone不再需要—本来这个类已经被现代Objective-c废弃。

ARC在函数和便利变量命名上也有一些新的规定

  • 禁止以new开头的属性变量命名。

(3)ARC Introduces New Lifetime Qualifiers

ARC introduces several new lifetime qualifiers for objects, and zeroing weak references. A weak reference does not extend the lifetime of the object it points to. A zeroing weak reference automatically becomes nil if the object it points to is deallocated.

You should take advantage of these qualifiers to manage the object graphs in your program. In particular, ARC does not guard against strong reference cycles (previously known as retain cycles—see ). Judicious use of weak relationships will help to ensure you don’t create cycles.

(4)属性变量修饰符

weak和strong两个修饰符是新引进的,使用例子如下:

@property(retain) MyClass *myObject;
@property(strong) MyClass *myObject;//这两句语句作用相同

@property(assign) MyClass *myObject;
@property(weak) MyClass *myObject;
// 这两句大体相同,不同的地方在于,如果MyClass的实例析构后,这个属性变量的值变成nil,而不是一个野指针。