IOS5(自动引用计数器) 的属性介绍

来源:互联网 发布:drgs分组器软件 编辑:程序博客网 时间:2024/05/29 19:11
目前自引进了iOS5,iPhone,iPad,iPodTouch的编程改变了很多。整个runtime和objective-c的编码方式发生了很大的改变。 在下面的文章中,我们会谈谈在objective-c runtime ARC下,怎样使用对象和管理它们!
从手工引用计数到自动引用计数(ARC)
问题:     学习Automatic Reference Counting(自动引用计数器),苹果的新的编译器解决了令人头痛的问题:在Objective-C中,当使用对象的时候,处理对象,以及管理内存。
解决: 由最新的LLVM编译器引进的新的属性存储技术:strong, weak,和unsafe_unretained
描述“在最新的LLVM编译器中,是使用了Automatic Reference Counting(ARC),我们需要处理strong,weak,或者unsafe和unretained存储技术。在ARC模式之下的对象,是由 :

strong:这种类型的对象在run-time的时候自动增加引用计数,并在它范围结束之前有效,之后就会被自动释放,熟悉Objective-C传统的内存管理办法的话,这个关键字和retain关键字很相似。

weak:这是 “归零弱引用 ”。如果变量使用这个关键字定义,当对象(变量指向的内存)被销毁了,这个变量会被设置为nil。例如:你有一个strong的string属性和一个weak的string属性,并将weak属性的值设置为strongoing属性的值,当strong属性被销毁了,那么weak属性就会被设置为nil。

unsafe_unretained:简单的将一个变量指向另一个变量。设置对象的新数值,不会增加它的引用计数,它只是简单的为变量分配了一个对象而。

 默认,所有的局部变量是strong变量。反之,属性必须明确指定它们的存储属性。你需要确定将你的属性指定为存储属性,看看下面的例子吧:

#import <UIKit/UIKit.h>@interface Moving_from_Manual_Reference_Counting_to_ARCAppDelegate : UIResponder <UIApplicationDelegate>@property (strong, nonatomic) UIWindow *window;@property (nonatomic, strong) NSString *string1;@property (nonatomic, strong) NSString *string2;@end

如果使用@"String 1"初始化string1,并将string1的属性值分配给string2,那么有着存储属性(storage attribute)的string2属性将会保存string1的值,即使在string1销毁后,string2仍然保存@"String 1"值。

#import "Moving_from_Manual_Reference_Counting_to_ARCAppDelegate.h"@implementation Moving_from_Manual_Reference_Counting_to_ARCAppDelegate@synthesize window = _window;@synthesize string1;@synthesize string2;- (BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{self.string1 = @"String 1";self.string2 = self.string1; self.string1 = nil;NSLog(@"String 2 = %@", self.string2);self.window = [[UIWindow alloc] initWithFrame: [[UIScreen mainScreen] bounds]];self.window.backgroundColor = [UIColor whiteColor];[self.window makeKeyAndVisible];return YES;}输出为:String 2 = String 1

在声明属性的时候strong, weak, unsafe_unretained会经常被用到。即使在声明局部变量的时候你也可以使用这些存储说明符,但是你需要对说明符做一点修改。strong等效的嵌入说明符为__strong,weak等效的嵌入说明符为__weak,unsafe_unretained等效的嵌入说明符为__unsafe_unretained。(记住这些关键字是以2个下划线开头),如下:

- (BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{/* All local variables are by default strong so just emphasis that.We really don't have to mention __strong for the first variable but to make it clear,we will set it. No harm in doing so. */__strong NSString *yourString = @"Your String";__weak NSString *myString = yourString;yourString = nil;__unsafe_unretained NSString *theirString = myString;/* All pointers will be nil at this time */self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];self.window.backgroundColor = [UIColor whiteColor];[self.window makeKeyAndVisible];return YES;}

