Objective-C のプロパティ割り当ては割り当てられた値を返しますか?
-
20-09-2019 - |
質問
次のものがあるとします。
@interface MyClass : NSObject { NSString* _foobar; }
@property (nonatomic, retain) NSString* foobar;
@end
@implementation MyClass
@dynamic foobar;
- (void) setFoobar:(NSString*)fbSet; { [_foobar release]; _foobar = [fbSet retain]; }
- (NSString*) foobar; { return _foobar; }
@end
それから:
MyClass* mcInst = [[[MyClass alloc] init] autorelease];
NSLog(@"I set 'foobar' to '%@'", (mcInst.foobar = @"BAZ!"));
の戻り値を見ると、 -[MyClass setFoobar:]
, 、ここではこの行が出力されると仮定するかもしれません I set 'foobar' to ''
, 、割り当てが何も返さないように見えるためです。
ただし、ありがたいことに、この割り当ては期待どおりに動作し、コードが出力されます。 I set 'foobar' to 'BAZ!'
. 。残念ながら、呼び出されたセッターの戻り値は、割り当てがそれに割り当てられた値を返すという事実を裏切っているため、これは矛盾しているように感じられます。最初はそう思いました mcInst.foobar = @"BAZ!";
ブロックの代わりに 2 つの呼び出しを行っています。最初にセッター、次にゲッターで戻り値を収集します。ただし、setter メソッドと getter メソッドをインストルメント化すると、 NSLog
呼び出しは、そうでないことを証明します。
解決
簡単な概要:
ここでの簡単な答えは、次の式の結果が次のとおりであるため、矛盾はないということです。
(mcInst.foobar = @"BAZ!")
実は @"BAZ!"
, 、 そして ない mcInst.foobar
.
詳細については以下を参照してください。ただし、次の変更を検討すると役立つかもしれません。 setFoobar
方法:
- (void) setFoobar:(NSString*)fbSet
{
[_foobar release];
_foobar = [[NSString stringWithFormat:@"HELLO_%@", fbSet] retain];
}
このコードを配置すると、 foobar
プロパティが設定中に変更された場合、 ただし、コード行には値「BAZ!」が表示されたままになります。.
詳細:
が指摘したように、 新しいアカウント, 、NSLog コードが機能するのは、代入演算子 (=) を使用しているためです。この代入演算子は、C 言語 (Objective-C のベースになっています) で非常に特殊な動作をします。
C では、次のことができます。
x = y = z = 42;
そしてすべての変数、 x
, y
そして z
値 42 が保持されます。
コンパイラは、一時変数 (*) を使用してこの動作を処理します。基本的に、舞台裏で何が起こっているかは次のようになります。
tempVar = 42;
z = tempVar;
y = tempVar;
x = tempVar;
同様に、次のことも実行できます。
SomeFunction(x = 42);
このコード行は、値 42 を x にコピーし、呼び出します。 SomeFunction
引数は 42 です。舞台裏では次のようになります。
tempVar = 42;
x = tempVar;
SomeFunction(tempVar);
現在、Objective-C では、ログ行は次のように処理されます。
tempVar = @"BAZ!";
[mcInst setFooBar:tempVar];
NSLog(@"I set 'foobar' to '%@'", tempVar);
(*) 私が説明する「temporaray 変数」の使用法は概念を説明することを目的としており、特定のコンパイラーが内部で実際に行うことを実際に反映していない可能性があることに注意してください。この種の実装の詳細はコンパイラを作成するプログラマに依存しており、それぞれが異なることを実行する可能性があります。ただし、最終的な結果は同じです。
他のヒント
ゲッターをコールする必要はありません - それは、値が同じ行に右が割り当てられています。あなたが[mcInst setFoobar:@"BAZ!"], @"BAZ!"
に拡大すると考えることができます。
はCで、割り当ては、割り当てられた値を評価する式である
これは、Cの代入演算子の動作方法です。 ANSI C標準に記載されているように
"代入演算子は、によって指定されたオブジェクトに値を格納します 左オペランド。代入式は、左の値を持っています 譲渡後のオペランド... "
あなたの代入式はmcInst.foobar = @"BAZ!"
です。私には意味をなさないように思わ割り当てが代入式の値が代入(@"BAZ!"
)の後に左のオペランドであるC.と同じmcInst上で動作するメソッドを呼び出すことで動作しますので、この値が渡されてもいますNSLog関数ます。
これは、あなたがif (self = [super init])
のスタイルで初期化子を書くことを可能にする動作と同じです。
P.S。コンパイラはそれに値を割り当てるときに、プロパティにセッターを呼び出し、その後mcInst.foobar
の値を使用している場合、ゲッターを呼び出すことはありません理由を尋ねるために公正な質問です。私は単にゲッターだけでプロパティに割り当てられたため、ゲッターが呼ばれていない同じ値を返します仮定だと言うだろう。