内存使用的N个建议

1> 使用alloc、new、copy族(如mutableCopy)创建的对象,要使用release/autorelease。使用retain的对象,同样处理。没有使用这四者的,不能用release/autorelease。

// 必须release
TestClass *ptr = [[TestClass alloc] init];
...
[ptr release];


// 不用release
NSString *str;
str = [NSString stringWithFormat:@"Some string here..."];
NSLog(str);


// 使用getter得到的,不增加引用计数,所以不用release
NSString *str;
str = [TestClass firstName];


2> alloc之后立刻init

TestClass *ptr = [TestClass alloc]; // 这样写是有问题的,因为alloc有可能失败
[ptr init]
if (ptr) {
    ...


正确的写法:TestClass *ptr = [[TestClass alloc] init];

3> 给野指针赋空值:nil

#import "TestClass.h"

@implementation TestClass


-(NSString *) str

{
    return str;
}

-(void) setStr:(NSString *)input

{
    [input retain];
    [str release];
    str = input;
}

-(void) dealloc

{
    [str release];
    [super dealloc];
}

@end


#import "TestClass.h"

 
int main(int argc, const char * argv[])
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
 
    TestClass *ptr = [[TestClass alloc] init];
    [ptr setStr:@"Fubar"];
 
    [ptr release];
    [pool drain];
    return 0;
}


上面的程序看似毫无问题,但还是有问题的。

-(void) dealloc
{
    [str setStr:nil];
    [super dealloc];
}


[str setStr:nil] 来代替 [str release] 更好,可消灭野指针,和C++是一样的道理。
注:当input为nil时,[input retain] 还是合法的调用,不会引起异常。所以调用前无需检查空指针。
另外,[str setStr:nil] 还可以写成 self.str = nil ,一样是调用setter。但不能直接写成 str = nil ,这是内存泄漏。

4> iPhone 3G 有128M的内存。但给你的App的只有大约40M。即使你只用了3M内存,也有可能收到内存警报。
5> 即使用Objective-C 2.0编程,在iPhone上也没有垃圾收集机制。
6> Objective-C runtime 不允许在栈上创建对象,只能在堆上。所以不能使用智能指针帮助管理对象资源。
7> 用autorelease要小心。内存池释放时,它们才释放。如果不小心就和内存泄漏没大区别。释放内存池会花很多时间,如果里面有几万个小对象的话。

// 这样创建的都是autorelease对象,必须由内存池释放。少用!
NSString *string = [NSString stringWithFormat:@"value = %d", intVariable];

// 使用这样的方法,可以更好地利用iPhone的内存

NSString *string = [[NSString alloc] initWithFormat:@"value = %d", intVariable];
...
[string release];

// 或者在循环的时候用autorelease对象

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
for (id item in array)
{
    id anotherItem = [item createSomeAutoreleasedObject];
    [anotherItem doSomethingWithIt];
}
[pool release];


另外,千万不要对autorelease对象使用release方法:程序极可能会立刻崩溃!

8> iPhone没有内存交换文件,没有虚拟内存。物理内存没有的时候,App就挂掉了。
9> 在内存报警时,即使无法释放无用内存,至少也要像下面这样:
- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
}


或者在application delegate里写上一点儿:
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application
{
    [[ImageCache sharedImageCache] removeAllImagesInMemory];
}


NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver:self
        selector:@selector(whatever:)
        name:UIApplicationDidReceiveMemoryWarningNotification
        object:nil];

- (void) whatever: (NSNotification *)note {...}


10> 申请资源时,用“懒汉策略”

@interface UITableViewControllerSubclass
{
@private
    NSMutableArray *items;
    DetailController *detailController;
    UINavigationController *navigationController;
}
@end

@implementation UITableViewControllerSubclass


- (id)init

{
    if (self = [self initWithStyle:UITableViewStylePlain])
    {
        // only basic stuff
        items = [[NSMutableArray] alloc] initWithCapacity:20];
        navigationController = [[UINavigationController alloc]
                                initWithRootViewController:self];
    }
    return self;
}

- (void)dealloc

{
    [items release];
    [detailController release];
    [navigationController release];
    [super dealloc];
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath

{
    Item *item = [items objectAtIndex:indexPath.row];
    if (detailController == nil)    // 在需要的时候才分配内存
    {
        detailController = [[DetailController alloc] init];
    }
    detailController.item = item;
    [self.navigationController
        pushViewController:detailController
                  animated:YES];
}
...


可以使用 UIViewController 的 viewWillAppear 和 viewDidDisappear 来申请/释放资源。
可以使用 UITabBarControllerDelegate 的 tabBarController:didSelectViewController: 来进一步控制资源的加载和释放。

11> 使用正确的setter:

@interface SomeClass
{
@private
    NSArray *items;
    NSString *name;
    id<someProtocol> delegate;
}

@property (nonatomic, retain) NSArray *items;

@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) id<someProtocol> delegate;
@end

@implementation SomeClass


@synthesize items;

@synthesize name;
@synthesize delegate;

- (void)dealloc

{
    [items release];
    [name release];
    delegate = nil;
}

- (void)setItems:(NSArray *)obj

{
    if (obj == items) {
        return;
    }

    [items release];
    items = nil;        // 很重要!参数obj有可能为空
    items = [obj retain];

    if (items != nil) {
        ...
    }
}

- (void)setName:(NSString *)obj

{
    [name release];
    name = nil;
    name = [obj copy];   // NSStrings总要用copy

    if (name != nil) {
        ...
    }
}

- (void)setDelegate:(id<someProtocol>)obj

{
    // 身为delegate,只需assign,不要增加引用计数
    delegate = obj;

    if (delegate != nil) {
        ...
    }
}

@end


12> 正确地处理delegate的dealloc:

@interface SomeClass <WidgetDelegate>
{
@private
    Widget *widget;
}
@end

@implementation SomeClass


- (id)init

{
    if (id = [super init]) {
        widget = [[Widget alloc] init];
        widget.delegate = self;
    }
    return self;
}

- (void)dealloc

{
    widget.delegate = nil;    // delegate已经消亡,而widget未必,所以要置空,免得
    [widget release];           // widget以后调用已经不存在的delegate的方法,会crash的!
    [super dealloc];
}

- (void)widget:(Widget *)obj callsItsDelegate:(BOOL)value

{
    // and here something happens...
}

@end

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值