__autoreleasing 与 局部变量

时间:2023-03-10 05:47:44
__autoreleasing 与 局部变量

__autoreleasing 修饰的变量不是局部变量;

它的生命周期由autoreleasepool负责;

+(Reachability*)reachabilityWithHostname:(NSString*)hostname

{

SCNetworkReachabilityRef ref = SCNetworkReachabilityCreateWithName(NULL, [hostname UTF8String]);

if (ref)

{

id reachability = [[self alloc] initWithReachabilityRef:ref];

return [reachability autorelease];

}

return nil;

}

局部变量由编译器插入的内存管理负责;只在作用域内有效,在步出作用域时会释放;

局部变量是强引用。

强引用的释放:

1、对象的析构释放;

2、作用域管理;

__autoreleasing

表示在autorelease pool中自动释放对象的引用,和MRC时代autorelease的用法相同。定义property时不能使用这个修饰符,任何一个对象的property都不应该是autorelease型的。

一个常见的误解是,在ARC中没有autorelease,因为这样一个“自动释放”看起来好像有点多余。这个误解可能源自于将ARC的“自动”和autorelease“自动”的混淆。其实你只要看一下每个iOS App的main.m文件就能知道,autorelease不仅好好的存在着,并且变得更fashion了:不需要再手工被创建,也不需要再显式得调用[drain]方法释放内存池。

__autoreleasing 与 局部变量

以下两行代码的意义是相同的。

NSString *str = [[[NSString alloc] initWithFormat:@"hehe"] autorelease]; // MRC

@"hehe"// ARC

这里关于autoreleasepool就不做展开了,详细地信息可以参考官方文档或者其他文章。

在中主要用在参数传递返回值()和引用传递参数()的情况下。

__autoreleasing is used to denote arguments that are passed by reference (id *) and are autoreleased on return.

比如常用的NSError的使用:

NSError *__autoreleasing error;

(![data writeToFile:filename options:NSDataWritingAtomic error:&error])

{

  @"Error: %@", error);

(在上面的writeToFile方法中error参数的类型为(NSError *__autoreleasing *))

errorstrong__autoreleasing

NSError *error;

// 编译器添加

(![data writeToFile:filename options:NSDataWritingAtomic error:&tempError])

{

  // 编译器添加

  @"Error: %@", error);

所以为了提高效率,避免这种情况,我们一般在定义error的时候将其(老老实实地=。=)声明为__autoreleasing类型的:

NSError *__autoreleasing error;

在这里,加上__autoreleasing之后,相当于在MRC中对返回值error做了如下事情:

*error = [[[NSError alloc] init] autorelease];

*error指向的对象在创建出来后,被放入到了autoreleasing pool中,等待使用结束后的自动释放,函数外error的使用者并不需要关心*error指向对象的释放。

ARC NSError **__autoreleasing比如下面的两段代码是等同的:

- (NSString *)doSomething:(NSNumber **)value

{

// do something

- (NSString *)doSomething:(NSNumber * __autoreleasing *)value

{

// do something

除非你显式得给value声明了__strong,否则value默认就是__autoreleasing的。

autorelease pool__autoreleasing比如NSDictionary的[enumerateKeysAndObjectsUsingBlock]方法:

- (void)loopThroughDictionary:(NSDictionary *)dict error:(NSError **)error

{

[dict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop){

// do stuff

if (there is some error && error != nil)

{

*error = [NSError errorWithDomain:@"MyError" code:1 userInfo:nil];

}

}];

会隐式地创建一个autorelease pool,上面代码实际类似于:

- (void)loopThroughDictionary:(NSDictionary *)dict error:(NSError **)error

{

[dict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop){

@autoreleasepool  // 被隐式创建

      {

if (there is some error && error != nil)

{

*error = [NSError errorWithDomain:@"MyError" code:1 userInfo:nil];

}

}];

// *error 在这里已经被dict的做枚举遍历时创建的autorelease pool释放掉了 :(

}

为了能够正常的使用*error,我们需要一个strong型的临时引用,在dict的枚举Block中是用这个临时引用,保证引用指向的对象不会在出了dict的枚举Block后被释放,正确的方式如下:

- (void)loopThroughDictionary:(NSDictionary *)dict error:(NSError **)error

  // 加保证可以在内被修改

  idid  {

     (there some error)

{

      @"MyError"1

}

  }]

   (error != nil)

  {

    *error = tempError;

  }

}

http://www.cnblogs.com/flyFreeZn/p/4264220.html