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
内存使用的N个建议
最新推荐文章于 2024-11-16 17:55:22 发布