Objective-C では alloc と init が別々に呼び出されるのはなぜですか?
-
21-09-2019 - |
質問
注記:私は Objective-C には比較的慣れておらず、Java と PHP から来ています。
なぜ常に最初にインスタンスを割り当ててから初期化する必要があるのか誰か説明してもらえますか?
次のような init メソッドでこれを行うことはできませんか:
+ (MyClass*)init {
MyClass *instance = [MyClass alloc];
[instance setFoo:@"bla"];
return instance;
}
+ (MyClass*)initWithString:(NSString*)text {
MyClass *instance = [MyClass init];
[instance setFoo:text];
return instance;
}
...
これは単に古い C 時代の名残なのでしょうか、それとも私が見ていない何かがあるのでしょうか?
alloc と init を常に呼び出すこともできるので、これが問題ではないことはわかっていますが、少し面倒なので、少なくともなぜそうするのかを知りたいと思っています。
私は今のところ言語の表現力が気に入っていますが、これは Objective-C の考え方をするために十分に理解しておきたいことです。
ありがとう!
解決
+新しい両端ます。
次は(Smalltalkのアイデアだった)+新しいメッセージが早い段階で、彼らは複数回同じオブジェクトを初期化できるようにしたかったような状況に遭遇したこと。
他のヒント
インスタンスの作成とインスタンスの初期化は 2 つの別個のジョブであるためです。
あなたは、 alloc
メッセージをクラスに送信して、初期化されていないインスタンスを取得します。次にインスタンスを初期化する必要がありますが、多くの場合、これを行う方法がいくつかあります。例えば:
myStr = [[NSString alloc] init]; //Empty string
myStr = [[NSString alloc] initWithFormat:@"%@.%@", parentKeyPath, key];
myStr = [[NSString alloc] initWithData:utf16data encoding:NSUnicodeStringEncoding error:&error];
myStr = [[NSString alloc] initWithContentsOfURL:URL encoding:NSUTF8StringEncoding error:&error];
これらはそれぞれ、まったく異なる方法で文字列を初期化します。文字列を初期化する方法は、それを初期化する対象によって異なります。
もちろん、文章を書くのが好きな人はいません alloc
その後 init
その後 autorelease
毎回なので、通常は便利なメソッドがあります(例: stringWithFormat:
) 3 つのステップすべてを実行します。
編集:コメント投稿者からの重要な洞察など、このトピックの詳細については、私のブログ投稿「再会”.
NSZone
を参照してください。
+alloc
ココアは、メモリ割り当てを最適化するために提供する機構である+allocWithZone:
のショートカットカットである。
あなたはこのような何かをするためのオプションを持っているのでます:
foo = [[NSString allocWithZone:MyZone] initWithString:@"Foo"];
foo2 = [foo copyWithZone:MyZone];
メモリゾーンの背後にある考え方は、あなたが頻繁に割り当てられ、それらのオブジェクトに対して個別のメモリ領域を使用することがかもしれない、より効率的な割り当てが解除されている類似したオブジェクトの数が多い場合ということです。
有効であることがゾーニングのためには、それゆえ、あなたが別の割り当てと初期化に必要な、すべてのNSObjectのサブクラスに利用できる+allocWithZone:
にしたいと思います。あなたは+new
のような、しかし、あなたがすでに割り当てられているオブジェクトを初期化-init
方法を必要とするそれをすべての下に、あなたが望むすべてのショートカットを作成して使用することができます。
は、「インスタンス作成の割り当てと初期化の段階を分離する多くの利点を提供します。これは、インスタンスを割り当てるために+ののallocクラスメソッドのいずれかのバリエーションを使用し、それを作る新しいinstance.Thisで使用可能な任意の初期化子を使用することが可能ですすべての配分方法の代替実装を提供することなく、独自の初期化メソッドを作成することが可能。 既存の方法は、ほとんどすべてのニーズに応えるため、新たな配分方法はほとんど作成されません。しかし、1つ以上の新しい初期化子は、ほぼすべてのクラスのために作成されます。割り当てと初期段階の分離に、実装初期化子のみ、新しいインスタンスの変数に対処する必要があり、完全に問題が大きく上回るallocation.The分離が初期化子の作成プロセスを簡素化し、丸め無視することができます。また、-initWithCoder等ココア標準イニシャライザ:かかわらず、例えば、方法メモリのインスタンスと作業が割り当てられました。 割り当てと初期化の分離の一つの負の結果は、初期化子を指定し、どのサブクラスで新しい初期化子を作成し、ドキュメントにされている方法を知っている必要があり、そのような指定initializer.Youなどの規則を意識する必要があります。長期的には、指定された初期化子簡素化ソフトウェアの開発を使用しますが、theTwoステージの作成パターンは、ココアの開発者のための初期の学習曲線に追加するなされるべき引数があります。 "の
<時間>(C)エリックM.バックドナルドA. Yacktmanによってココアデザインパターン
あなたがする必要はありません。あなたは[MyClass new]
を使用することができます。これは架空のinit
方法に似てます。
基本的には、最初にガベージコレクションを持っていなかったのObjective-Cは、メモリの割り当てとクラスの初期化の概念を分離します。二つの異なる方法がある理由です。あなたがalloc
を呼び出すと、明示的にメモリを割り当てるされます。
ほとんどのクラスは、あなたが求めているものを持っています。あなたはそれがあると、なぜあなたは、常にすべての時間これを使用したくないだろうが、あなたがクラスにドキュメントを読めば、あなたがこのように行動し、それらがしばしば使用されている多くのクラスメソッドが表示されますように、これはある理由で前の回答を得ています。
例えば、あなたが持っているのNSStringのために、
+ (id)string // (Empty string)
+ (id)stringWithFormat:... // Formatted string (like you use)
+ (id)stringWithContentsOfURL:... // String populated with contents of URL
と上のようにします。そして、あなたはその後、同じようにこれを使用します。NSString *myString = [NSString stringWithFormat:@"Hello %@\n", userName];
他のほとんどのクラスはNSArrayのように、これを持ってます:
+ (id)array
+ (id)arrayWithContentsOfFile:...
+ (id)arrayWithContentsOfURL:...
+ (id)arrayWithObjects:...
あなただけのドキュメントを読んでする必要があります。 :)そして、あなたはあまりにも多く、これを使用したくない理由について、他の回答をお読みください。
割り当てる :メモリはオブジェクト参照に割り当てられます。現在、参照はメモリを所有していますが、まだ何もしていません。このメモリは空であるか (最もまれなケース)、匿名データが含まれています。
割り当てと初期化 :割り当てられたメモリがクリーンアップ/空になります。メモリはゼロビットから開始されます。
alloc と initwithdata... :割り当てられたメモリは、クラスのプロパティに従って必要なデータで開始されます。
たとえば、土地を購入すると、所有権が得られます。この区画は現状のまま提供されており、廃墟となったレンガや古い家がそこにある場合があります。これは 割り当てる.
敷地を掃除し、汚れやゴミをすべて取り除くとき。これは initで割り当てます。
それを価値のある家に建てると、それはあなたにとってより意味のあるものになります。そしてそれは 初期化を割り当てます...