Objective-Cにおけるinit関数実装に関する研究if((self=[super init])!=nil)

9041 ワード

今日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(P 25)説明が見つかりました.その節の例の対応コードは次のとおりです.
    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. 
博文です.このブログでは、著者らは2つの形式の初期化方法を比較した.
    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]を用いなければ正しくない場合はあり得ないと考えているので,第2の方法が正しいと考えている.彼は以前のブログで、誰がこのような状況を見つけることができたら、その人に20ドルをあげたと言ったことがある.
しかし、著者らは、Cocoaライブラリの各クラスに自動的にサブクラスを派生させ、プログラムをインスタンス化し、初期化時にselfを返すかどうかを判断するKen Ferryという人がプログラムを作成したと告白している.最終的に、このプログラムKen Ferryは、single intance(単一インスタンス)のクラスであるこのようなクラスを見つけました.
ここまで言うと、単一インスタンスのクラス初期化関数は、最初に呼び出されたときに新しいインスタンスを返し、後で呼び出されたときに最初に生成されたインスタンスだけを返します.この場合,著者らが提案した方式2にも問題がある.親が単一例モードを採用すると,サブクラスで[super init]が返すのは確かにnilではないが,サブクラスオブジェクトに含まれるその親オブジェクトではない.これにより,サブクラスオブジェクトに含まれるその親オブジェクトは初期化されず,初期化関数の目的を達成しなかった.
しかし、最初の方法も間違っていることに気づくべきです.selfは親を指す単一のインスタンスに再配向され、selfがもともと指していたオブジェクトが「チェーンが詰まっていない犬」(ポインタが指していない)になったため、メモリ漏れが発生します.
どちらも不足していたのですが、どうすればいいのでしょうか.著者らは3つ目の方法を提案した.
    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と子のselfのタイプはidタイプ(汎用タイプ)です.親のinitメソッド返されるポインタがselfと異なる場合、親のinitメソッドにはreleaseと新しいメモリ割り当てが行われており、自分でrelease sefに行く必要はなく、親のinitメソッドで返されるポインタを直接使えばよい.
  
1年以上javaを学んで、if(self=[super init])という文の意味を理解していなかったが、最近同僚の説明を聞いて、「super init」は親の変数を初期化する方法であり、self=[super init]は子クラスに相当してこれらの変数と方法を初期化したが、ifで判断すると、selfが空の場合、すなわち作成に失敗することを防ぐためだと悟った.
selfは戻り値として指定され、この戻り値はself=〔super init〕でsuperオブジェクトに送信されるinitメッセージから得られ、C++背景があれば、これを見るときっと苦しくて震えるに違いない.あまりいらいらしないで、大丈夫です.これは、Object-Cで親のinitメソッドを手動で呼び出さなければならないことを意味します.親クラスの自動呼び出しはありません.selfがnilを返す可能性があるため、selfが「super init」の戻り値を指定する必要があります.
Objective-Cオブジェクトを作成するには、allocとinitの2つのメッセージが必要です.allocの役割はメモリ空間を割り当てることであり,initはオブジェクトを初期化することである.InitとallocはいずれもNSObjectに定義されたクラスメソッドであり,オブジェクトがこの2つのメッセージを受信して正しく応答した場合,新しいエンティティが適切に準備される.次に例を示します.
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];