29

私は C++ の世界から来たので、代入の概念thisは私を身震いさせます:

this = new Object; // Gah!

しかし、Objective-C には同様のキーワード があり、selfこれは完全に受け入れられます。

self = [super init]; // wait, what?

サンプルの Objective-C コードの多くは、上記の行をinitルーチンで使用しています。私の質問:

1) 代入が意味を成すのはなぜですかself(「言語で許可されているため」などの回答はカウントされません)。

2)ルーチンで割り当てselfを行わないとどうなりますか? initインスタンスを何らかの危険にさらしていませんか?

3) 次のifステートメントが失敗した場合、それは何を意味し、そこから回復するにはどうすればよいですか?

- (id) init
{
    self = [super init];

    if (self)
    {
        self.my_foo = 42;
    }

    return self;
}
4

6 に答える 6

34

これは、初心者が頻繁に挑戦するトピックです。

基本的に、スーパークラスが指定された初期化子をオーバーライドして、 から返されたものとは異なるオブジェクトを返す可能性があるという考えに由来します+allocsuperの初期化子の戻り値を に代入しなかった場合self、部分的に初期化されたオブジェクトを処理する可能性があります (初期化されたオブジェクトは、super初期化するオブジェクトと同じではないため)。

super全体として、 が別のものを返すことはほとんどありませんが、いくつかのケースでは発生します。

于 2009-08-27T15:23:44.443 に答える
10

Objective-C では、イニシャライザには、失敗時に nil を返すか、イニシャライザが呼び出されたオブジェクトとはまったく異なるオブジェクトを返すオプションがあります (たとえば、NSArray は常にこれを行います)。の戻り値をキャプチャしない場合init、メソッドは割り当て解除されたオブジェクトのコンテキストで実行されている可能性があります。

スーパークラス初期化子から何か他のものが返されることを期待していない場合、自己への代入リガマロール全体を実行する必要があるかどうかについて意見が分かれる人もいますが、一般的には防御的なコーディングであると考えられています。

はい、奇妙に見えます。

于 2009-08-27T15:26:18.167 に答える
6

nil初期化が失敗した場合、initがを返す可能性があるのは事実です。しかし、これは、独自の初期化子を実装するときに自分自身に割り当てる必要がある主な理由ではありません。

前に説明しましたが、さらに強調する必要があります。初期化子から返されるインスタンスは、送信したインスタンスと同じではない場合があります。実際、同じクラスではない場合もあります。

一部のクラスはこれを標準として使用します。たとえば、すべての初期化子はNSStringNSArray常に別のクラスの新しいインスタンスを返します。のイニシャライザーUIColorは、特殊なクラスの別のインスタンスを頻繁に返します。

そして、あなた自身が望むなら、幸いにもこのようなものを実装することができます:

-(id)initWithName:(NSString*)name;
{
  if ([name isEqualToString:@"Elvis"]) {
    [self release];
    self = [[TheKing alloc] init];
  } else if (self = [super init]){
    self.name = name;
  }
  return self;
}

これにより、APIのクライアントが気にかけたり、それについて知ったりすることなく、特別なケースの実装を別のクラスに分割できます。

于 2009-08-28T21:56:30.860 に答える
3

ここでの他のすべてのポイントは有効ですが、これselfはすべての Objective-C メソッドに対する暗黙のパラメーターであり (objc_msgSend()渡され)、他のメソッド パラメーターと同様に書き込むことができることも理解することが重要です。(明示的なパラメーターへの書き込みは、それらが out パラメーターでない限り、一般的に嫌われます。)

通常、これは-init他の人が述べた理由により、メソッドでのみ行われます。selfメソッドから返され、割り当てで使用されるため、効果があるだけid obj = [[NSObject alloc] init];です。たとえば、myVar がクラスの ivar である場合、メソッドでそれにアクセスすると暗黙的にに解決されましたself->myVar

于 2009-08-27T15:52:33.263 に答える
1

私はまだ Objective C に慣れていませんが、この投稿はこれを理解するのに役立ちました。

要約すると、ほとんどの init 呼び出しは、self が既に初期化されているのと同じオブジェクトを返します。エラーが発生した場合、init は nil を返します。また、シングルトンや一意のオブジェクト (NSNumber 0 など) などの一部のオブジェクトは、初期化されたオブジェクト (シングルトンまたはグローバル 0 オブジェクト) とは異なるオブジェクトを返します。このような状況では、そのオブジェクトを自己参照する必要があります。私はここで舞台裏で何が起こっているかについて決して専門家ではありませんが、表面的には理にかなっています。

于 2009-08-27T15:24:47.220 に答える
1

[super init]nil を返す場合は、割り当てが解除され、selfパラメーターが無効なポインターになったことを意味します。規約にやみくもに従うself = [super init]ことで、潜在的に厄介なバグからあなたを救うことができます。

次の非典型的な初期化子を検討してください。

- (id)initWithParam:(id)param {
    if (!param) {
        // Bad param.  Abort
        self = [super init]; // What if [super init] returns nil?
        [self release];
        return nil;
    }
    else 
    {
        // initialize with param.
        ...
    }
}

スーパークラスがアボートして nil を返すことにした場合はどうなるでしょうか。割り当てが解除され、selfパラメーターが無効になり、[self release]クラッシュします。を再割り当てすることselfで、そのクラッシュを回避できます。

于 2009-08-28T00:02:09.843 に答える