特酷吧[]采用"署名-非商业用途-保持一致"的创作共用协议,使用本文内容请遵循该协议。 博主在现在的公司已经两年了,现在正考虑着换工作。趁着这个机会,准备把一些基础的iOS知识系统的整理下,这一篇就来说说iOS内存管理方面的,主要是ARC环境。后面可以看到,虽然ARC在本质上也是采用了引用计数的概念,但作为开发者来讲,ARC环境基本上很少考虑非ARC环境中的复杂的引用计数关系。在ARC中,只需要明确强引用和弱引用的概念,其他的问题编译器自动帮助我们完成了。 一,ARC中的变量所有权修饰符 变量修饰符,主要用来标示对象的生命周期。在手动内存管理方式中没有这些概念。 ARC环境下NSObject/id变量所有权修饰符主要有以下几个: __strong __weak __unsafe_unretained __autoreleasing 详细说明: (1)变量默认都是__strong修饰 只要强引用存在,对象就不会释放。当超过了对象的作用域以及没有强引用时,对象会自动销毁。__strong属性基本上能适应ARC环境下的所有情况。是我们最常用的,如果不写,默认是__strong属性 (2)__weak不持有对象,只是简单引用。 __weak不会阻止对象被销销毁,也就是__weak修饰的对象在其它地方没有强引用时,会自动销毁,这时__weak变量会自动设置为nil。主要是为了防止循环引用而引入的。看这个例子:
折叠C/C++ Code复制内容到剪贴板 - NSString * __weak string = [[NSString alloc] initWithFormat:@“hello”];
- NSLog(@"string: %@", string);
没有强引用的变量是会被立即释放的,所以打印的string会是nil。 (3)__unsafe_unretained,类似__weak,只是不会在没有引用的时候自动设置为nil。iOS5.0以下没有引入__weak之前使用,现在基本可以不要使用了。 (4) __autoreleasing 用于标识id*的引用参数(也就是对象的指针的指针),或者需要自动释放的返回的对象(返回值默认都会加上__autoreleasing属性,可以不用写),用来指示通过引用传递的参数。主要作用是延迟对象释放,使方法内部生成的对象可以在外部访问。等同于ARC无效时调用对象的autorelease方法。典型的就是NSError。关于__autoreleasing,我们一般很少显式的使用,但是在一些情况下默认是添加了__autoreleasing修饰的: 1,作为返回值的对象默认加上了__autoreleasing修饰 参考后面的ARC的方法命名规则,在ARC时,编译器会检查方法是否以alloc/new/copy/mutableCopy/init等开头,如果不是且有返回值的话会自己将返回值加入__autoreleasing修饰。 2,访问__weak修饰的变量时,实际上是访问到了注册到__autoreleasing的对象 例如: id __weak obj1 = obj0; NSLog(@"%@",[obj1 class]); 实际上是执行了: id __weak obj1 = obj0; id __autoreleasing obj2 = obj1; NSLog(@"%@",[obj2 class]); 3,id的指针或对象的指针在没有显式的指定时会自动加上__autoreleasing修饰。 赋值给对象指针时,所有权修饰符必须一致 (5)__strong、__weak和__autoreleasing修饰的栈变量默认都被初始化为nil (6)无修饰符的NSObject对象指针默认是__strong,而无修饰符的id指针(也就是对象的指针的指针,id本身就是指针,好比void *)默认的修饰符为__autoreleasing
表达方法: 类名* 修饰符 变量名 或者 修饰符 类名* 变量名 示例:
折叠C/C++ Code复制内容到剪贴板 - __strong NSString *string1 = @"tekuba";
- NSString * __strong string11 = @"tekuba";
- __weak NSString *string2 = @"tekuba";
- NSString * __weak string22 = @"tekuba";
- __autoreleasing NSString *string3 = @"tekuba";
- NSString * __autoreleasing string33 = @"tekuba”;
二,ARC新增的属性访问器修饰符Property Attributes 就是@property修饰的属性。 ARC之前的有retain,assign retain:相当于arc的strong。 assign:相当于arc的weak,主要还是用在一些元数据类型int、BOOL之类的。 copy:作用是一样的 和手动管理内存方式相比,ARC增加了strong,和 weak。相当于是给各属性的类成员变量增加对应的所有权修饰符。如strong对应的是__strong。 另外需要注意:在声明类成员变量时,如果同属性声明中的所有权修饰符不一致则会引起编译错误。如: id obj; @property (nonatomic , weak) id obj; obj成员变量默认是__strong,而属性修饰却用了weak,这里改成strong即可。
二,和手动内存管理的区别 (1)ARC不再使用NSZone的相关内容; (2)自定义的dealloc方法,不需要调用[super dealloc]; (3)不能实现和调用retain、release、retainCount和autorelease等相关方法; (4)id和void*没有自动转换,需要使用__bridge。 主要用在CF框架和NS框架数据转换的时候,典型的如下用法: (__bridge void *)(self) (__bridge MyNSObject *)inClientData 档案编译器不会自动管理Core foundation对象的生命周期。开发者必须根据CoreFoundation的内存管理规则,使用CFRetain和CFRelease。 关于__bridge也有几个所有权标示符: __bridge 不改变所有权的情况下,将OC和Core foundaton对象之间转换。 __bridge_retained/CFBridgingRetain 将OC和Corefoundaton对象之间进行所有权转换。 __bridge_transfer/CFBridgingRelease 将一个非OC指针,转化为OC指针,ARC负责释放对象。 (5)开发者不能使用NSAutoreleasePool对象。ARC下使用@autoreleasepool (6)ARC的方法命名规则 对象生成和持有的方法必须是alloc,new,copy,mutableCopy等开头的方法(ARC和非ARC都是这样),特别的init开头的方法必须是实例方法,且必须要返回对象。 基于这个规则,访问器方法不能已new,init(注意initiaize这样的不属于这个规则之内的,initMyObject这样的才算),copy等开头。比如你不能声明一个已new开头的属性,除非你给你指定一个getter。内部参数没有这个限制 。 如果你这么做了,在编译的时候会提示: property's synthesized getter follows Cocoa naming convention for returning 'owned’ objects 原因是:You take ownership of an object if you create it using a method whose name begins with “alloc”, “new”, “copy”, or “mutableCopy”.
三,ARC模式下的单例 在之前MRC模式下通常这样写:
折叠C/C++ Code复制内容到剪贴板 - #import <Foundation/Foundation.h>
-
- @interface Singleton : NSObject
- +(Singleton *) shareInstance;
- @end
-
- @implementation Singleton
- +(Singleton *) shareInstance
- {
- static Singleton *sharedSingleton = nil;
- @synchronized(self){
- if(sharedSingleton == nil){
- sharedSingleton =[[super allocWithZone:NULL] init];
- }
- }
- return sharedSingleton;
- }
-
- - (id)init
- {
- self = [super init];
- if (self) {
- // 通常在这里做一些相关的初始化任务
- }
- return self;
- }
-
-
- + (id) allocWithZone:(NSZone *)zone
- {
- return [[self shareInstance] retain];
- }
-
- - (id) copyWithZone:(NSZone*)zone
- {
- return self;
- }
-
- - (id) retain
- {
- return self;
- }
-
- - (NSUInteger) retainCount
- {
- return NSUIntegerMax;
- }
-
-
- -(oneway void)release
- {
- }
-
- - (id) autorelease
- {
- return self;
- }
-
- -(void)dealloc
- {
- }
-
- @end
在ARC中由于废弃了autorelease,release等方法,再结合GCD的相关知识,单例的写法可以变得很简单, 苹果的官方例子如下:
折叠C/C++ Code复制内容到剪贴板 - + (NetworkManager *)sharedInstance
- {
- static dispatch_once_t onceToken;
- static NetworkManager * sSharedInstance;
-
- dispatch_once(&onceToken;, ^{
- sSharedInstance = [[NetworkManager alloc] init];
- });
- return sSharedInstance;
- }
甚至可以写成宏定义的形式传入一个类名即可。
四,回过来看看手动内存管理 手动内存管理的规则是 (1)使用alloc,new,copy或者mutalbeCopy等方法时,以及使用addObject等时引用计数+1,release时引用计数减去1,当引用计数为0时释放内存。 (2)Property Attributes包括retain,assign retain:相当于arc的strong assign:相当于arc的weak 也基本上是这些内容。手动内存管理没有arc中的__strong等这样的对象变量修饰符。举个例子,下面的代码: -(void)test{ NSString *string = [[NSString alloc] init]; } 在手动内存管理中则会造成内存泄露,需要执行[string release]。在arc中完全没有问题,因为string默认是__strong,在超过作用域时自动释放。 认识所限,文章难免有错误的地方,欢迎批评指正。 转载请注明来自特酷吧,本文地址:http://www./program/346/ 推荐阅读: IOS ARC机制 Objective-C Runtime分析(二)-Class,Method,SEL,IMP iOS App转让流程须知
|