wuj*_*jek 18 properties objective-c
有一个类看起来像这样(我为了简洁省略了导入):
Base.h:
@interface Base : NSObject
@property (strong, readonly) NSString *something;
- (id)initWithSomething:(NSString *)something;
@end
Run Code Online (Sandbox Code Playgroud)
Base.m:
@implementation Base
- (id)initWithSomething:(NSString *)something {
self = [super init];
if (self) _something = something;
return self;
}
@end
Run Code Online (Sandbox Code Playgroud)
如你所见,'something'属性是readonly.现在我想创建一个子类来覆盖该属性也是可写的:
Sub.h:
@interface Sub : Base
@property (strong) NSString *something;
@end
Run Code Online (Sandbox Code Playgroud)
Sub.m:
@implementation Sub
@end
Run Code Online (Sandbox Code Playgroud)
和代码:
main.c中:
int main(int argc, const char * argv[]) {
@autoreleasepool {
Sub *o = [Sub new];
o.something = @"foo";
NSLog(@"%@", o.something);
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
此代码导致:
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'
Run Code Online (Sandbox Code Playgroud)
这是为什么?为什么找不到setSelector?
当我在子类中执行此操作时:
Sub.m:
@implementation Sub
@synthesize something = _something;
@end
Run Code Online (Sandbox Code Playgroud)
一切正常.这是否意味着子类属性默认情况下不合成的,即使它被定义为@property在@interface?编译是否以某种方式'看到'从Base自动生成的getter并且不生成setter?为什么,我认为应该生成setter,因为它还不存在.我正在使用Xcode 4.6.2,该项目是一个Cli工具(类型基础),但在我的实际项目中也是如此,这是一个iPhone应用程序.
背景:我有一个重型对象(Base的实例),需要蓝牙连接到某些设备,我应该为某些功能创建一个视图控制器.为了便于测试,我不想连接到BT(实际上,我需要一个物理设备并在其上测试代码),我希望能够在模拟器中测试它.我想到的是我只是创建了一个子类(Sub)来存根一些方法/属性并使用它代替,当代码准备就绪时我只需删除子类的代码,用正确的代码替换它的实例,用设备测试,提交和推送.它实际上工作正常,除了@property上面的奇怪之处.
有人可以告诉我房地产压倒怎么回事?
Mar*_*n R 28
对于readonly属性,只合成一个getter方法,但没有setter方法.
在编译子类时,编译器不知道如何在基类中实现该属性(它可以是自定义getter而不是后备实例变量).所以它不能只在子类中创建一个setter方法.
如果你想从子类中获得对同一个实例变量的写访问权限,你必须@protected在基类中声明它(以便它可以在子类中访问),在子类中将该属性重新声明为read-write,并提供一个setter方法:
Base.h:
@interface Base : NSObject {
@protected
NSString *_something;
}
@property (strong, readonly) NSString *something;
- (id)initWithSomething:(NSString *)something;
@end
Run Code Online (Sandbox Code Playgroud)
Sub.h:
@interface Sub : Base
@property (strong, readwrite) NSString *something;
@end
Run Code Online (Sandbox Code Playgroud)
Sub.m:
@implementation Sub
-(void)setSomething:(NSString *)something
{
_something = something;
}
@end
Run Code Online (Sandbox Code Playgroud)
你的解决方案
@synthesize something = _something;
Run Code Online (Sandbox Code Playgroud)
使用子类中的单独实例变量 _something(_something与基类不同)在子类中生成getter和setter方法.
这也适用,你应该知道它self.something引用了基类和子类中的不同实例变量.为了使其更加明显,您可以在子类中使用不同的实例变量:
@synthesize something = _somethingElse;
Run Code Online (Sandbox Code Playgroud)
给定的答案工作得很好。这是另一种答案,显然 Apple更喜欢.
您可以定义私有扩展类的,一个Base+Protected.h文件,它需要被纳入Base.m和Sub.m。
然后,在这个新文件中,您将属性重新定义为readwrite.
@interface Base ()
@property (strong, readwrite) NSString *something;
@end
Run Code Online (Sandbox Code Playgroud)
这种替代方法允许您使用访问器self.something而不是 ivar _something。
注意:您仍然需要保留的定义something在你的Base.h原样。
| 归档时间: |
|
| 查看次数: |
15673 次 |
| 最近记录: |