次のようなクラスがあります (簡潔にするためにインポートを省略しています)。
Base.h:
@interface Base : NSObject
@property (strong, readonly) NSString *something;
- (id)initWithSomething:(NSString *)something;
@end
Base.m:
@implementation Base
- (id)initWithSomething:(NSString *)something {
self = [super init];
if (self) _something = something;
return self;
}
@end
ご覧のとおり、「something」プロパティは読み取り専用です。ここで、そのプロパティをオーバーライドして書き込み可能にするサブクラスを作成したいと思います。
サブ h:
@interface Sub : Base
@property (strong) NSString *something;
@end
サブメートル:
@implementation Sub
@end
そしてコード:
main.c:
int main(int argc, const char * argv[]) {
@autoreleasepool {
Sub *o = [Sub new];
o.something = @"foo";
NSLog(@"%@", o.something);
}
return 0;
}
このコードの結果は次のとおりです。
2013-09-07 13:58:36.970 ClilTest[3094:303] *** Terminating app due to uncaught
exception 'NSInvalidArgumentException', reason: '-[Sub setSomething:]: unrecognized
selector sent to instance 0x100109ff0'
何故ですか?setSelector が見つからないのはなぜですか?
代わりにサブクラスでこれを行うと:
サブメートル:
@implementation Sub
@synthesize something = _something;
@end
それはすべて動作します。@property
これは、サブクラスのプロパティが のように定義されていても、デフォルトでは合成されないということ@interface
ですか? コンパイルは、Base から自動的に生成されたゲッターを何らかの形で「認識」し、セッターを生成しませんか? なぜ、セッターはまだ存在しないので生成する必要があると思います。私は Xcode 4.6.2 を使用しており、プロジェクトは Cli ツール (タイプ Foundation) ですが、iPhone アプリである実際のプロジェクトでも同じことが起こります。
背景: 一部の機器への Bluetooth 接続を必要とする重いオブジェクト (Base のインスタンス) があり、一部の機能のためにビュー コントローラーを作成することになっています。テストを簡単にするために、BT に接続したくありません (実際には、物理デバイスが必要であり、その上でコードをテストする必要があります)。シミュレーターでテストできるようにしたいと考えています。私が思いついたのは、いくつかのメソッド/プロパティをスタブ化して代わりに使用するサブクラス (Sub) を作成するだけで、コードの準備ができたら、サブクラスのコードを削除し、そのインスタンスを正しいものに置き換えるだけです。デバイスでテストし、コミットしてプッシュします。上記の奇妙なことを除いて、実際には正常に動作し@property
ます。
プロパティのオーバーライドで何が起こっているのか誰か教えてもらえますか?