1、
从最简单的说起,先看例子,看注释:
-(void)fun1
{
str1 = @"我是str1";
NSLog(@"str1的conut: %d",[str1 retainCount]);//-1 之所以为-1,是因为直接赋值后,"我是str1"被放在常量区,没有所谓引用
}
-(void) fun2
{
str2 = [NSString stringWithFormat:@"我是str2"];
NSLog(@"str2的count: %d",[str2 retainCount]);//1。注意:stringWithFormat里面已经包含alloc和autorelease了
//[str2 release];如果加了这句,程序就崩溃。因为已经包含了autorelese,下面fun4的str2就是非法引用
}
-(void) fun3
{
str3 = [[NSString alloc]init];
str3 = @"我是str3";
NSLog(@"str3的count: %d",[str3 retainCount]);//-1 alloc跟init被忽略了,效果如fun1
}
-(void) fun4
{
NSLog(@"str2:%@",str2);
NSLog(@"str1:%@",str1);
NSLog(@"str3:%@",str3);
}
在外面:
NSLog(@"str2 final count:%d",[str2 retainCount]);//1 仍旧是1,因为由编译器来负责管理(autorelease)
NSLog(@"str3 final count:%d",[str3 retainCount]);//-1
由上面的代码示例可以看出直接赋值跟用*with*方法赋值的区别。
stringWithFormat里面已经包含alloc和autorelease。确切地说,*with*方法都包含了alloc以及autorelease
2、
在声明为@property (nonatomic, retain) UIAlertView *alert时,这里的retain不是摆设,而是retain了一次,这就刚好跟dealloc对应,在dealloc里面release
计数器加1了。所以在还没alloc之前,retainCount为1。
在.h中声明alert为成员变量,并设为property的retain属性
UIAlertView *tmpAlert = [[UIAlertView alloc]initWithTitle:tempStr
message:nil
delegate:self
cancelButtonTitle:@"取消"
otherButtonTitles:@"确定",nil];
self.alert = tmpAlert;
[tmpAlert release];
[alert addSubview:view];
[alert show];
在上例子中,一般就这么用,不要直接轻易去对alert进行alloc,这样很容易出错。常见的做法如上,设一个临时变量tmpAlert,赋值给alert后就release掉。注意,是赋值
给self.alert,而不是alert。别忘了,self.alert = tmpAlert 这句话等价于[alert release];alert = [tmpAlert retain];(为什么?)所以,为了避免额外的
错误,尽量在.h中声明property/retain属性,要赋值的时候就用self.***。
3、成员变量跟property不一定要对应存在,没有成员变量只有property也是合法的,self.***访问的就是property。
4、对一个尚未分配内存的变量进行release是合法的。但是一旦你alloc+init了之后,就不能那么随便release。请看下面比较:
UIAlertView *alert = nil; [alert release];//正确 UIAlertView *alert2 = [[UIAlertView alloc] init]; [alert release]; [alert release];//报错 NSString *str = nil; [str release];//正确 NSString *str2 = [[NSString alloc] init]; [str2 release]; [str2 release];//正确!!!!!
可以看出,NSString类型是个特列,不管你有没有alloc分配内存给他,都可以随时release。
从这个例子我们也可以看出,对于工程里面的成员变量,不应该随意去设@property属性,因为这样会暴露给别的类。但是这时候会有这样的烦恼,没有了(retain),似乎后面的内存管理会变得麻烦些。所以产生了另外一种方式,在.m文件里面,凡是用该成员变量(假设为A)的地方,首先要在init里面把A置为nil,这是为了后面release的方便,不会出错(对nil对象release是不出错的)。然后凡是对该变量进行赋值的地方,都要先release,赋值完后再retain,养成习惯吧,兄弟。
5、@property、@synthesize
这两个关键字是让成员变量生成相应的setter、getter。setter里面已经包含了必要的retain、release。平时我们用self.****就是访问setter,而没加self的就是访问普通的成员变量。
看个例子:
@interface Photo : NSObject
{
NSString* caption;
NSString* photographer;
}
- (NSString*) caption;//getter
- (NSString*) photographer;
- (void) setCaption: (NSString*)input;//setter,注意其默认的名字set+***
- (void) setPhotographer: (NSString*)input;
@end
用@property实现简化如下:
@interface Photo : NSObject
{
NSString* caption;
NSString* photographer;
}
@property (retain) NSString* caption;
@property (retain) NSString* photographer;
@end
这里的retain意思是,setter应该对input进行retain。
http://cocoadevcentral.com/d/learn_objectivec/ 原链接
- (void) dealloc
{
self.caption = nil;
self.photographer = nil;
[super dealloc];
}
6.下面介绍几个个人比较容易混淆的东西,非常实用!先总说一下,原则是:
原则1:往数组里填东西或者删除东西,数组本身的引用计数不改变!!!!,变的是被拿去添加的元素,引用计数相应增减
原则2:往view添加subview或者removeview,superView本身引用计数都不改变!!!变的是被拿去添加的subview,引用计数相应增减
原则3:subview可分为两种,一种是不需要控制的静态view,一种是被设为成员变量长期控制的动态view。 假设subview添加到superview中,并且以后不打算做改变,则应这么写:
uiview *subview = new subview;//subview:1
//若是动态view,则是_subView = new subview;//subview:1
[superView addSubView:subview];//subview:2, superview:1
[subview release];//subview:1
静态view:在dealloc中就不用再释放了!因为大原则是“谁申请谁释放”,你只申请了一次,自然只需要释放一次。剩下的1个引用什么时候减掉呢?当superView释放的时候自己释放掉!
动态view:若是动态view,则完全可以跟静态view一样,这样的话Dealloc里面就是空空的,这也是可以的;另一种是在上述步骤中不做release操作,统统保留到dealloc中做