1.当成员变量提供了实现了 @property (nonatomic, copy) NSString *appName; @property (nonatomic, retain) UIImageView *appIconView;并且@synthesize的时候,只要@property里面有retain copy strong的时候,都需要在dealloc里面释放内存,一般采用self.appName = nil的方式,当然也可以[appName release]; self.appName = nil相当于 if(appName != nil){ [appName release]; appName = nil;}
2.对于没有提供get和set的成员变量只有用release来进行释放;
3.对于如果在.m文件里面需要赋值的成员变量appIconView 不要直接写appIconName =[ [UIImageView alloc] init]; 应该先声明一个局部的UIimageView然后赋值,UIIageView *imageVIew= [[UIImageView alloc] init]; appIconView = imageVIew; [imageVIew release];
4.一般情况下在UIViewController里面是尽量不要给UIView控件提供get set方法的 因为这些方法是在头文件里定义的,对外部是公开的,所以考虑安全性尽量避免提供外部接口,只有在结构体或者数据模型类里面需要为外部提供接口的时候才会给成员变量设置get set方法
关于@property 和 @syn
@synthesize window=_window; 意思是说,window 属性为 _window 实例变量合成访问器方法。
也就是说,window属性生成存取方法是setWindow,这个setWindow方法就是_window变量的存取方法,它操作的就是_window这个变量。通过这个看似是赋值的这样一个操作,我们可以在@synthesize 中定义与变量名不相同的getter和setter的命名,籍此来保护变量不会被不恰当的访问。
下面是一个常见的例子
写法一:
C代码
@interface MyClass:NSObject{
MyObjecct *_myObject;
}
@property(nonamtic, retain) MyObjecct *myObject;
@end
@implementatin MyClass
@synthesize myObject=_myObject;
写法二:
C代码
@interface MyClass:NSObject{
}
@property(nonamtic, retain) MyObjecct *myObject;
@end
@implementatin MyClass
@synthesize myObject=_myObject;
这个类中声明了一个变量_myObject,又声明了一个属性叫myObject,然后用@synthesize生成了属性myObject的存取方法,这个存取方法的名字应该是:setmyObject和getmyObject。@synthesize myObject=_myObject的含义就是属性myObject的存取方法是做用于_myObject这个变量的。这种用法在Apple的Sample Code中很常见。
弄明白了这个语句的意思之后,我们也就清楚了myObject和_myObject的区别,那么,在使用的时候,有什么需要注意的地方,大家应该也都清楚了。是的,myObject是属性,而_ myObject才是变量,我们最终操作的变量都是myObject。
那么,同样是存取操作,语句
C代码
self.nameVarPtr = [[ObjectName alloc] init]
C代码
nameVarPtr = [[ObjectName alloc] init]
两种赋值方式的区别何在呢?
self.nameVarPtr=xxx 这种赋值方式等价于调用 [self setnameVarPtr:xxx], 而setnameVarPtr:xxx的方法的实现又是依赖于@property的属性的,比如retain,assign等属性。
nameVarPtr = xxx 的赋值方式,仅仅是对一个指针进行赋值。nameVarPtr仅仅是一个指针变量,记录了xxx的地址。在这个过程中不会调用setter方法,不会调用setter方法,就和@property没有关系,从而,也和retain,assign等属性没有关系。这种赋值方式就是一个简单的指针赋值。
综上,对成员变量进行赋值,为防内存泄露需要注意的点:
1.self调用setter方法的方式
ObjectName* tmp= [[ObjectName alloc] init];
self.nameVarPtr =tmp; //retainCount=2
[tmp release]; //retainCount=1 { 因为考虑到self.nameVarPtr = tmp 即setnameVarPtr的实现是 if[ _nameVarPtr != tmp]{ [_nameVarPtr release ]; _nameVarPtr = tmp;} 所以不会存在多次调用set方法导致指针计数器一直增加的情况(set方法依赖于@property 二@property里面有retain属性) }
2.指针赋值方式,不会调用setter方法
nameVarPtr= [[ObjectName alloc] init]; // retainCount=1
所以,笔者建议大家在对某个变量进行赋值操作的时候,尽量要写self.myObj = xxx; 这才是最可靠的方法。
@property和@synthesize可以自动生成某个类成员变量的存取方法
readwrite:这个属性是默认的情况,会自动为你生成存取器
assign:这个属性一般用来处理基础类型,比如int、float等等,如果你声明的属性是基础类型的话,assign是默认的,你可以不加这个属性
natomic:默认是有该属性的,这个属性是为了保证程序在多线程情况,编译器会自动生成一些互斥加锁代码,避免该变量的读写不同步问题
readonly:只生成getter不会有setter方法
copy:这个会自动生成你赋值对象的克隆,相当于在内存中新生成了该对象的副本,这样一来,改变赋值对象就不会改变你声明的这个成员变量了
retain:会自动retain赋值对象
nonatomic:如果该对象无需考虑多线程的情况,请加入这个属性,这样会让编译器少生成一些互斥加锁代码,可以提高效率
assign:指定setter方法用简单的赋值,这是默认操作。你可以对标量类型(如int)使用这个属性。你可以想象一个float,它不是一个对象,所以它不能retain、copy。
assign:简单赋值,不更改索引计数(Reference Counting).使用assign: 对基础数据类型 (NSInteger)和C数据类型(int, float, double, char,等)
retain:指定retain应该在后面的对象上调用,前一个值发送一条release消息。你可以想象一个NSString实例,它是一个对象,而且你可能想要retain它。
retain:释放旧的对象,将旧对象的值赋予输入对象,再提高输入对象的索引计数为1 ,使用retain: 对其他NSObject和其子类 ,retain,是说明该属性在赋值的时候,先release之前的值,然后再赋新值给属性,引用再加1。
copy:指定应该使用对象的副本(深度复制),前一个值发送一条release消息。基本上像retain,但是没有增加引用计数,是分配一块新的内存来放置它。copy是创建一个新对象,retain是创建一个指针,引用对象计数加1。copy:建立一个索引计数为1的对象,然后释放旧对象,copy是创建一个新对象,retain是创建一个指针,引用对象计数加1。
readonly:将只生成getter方法而不生成setter方法(getter方法没有get前缀)
。
readwrite:默认属性,将生成不带额外参数的getter和setter方法(setter方法只有一个参数)
。
atomic:对于对象的默认属性,就是setter/getter生成的方法是一个原子操作。如果有多个线程同时调用setter的话,不会出现某一个线程执行setter全部语句之前,另一个线程开始执行setter的情况,相关于方法头尾加了锁一样。
nonatomic:不保证setter/getter的原子性,多线程情况下数据可能会有问题。nonatomic,非原子性访问,不加同步,多线程并发访问会提高性能。先释放原先变量,再将新变量 retain然后赋值;
注意,如果不加此属性,则默认是两个访问方法都为原子型事务访问。
Objective-C 中创建对象分为 alloc 和 init 两步,alloc 是在堆(heap)上初始化内存给对象变量,把变量(指针)设为 nil。每个类可以很多 init 方法,且每个方法都以 init 开头,但每个类只有一个特定(designated)的 init 方法,NSObject 是 init;,UIView 是 - (id)initWithFrame:(CGRect)aRect;。在子类的 designated 方法中一定要调用父类的 designated 方法,子类其他的 init 方法只能调用子类自己的 designated 方法,不能调用父类的(即使用 self 而不是 super)。例如 - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (id)init
{
if(self = [super init])
{
//code..
}
return self;
}
@"string" 是 autorelease 的
NSString 一般是 copye 而不是 retain
你应该尽快 release 你拥有的对象,越快越好。建议创建完对象后就写好 release 的代码
当最后一个对象 owner release 后,会自动调用 dealloc 函数,在类中需要重载 dealloc,但永远都不要自己去调用 dealloc
@property 一般直接返回对象变量,我们可以把它理解为返回的是 autolease 的对象
使用 @synthesize 实现时,@property 可以指定 setter 函数使用 retain,copy 或 assign。assign 一般用在属性一定会随着对象的消亡而消亡的,比如 controller 的view,view 的 delegate
关于autorelease
autorelease究竟是什么时候被释放?首先可以告诉你,没有时间点! 可能是立即,也可能是过了几s,也可能是过了几个小时!从这里就可以看出, 如果一个实例被标识为autorelease多危险!其实,这个的释放时间,要看此时的 runloop执行多久,当然没有几个小时那么夸张!但是,只要是内存不能被立即 释放,肯定会或多或少的导致内存使用不合理,内存累积严重!所以,个人推荐 不这么用!