内存问题
app中内存激增
可能的原因是:读入大量图像的同时改变其尺寸(比如循环压缩),图像文件读入到NSData对象,从中生成UIImage对象,改变对象尺寸后生成新的UIImage对象
ARC规则
ARC有效时,对象类型上必须附加所有权修饰符。所有权修饰符一共有4种:
- __strong 修饰符
- __weak 修饰符
- __unsafe_unretained 修饰符
- __autoreleasing 修饰符
- __strong 修饰符
strong修饰符是id类型和对象类型默认的所有权修饰符。id和对象类型在没有明确指定所有权修饰符时,,默认为strong。例如,下面两段代码是相同的效果:
id obj = [[NSObject alloc] init]; id __strong obj = [[NSObject alloc] init];
__strong修饰符表示对对象的强引用。持有强引用的变量在超出其作用域时被废弃,随着强引用的失效,引用的对象会随之释放。
{ //自己生成并持有对象 id strong obj = [[NSObject alloc] init]; } // 因为变量obj超出其作用域,强引用失效,所以自动释放自己持有的对象,对象的所有者不存在,因此废弃该对象
当然,不仅仅适用于自己生成并持有的对象,非自己生成并持有的对象也适用,附有strong修饰符的变量可以相互赋值,在赋值上也能够正确的管理其对象的所有者。 通过strong修饰符,不必要再次键入retain和release,完美的满足了“内存管理的思考方式”。
weak 修饰符 看起来通过strong修饰符就能完美地进行内存管理,但是实际上,仅用strong就可能会出现引用计数式内存管理中存在的“循环引用”问题。weak 修饰符就是为了解决循环引用的问题,weak 修饰符与strong相反,提供弱引用。弱引用不能持有对象实例。
{ //自己生成并持有对象 id strong obj0 = [[NSObject alloc] init]; //obj0为强引用,所以自己持有对象 id __weak obj1 = obj0; //obj1变量持有生成对象的弱引用 } // 因为变量obj0超出其作用域,强引用失效,所以自动释放自己持有的对象,对象的所有者不存在,因此废弃该对象
__weak修饰符还有一个优点,在持有某对象的弱引用时,若该对象被废弃,则此弱引用将自动失效且处于nil被赋值的状态。
__unsafe_unretained 修饰符 unsafe_unretained 修饰符,正如其名,是不安全的所有权修饰符。尽管ARC式的内存管理是编译器的工作,但附有unsafe_unretained 修饰符的变量不属于编译器的内存管理对象。
id unsafe_unretained obj1 = nil; { id strong obj0 = [[NSObject alloc] init]; //obj0为强引用,所以自己持有对象 obj1 = obj0; //虽然obj0变量赋值给obj1,但是obj1变量既不持有对象的强引用也不持有弱引用 NSLog(@"A: %@",obj1); //输出obj1变量表示的对象 }//因为obj0变量超出其作用域,强引用失效,所以自动释放自己持有的对象,因为对象无持有者,所以废弃该对象 NSLog(@"B: %@",obj1); //输出obj1变量表示的对象 obj1变量表示的对象已经被废弃(悬垂指针),错误访问
在使用unsafe_unretained修饰符时,赋值给附有strong修饰符的变量必须确保被赋值的对象却是存在。在iOS4 以后,苹果开始用weak替代了unsafe_unretained。
__autoreleasing 修饰符 虽然ARC不能直接使用autorelease,但实际上,ARC有效时autorelease功能是其起作用的。
ARC无效的时候用法如下:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; id obj = [[NSObject alloc] init]; [obj autorelease]; [pool drain];
ARC有效的时候用法就改成下面这样了:
@autoreleasepool { id __autoreleasing obj = [[NSObject alloc] init]; }
指定@autoreleasepool快来代替NSAutoreleasePool类对象生成、持有以及废弃。 NSRunLoop等实现不论ARC有效还是无效,均能够随时释放注册到autorelease中的对象。
ARC有效下的一些规则:
- 不能使用retain、release、retain、ratainCount、autorelease
- 不能使用NSAllocateObject/NSDeallocateObject
- 必须遵守内存管理的方法命名规则
- 不要显示调用dealloc
- 使用@autoreleasepool代替NSAutoreleasePool
- 不能使用区域(NSZone)
- 对象型变量不能作为C语言结构体的成员
- 显示转换id和void
- id型或对象型变量赋值给void 或者逆向赋值都需要进行特定的转换,如果只想单纯的赋值,则可以使用”__bridge 转换“。