Objective-C中init函数实现的相关研究 if ((self = [super init]) != nil)

今天在学习Objective-C时见到某初始化函数中有如下代码:

    self = [super init];

    if(self){

// Initialize members

    }

    return self;

    当时只是觉得Objective-C与才C++应该一样,每个子类对象都包含父类对象,所以super与self都是指向同一对象的头部的,[super init]返回的地址应该与self所代表的地址一样(即self == [super init])。那么,对self赋[super init]的值岂不是没有什么意义?

    找朱去讨论,他也不知道是因为什么。但是他想起了在《From C++ to Objective-C》中好像提到过这个情况,于是在一通查找之后终于在7.1.3(P25)找到了说明。那一节的例子中的对应代码是这样的:

    if(![super init])

return nil;

   // Initialize members

return self;

    同时下面又相应的说明:

    Polemic: Most people use the instruction self = [super init]; if (self) {...} in the initializer. This is justified by the fact that in some cases, [super init] could return a different object. However, in a very interesting document [6], Will Shipley shows that is a bad practice. It is far more logical to use the above form, where it is only checked whether [super init] returns nil or not.

    意思是很多人采用了self = [super init]; if (self) {...}的方法,这是由于有一些实践已经证明了[super init]有可能返回一个(与self所指对象)完全不同的对象。但作者推荐了一篇文章,说这篇文章证实了这个为大多数人所使用的初始化方式是一种不好的手法。

    这里所说的 a very interesting document[6] 指的是:

    [6] Will Shipley. self = [supid init]. http://wilshipley.com/blog/2005/07/self-stupid-init.html

    是一篇博文。在这篇博文里,作者对比了两种形式的初始化方法,它们是:

    1.Traditional -init

    - (id)init;

    {

if ((self = [super init]) == nil)

   return nil;

[...initialize my stuff...]

return self;

    }

    2.Wil's -init

    - (id)init;

    {

if (![super init])

   return nil;

[...initialize my stuff...]

return self;

    }

    作者认为不可能存在不用self = [super init]就不对的情况,所以他认为第二种方法才是正确的。他曾在以前的一篇博文上说谁能找到这样的情况就给那人20美元。

    但现在作者坦言这样的情况确实存在——一个名叫Ken Ferry的人编写了一个程序,该程序会自动为Cocoa库的每一个类派生出子类并产生程序将其实例化,并在初始化时判断[super init]是否返回的就是self。最终该程序Ken Ferry终于找到了一些这样的类——它们都是 single intance(单实例)的类。

    说到这里大家想必也都知道是怎么回事了,单实例的类初始化函数在第一次被调用时会返回新的实例,以后再被调用则只会返回第一次生成的实例。在这种情况下,作者提出的方式2也就有了问题 ——若遇到父类采用单例模式,则在子类中[super init]返回的确实非nil,但却也不再是子类对象所包含的那个父类对象了。如此一来子类对象所包含的那个父类对象并未被初始化,没有达到初始化函数的目的。

    但是我们也应该注意到第一种方式也是不对的——self被重新定向为指向父类那个单实例,如此一来则发生了内存泄露,因为self原先所指向的对象变成了“没有链子栓着的狗”(没有指针指向它)。

    原来两种方式都存在不足,那么该如何是好呢?作者提出了第三种方式:

    id superInitReturn = [super init];

    if(!superInitReturn || self != superInitReturn)

    {

return nil;

    }

    // Initialize memebers

    return self;

   我个人对此方法的理解是:若[super init]返回的与self不同,则说明父类是单实例类,而单实例类的init函数应该是被重写过的,一般会返回nil,遇到这种情况我们就该收手了——让你的类去继承一个单实例类并非好的设计(如果想达到类似效果,请让这个单实例成为你的类的成员)——故而返回nil。

    值得一提的是该博文为作者2005年所作,作者于2009年在末尾追加了更新,指出苹果公司有些说明表明了他们很有可能要重写[NSObject init]方法,主要是因为要采用新的内存管理手段以提高内存重用率,所以作者最终推荐的init方式为:

    -(id) init

    {

if(!(self = [super init]))

{

   return nil;

}

// Initialize members

return self;

    }

    原文如下:

    Update April, 2009:

