ios内存管理随笔

以下是我所总结的一些常见内存管理需要注意的方面,并没有严格意义上的数据来源,可能有些部分有歧义,不太正确或遗漏,大家可以和我说说,共同进步。

按照这样方式来使用的话,确实可以大大减少内存方面的问题,错误使用内存导致的崩溃也会少点。 

这里记录下,方便以后参考,也为大家提供个借鉴。

1. 保持对象的属性/成员变量和对象本身的引用计数保持一致

a) 成员变量初始化时,不应该用autorelease的,如果是autorelease,则最好要retain一下,保持引用计数为1,然后在dealloc中释放。

b) 对于属性,除自定义的setter方法和dealloc之外,都需要使用self.testProperty=@"testPropert"的方式来进行赋值,这样可以保持自己控制的引用计数始终为1;否则则需要在每次赋值之前都进行release。如

[_testProperty release];

_testProperty = testProperty;

c) 对应于a),所有的成员变量都需要在dealloc中进行释放。

d) 每次成员变量release之后,除非立马进行赋值,否知需要将其置为nil,防止其他引用的地方无法对其进行判断。

   dealloc中可以酌情处理,关于成员变量,不设置为nil也无妨。简单的处理方式可以将dealloc中所有的释放的变量都置为nil

e) 属性中所有的obj-c对象都应该设置为retain(delegate),对其引用计数进行+1操作,而不要使用assign

对于类似于BOOL,int,以及Core**框架等则需要使用assign,不需要更改引用计数。

但是delegate等需要使用assign来进行属性声明,当前对象不应该管理代理对象的引用计数。

如:

@property (nonatomic, copy)   NSString*testProperty;

@property (assign)      BOOLflag;

@property (assign)      id<property>delegate;

f) 基本原则,谁分配,谁释放。在和C框架交互使用时更应该注意。 

g) 注意在struct中使用obj-c对象的内存释放问题,确保在free的时候将引用计数变为0,或已经是autorelease

2. 属性关键字的使用

a) retaincopy的区别

retain的生成的代码类似于如下:

- (void)setTestProperty:(id)testProperty
{
    if(_testProperty != testPropert)
    {
        [_testProperty release];
        _testProperty = [testPropert retain];
    }
}

所以retain会释放旧的值,然后设置为新的值,并retain,自身保持其引用计数。从此也可以看出,成员变量_testProperty引用外部变量时,始终会retain一次。

copy会产生一个新的对象指针,例如

一个NSString*的地址为0x0011,内容为@"testProperty"

copy操作之后,产生一个新的NSString *,其地址为0x1122,内容相同,新的对象的retainCount1,不对旧对象进行操作,故旧对象没有任何变化。

所以可以理解为retain其实是对指针的拷贝,copy是对内容的拷贝。但是由于NSArray,NSDictionay对象等,由于其内容也是指针,故拷贝的其实是数组内部的指针。

也即一般情况下,都可以将NSString 的属性声明为copy的。如@property (nonatomic, copy) NSString *test; 

b) assign,nonatomic

assign, Setter方法为直接赋值,不进行retain操作,通常是为了基本类型或像delegate之类的引用(防止出现循环引用问题)

nonatomic, 非原子性访问,不加同步,多线程并发访问会提升性能,如果不加此属性,默认为原子型事务。锁被加到所属对象实例级。nonatomic使用也较多。

c) @synthesize xxx; xxx生成相应的Setter/Getter方法

d) 系统会默认分配一个没有对应变量的属性,如下示例:

@property (nonatomic, copy) NSString *testProperty;

@synthesize testProperty;

示例中并未声明任何变量对应与testProperty属性,但是仍然可以使用self.testProperty来进行赋值和取值。

这是因为系统会默认分配一个_testProperty的变量来与之对应。但建议还是添加一个成员变量,这样更为清晰。 

3. obj-c编程中使用了CoreGraphics.frameworkCoreTelephony.frameworkC框架

该类C框架采用CFRelease/CFRetain去控制对象的生命周期。其可以与obj-c对象直接转换。例如:

NSString *str = [NSStrig stringWithFormat:@"%@", @"abcdefg"];

CFStringRef ref = (NSString *)[str retain];

此时需要使用CFRelease(ref);来对其进行释放; 

4. 直接使用C语言,则需要自己去控制内存的分配和释放

mallocfree需要严格对应,如果作为函数参数的话,需要使用指向指针的变量来作为函数参数。外部提供释放。

关于这块,建议看看圣经《深入理解计算机系统》,上面讲得非常透彻与详细。 

5.  特殊场景

a) @"123", 以及initWithString等产生的引用计数都是非常大的。对此执行的release操作只是为了与之前的init对应,并不会真正的释放

b) 对象release之后,不会立刻释放,如:

[obj release];

NSLog(@"obj = %@", obj); // 这句话不会导致崩溃

NSLog(@"obj = %@", obj); // 此时的调用会导致崩溃

c)NSAutoreleasePool的性能问题

NSAutoreleasePool也会占用一定的性能,在XCode4.2中默认使用的编译期支持@autoreleasepool{}块来代替NSAutoreleasePool,其性能相对于

NSAutoreleasePool来说,有较大的提升(记得曾经看过一份文档说会提升6倍以上)。

by yytong

posted @ 2012-03-12 22:30  iPhone Dev  阅读(1364)  评论(0编辑  收藏  举报