iOS小结

__autoreleasing

2019-02-21  本文已影响7人  SylvaChen

https://blog.csdn.net/li198847/article/details/50517715

https://blog.csdn.net/junjun150013652/article/details/53149145

https://www.jianshu.com/p/ec2c854b2efd

1、声明NSError *__autoreleasing error;可以节省编译器的工作(参考下方)

比如常用的NSError的使用:

NSError *__autoreleasing error; 

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

NSLog(@"Error: %@", error); 

}

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

注意,如果你的error定义为了strong型,那么,编译器会帮你隐式地做如下事情,保证最终传入函数的参数依然是个__autoreleasing类型的引用。

NSError *error; 

NSError *__autoreleasing tempError = error; // 编译器添加 

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

error = tempError; // 编译器添加 

NSLog(@"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

{

__block NSError* tempError; // 加__block保证可以在Block内被修改 

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

if (there is some error) 

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

}  

}] 

if (error != nil) 

*error = tempError; 

  }

}

2、方法用临时变量返回和不用临时变量的区别

+ (id)Object

{

NSMutableArray *marr = [NSMutableArray array];

return marr;

}

+ (id)Object

{

return [NSMutableArray array];

}

在于临时变量在接收端赋值时会进行优化,不会入栈autoreleasepool,而不声明临时变量的返回值则(根据优化规则有可能)会入栈autoreleasepool增加成本和延长声明周期。

对函数返回值进行优化
上一篇 下一篇

猜你喜欢

热点阅读