快一年半多没有看过OBJ-C了,基本就记得一些概念,所以决定把一些东西总结一下,看看自己理解的对不对,同时也和大家交流一下,如果发现有不对的地方,希望大家能指出来。
1.new VS alloc-init
Class* object = [Class new];
VS
Class* object = [[Class alloc] init];
这两种表达是没有差别的,new是一种向后兼容的方法,但是如果要在初始化对象是传入参数:
例如 NSString * str = [[NSSting alloc]initWithString : @"hello"];
这时候new 方法就望尘莫及了。
总的来说:
1. new 不支持自定义初始化
2. alloc -init比new 更加形象
3. 如果不需要自定义初始化,你可以随便揭谁的牌。
2. allocWithZone VS alloc
对于这两个函数的差别,由于没有官方的文档没有给出内部实现,所以网上都是给出了一些可能的猜测。其中个人认为比较对的如下:
[[Class alloc]init] 基本相当于 [[Class allocWithZone:Null]init];
其中官方文档中给出的说话是alloc中会去调用allocWithZone(具体可见官方文档的单例模式案例)。
这里有必要对allocWithZone:zone(其中zone是NSZone类型)说明一下:
先得说一下内存池,在OBJ-C中有一个内存池的概念,也是NSZone来表示,在系统中会默认创建一个内存池,当然你也可以利用NSZone的方法创建自己内存池(我没有见到过有人这样做过,当然这样会使得内存的利用率更高,效率也更快)。
大家都知道allocWithZone:zone,用于给一个对象分配内存,参数zone就是表示一个内存池,当参数为NULL时,表示从默认内存池中创建。也就是平时我们的alloc-init都是直接创建在默认内存池中。当然zone这个参数也是有用的,例如下面这种情况:
我们进行一个拷贝操作,为了能适应copy方法,我们假设已经继承了NSCoping协议和重写了copyWithZone:zone
其中我们可以这样来重写copyWithZone:zone
-(id)copyWithZone : zone
{
id newObj = [[[self class] allocWithZone:zone]init];
return newObj;
}
这个我们就可以使得新创建的对象,与原来的对象在同一个内存池内,并且在内存池中会尽可能的靠近原对象。
关于内存池的利用还有别的情况,例如:
我们在一个对象中去创建他的成员对象,这是利用[self zone]可以达到上面的提到的效果。
-(id)init {
if (self = [super init]) {
someIvar = [[SomeOtherClass allocWithZone:[self zone]] init];
}
return self;
}
总的来说就是下面这句话(个人觉得不翻译更好理解):
When one object creates another, it’s sometimes a good idea to make sure they’re both allocated from the same region of memory. The zone method (declared in the NSObject protocol) can be used for this purpose; it returns the zone where the receiver is located.
3 init函数
这个函数很基础,其实越是基础的函数,越容易挖出东西。
大家都知道init给创建的对象一个初始化的时机,你可以重载该方法,来给对象的变量自定初始化值,当然也可以调用默认的init,把初始化变量的任务交给系统。
例如:
-(id)init
{
if(self = [super init])
{
date = [[NSDate date] retain]
}
return self;
}
上面是一个到处可见的一个初始化函数。从这个函数主要做了三件事:
调用超类的初始化方法并检查其返回值
为对象的实例变量赋值
返回已完成初始化的对象
这里需要特别注意下面这句代码:
if(self = [super init])
这里有三个问题需要清楚:
1. 调用父类的init方法来初始化从父类继承过来的变量;
2. self 赋值为[super init]:可以防止父类的初始化方法release掉了self指向的空间并重新alloc了一块空间。这时的话,[super init]可能alloc失败(例如当子类中加入新的变量时),这时就不再执行if中的语句。
3.. [super init];中表面上super是作为init方法的接收者,但是其实质是self才是init方法的接收者,同时需要注意,[super message]中,message方法出现的self为[super message]语境中的self,即子类实例。
下面看一段代码:
1 父类:ClassA的init
-(id)init
{
id temp = self;
self = [ClassA alloc];
[temp release];
return self;
};
2. 子类:ClassB的init
-(id)init
{
if(self = [super init])
{
data = [[NSDate date]retain];
}
return self;
}
从上面我们可以看到父类的init把子类以前alloc的内存(大小是ClassB的size)回收了,然后又创建了一个新的内存(大小是CLassA的size),所以这个时候当ClassB中还有其他的成员变量是,内存中就放不下,因此这运行就会出现错误。
前面提到self才是init方法的接收者,所以上面ClassA的代码可以改为:
-(id)init
{
id temp = self;
self = [[self class] alloc];
[temp release];
return self;
};
这样init方法中创建的内存的size就是CLassB的size。从而不会出现上面的错误。
今天已经很晚了,我会每天更新一,两个点,希望能和大家讨论。对CSDN的代码编辑很无语,每次都搞得排版打乱,只能不用代码编辑了!