内存使用的N个建议

本文详细介绍了Objective-C中内存管理的关键概念,包括使用alloc、new、copy族创建对象时如何正确使用release/autorelease,避免内存泄露。同时讨论了在iOS应用开发中合理分配资源的重要性,提供了一些实用的内存优化技巧,如使用autorelease池和避免野指针等。此外,文章还涉及了Objective-C runtime特性、setter的正确使用,以及如何在不同场景下高效管理资源,以提高应用性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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、付费专栏及课程。

余额充值