There's been hints from Apple that they might modify the standard -[NSObject init] method to try to re-use old object's memory, since it turns out that a very common usage pattern is for programs to keep creating and deallocating, say, 12 objects of the same class, over and over. Re-using the exact same memory ends up being a big win (and this is a trick the iPhone already does with its UITableViewCell class, and that is a HUGE win if you do it yourself on the iPhone).

So, from now on, I recommend everyone uses:

Subclassing NSColorPanel the Right Way

- (id)init;

{

 if (!(self = [super init]))

   return nil;

 // other stuff

 return self;

}

I do.

    我还是感到不解,看不出他的理由是什么。明天继续研究,也希望有高手能来指点一二。

小弟最近iPhone,感到 Objective C上的一些疑,希望各高手能指一下。

............
- (id)init {
// 先父行初始化
if (self = [super init]) {
// do something
}
return self;
}
............
[[MyClass alloc] init];
............

上述是分配空然後行初始化,用父的初始化可以理解。
要返回 self ,甚要做?有父所返回的型跟子是不一的。
有在入 init 之前,self 本身指向 alloc 所予的空,我不需要先 release 它?
就像:
........
newSelf = [super init];
if (self != newSelf){
[self release];
self = newSelf;
}
return self;
...........  0

父类进行初始化时,用的是子类对象指针self,父类的init方法有可能对这个指针指向的内存区作了大的变更(有可能把这个指针所指的内存释放了,重新分配了另一块内存区域返回来,这时这个返回的指针与原来的指针是指向不同地址的),所以父类初始化后要重新返回指针。父类返回的和子类的self的类型都为id类型(通用类型)。父类的init方法若返回的指针与self不一样,在父类的init方法中已作了release和新的内存分配,不需要自己再去release sef,直接用父类init方法返回的指针就可以了。

  

 学了一年多的java,一直没搞懂if(self=[super init])这条语句的意思,最近听一个同事讲解恍然大悟,[super init]是初始化父类中的变量方法,self=[super init]就相当于子类也初始化了这些变量和方法,而用if判断下,是为了防止self为空的情况,即创建失败的情况。

self被指定为返回值,这个返回值通过self = [super init]中发送给super对象的init消息得来,如果你有C++背景,看到这个一定会痛苦得打哆嗦。不要太心烦,没关系的。它只意味着在Object-C中我们必须手工调用父类得init方法。没有对父类的自动调用。我们必须指定self为[super init]的返回值,因为它可能会返回nil。

Objective-C创建对象需通过两个消息:alloc以及init。alloc的作用是分派存储器空间,init则是对对象做初始化。 init与alloc都是定义在NSObject里的类方法,当对象收到这两个消息并做出正确回应后,新实体才算准备妥当。以下即为示例:

MyObject * my = [[MyObject alloc] init];

在Objective-C 2.0里,可以简化为单独一个消息new

MyObject * my = [MyObject new];

这仅仅是语法上的精简,效用完全相同。 若要自己定义初始化的过程,可以复写init方法,来添加额外的工作。(功用类似C++的constructor)

- (id) init { if ( self=[super init] ){ // 必須呼叫父類的init // do something here ... } return self; }

objc的对象初始化包括两步
 1. 分配内存[ClassName alloc],alloc方法继承自NSObject,分配内存,并清空置0.
2. 初始化[Object init], 返回对象实例; 注意init方法有可能返回的是跟alloc取得的不同的对象. init 是个普通的方法,类可以有多个初始化方法.
- (id) init {
    if (self = [super init]){
    }
    return (self);
}


object = [[ClassName alloc] init];
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值