OBJ-C相关分析

快一年半多没有看过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的代码编辑很无语,每次都搞得排版打乱,只能不用代码编辑了!











评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值