当object被销毁了,这时候要解决很多的问题,但是,ARC中的“归零弱引用有用,可以解决很多问题。weak引用:当指针指向的对象被销毁了,那么weak引用的对象(a zeroing reference's object)会被设置为nil。所有指向被回收对象的weak引用(the weak referencing pointers),都会被设置为nil。
unsafe_unretained存储说明符是真正安全的,就像它的名字寓意。它安全的原因是:当unsafe_unretained变量指向的对象(object)被回收销毁了,这个变量会被设置为nil,并且将会指向内存中的a dangling location。访问这个地址可能引起程序的崩溃。为了避免这种情况,你应该使用“归零弱引用存储说明符 - zeroing weak referencing storage specifier”,weak或者内嵌(inline equivalent)说明符。

#import <UIKit/UIKit.h>@interface Moving_from_Manual_Reference_Counting_to_ARCAppDelegate : UIResponder <UIApplicationDelegate>@property (strong, nonatomic) UIWindow *window;@property (nonatomic, strong) NSString *string1;@property (nonatomic, weak) NSString *string2;@end
程序第一次运行的时候,将会初始化strong类的string1属性,然后将string1分配给string2.然后我们将string1的值设为nil。然后等待,这绝对是至关重要的。runloop除去所有无效的对象。为了实现这个目标,我们在应用程序将要进入后台的时候,我们将打印string2的值。(这是在用户将另一个应用程序移到前台时,你的应用程序进入后台)。一旦程序在后台运行,我们知道runloop已经除去了内存中所有无效对象,并且我们得到的结果将是正确的:
/* 3 */- (BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{self.string1 = [[NSString alloc] initWithUTF8String:"String 1"];self.string2 = self.string1; self.string1 = nil;/* All pointers will be nil at this time */self.window = [[UIWindow alloc] initWithFrame: [[UIScreen mainScreen] bounds]];self.window.backgroundColor = [UIColor whiteColor];[self.window makeKeyAndVisible];return YES;}- (void)applicationDidEnterBackground:(UIApplication *)application{NSLog(@"String 2 = %@", self.string2);

现在运行程序,等到1-2秒钟后,点击Home按钮。你将会注意到接下来的结果将会被打印到控制台中:

String 2 = (null)

这很容易证明ARC的“归零弱引用 - zeroing weak referencing”,实现的很完美。现在检查unsafe_unretained存储说明符是多么的危险,代码例子:

#import <UIKit/UIKit.h>@interface Moving_from_Manual_Reference_Counting_to_ARCAppDelegate : UIResponder <UIApplicationDelegate>@property (strong, nonatomic) UIWindow *window;@property (nonatomic, strong) NSString *string1;@property (nonatomic, unsafe_unretained) NSString *string2;@end

AppDelegate的实现部分,就像我们之前实现的一样,在程序进入后台的时候打印string2的值,并重复打开和最小化程序的操作,程序和crash!这就意味我们的应用程序被送到后台的时候,试图打印内存中无效对象(string2指向的对象)的内容人,然而,string2属性不安全并且 unretained(没有retain),所以string2不知道它指向的对象(in string1),当string1被设置为nil,已经被回收销毁。
除上述的3个存储说明符,我们还可以使用_说明符。如我们想向方法传递对象的引用的时候,存储说明符是最方便的。如,方法需要向调用方法(the caller method),传递一个NSError的error对象,方法将会向调用方法(the caller method)传递一个未初始化并且未分配的NSError实例对象。这就意味着调用者不需要分配这个error对象,所以,我们的方法就应该这样做。为了实现这个,error参数需要是自动释放对象,在合适的时间点的时候,通过runtime释放。

- (void) generateErrorInVariable:(__autoreleasing NSError **)paramError{ //the caller method,声明参数的类型是自动释放的类型NSArray *objects = [[NSArray alloc] initWithObjects:@"A simple error", nil];NSArray *keys = [[NSArray alloc] initWithObjects:NSLocalizedDescriptionKey, nil];NSDictionary *errorDictionary = [[NSDictionary alloc] initWithObjects:objects forKeys:keys];*paramError = [[NSError alloc] initWithDomain:@"MyApp" code:1 userInfo:errorDictionary];}- (BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{NSError *error = nil;[self generateErrorInVariable:&error];NSLog(@"Error = %@", error);self.window = [[UIWindow alloc] initWithFrame: [[UIScreen mainScreen] bounds]];self.window.backgroundColor = [UIColor whiteColor]; [self.window makeKeyAndVisible];return YES;}