私の理解が正しければ、Objective-C では、プロパティはゲッターとセッターを使用して自動的に合成され、インスタンス変数はアンダースコア ( _ivar
) が先頭に付いたプロパティ名として宣言されます。
つまり、このコード:
メイン.m
#import <Foundation/Foundation.h>
#import "hello.h"
int main(int argc, char *argv[])
{
@autoreleasepool {
Hello *hello = [[Hello alloc] init];
NSLog(@"%@", hello.myString);
return 0;
}
}
こんにちは
#import <Foundation/Foundation.h>
@interface Hello : NSObject
@property (copy, nonatomic) NSString *myString;
@end
こんにちは。
#import "hello.h"
@implementation Hello
-(Hello *)init
{
if (self = [super init]) {
_myString = @"Hello";
}
return self;
}
-(NSString *)myString
{
return [NSString stringWithFormat:@"%@ %@", _myString, @"World"];
}
@end
次のようにコンパイルして実行できます:
bash-3.2$ clang -framework Foundation main.m hello.m -o hello
bash-3.2$ ./hello
2013-05-27 13:20:39.738 hello[23320:707] Hello World
ここで、myString プロパティを次のように readonly に変更します。
@property (readonly, copy, nonatomic) NSString *myString;
その後、コンパイルしようとするとエラーが発生します:
hello.m:11:9: error: unknown type name '_myString'; did you mean 'NSString'?
_myString = @"Hello";
^~~~~~~~~
NSString
つまり、_myString
定義されていません。コンパイラはインスタンス変数 _myString を使用してプロパティを合成しませんでしたか? 自分で合成したときに動作するかどうかを確認してみましょう。
hello.m の実装では:
@synthesize myString = _myString;
これで再び動作するようになりました:
bash-3.2$ clang -framework Foundation main.m hello.m -o hello
bash-3.2$ ./hello
2013-05-27 13:36:59.916 hello[24219:707] Hello World
そこで、私の質問は、プロパティで使用したときに、アンダースコア ivar で自動的に合成されないのはなぜかということですreadonly
。それとも、Objective-C の仕組みの理解がまったく間違っているのでしょうか。
何が起こっているのか、そしてなぜ起こっているのかを本当に理解したいので、説明的な回答をいただければ幸いです。
よろしくお願いします。
ベストアンサー1
プロパティとは自動的に合成されない実装する場合必要なすべてのアクセサメソッド(読み取り専用プロパティの場合は getter、読み取り/書き込みプロパティの場合は getter + setter)。
読み取り専用プロパティのgetter メソッドを実装しているため-(NSString *)myString
、自動合成されません。プロパティ値をバックアップするために getter にインスタンス変数が必要な場合は、合成ステートメント (実行したように) またはインスタンス変数を追加する必要があります。