覆盖Objective-C中的@property声明

tit*_*coy 25 objective-c

我经常发现我知道基类的某个属性永远是子类中的某个类型.例如,在下面的示例中,属性obj将始终是Derived中的NSString对象.但是,我需要此属性是类Base中更通用的id类型.

@interface Base
@property (strong, nonatomic) id obj;
@end

@implementation Base
//@synthesize obj = obj_;
@dynamic obj;
@end


@interface Derived : Base
@property (strong, nonatomic) NSString *obj;
@end

@implementation Derived
@synthesize obj = obj_;
@end
Run Code Online (Sandbox Code Playgroud)

这段代码是否正确?我担心@synthesize会出现两次.这是创建两个属性,还是Derived中的@synthesize声明覆盖Base中的一个?

编辑:在Base中将@synthesize更改为@dynamic更有意义.

编辑:这需要iOS SDK 5.

Lil*_*ard 49

子类可以更改与方法关联的类型.通常,子类可以专门化返回类型,并且可以使参数类型更通用.实际上有一个名字,但我不记得它是什么.无论如何,这是理性的:

返回类型

如果我有课

@interface A
- (id)foo;
@end
Run Code Online (Sandbox Code Playgroud)

和另一堂课

@interface B : A
- (NSString *)foo;
@end
Run Code Online (Sandbox Code Playgroud)

我有一个实例B* b,我可以将它转换为A*并仍然符合方法的类型签名-[A foo],因为任何NSString*也是一个id.

但是,我不能使这更加普遍.如果相反,我有

@interface A
- (NSString *)foo;
@end

@interface B : A
- (id)foo;
@end
Run Code Online (Sandbox Code Playgroud)

我有一个实例,然后B* b将其转换为A*,然后[(A*)b foo]是is 的类型,NSString *但实际值可能是任何id,因为这是我声明的类型-[B foo].这违反了类型系统.

参数

如果我有课

@interface A
- (void)foo:(NSString *)obj;
@end
Run Code Online (Sandbox Code Playgroud)

和另一堂课

@interface B : A
- (void)foo:(id)obj;
@end
Run Code Online (Sandbox Code Playgroud)

我有一个实例B* b,我把它归结为A*,然后任何有效的参数[(A*)b foo:obj]也符合类型-[B foo:],因为任何NSString *也是一个id.

但是,如果我有以下内容

@interface A
- (void)foo:(id)obj;
@end

@interface B : A
- (void)foo:(NSString *)obj;
@end
Run Code Online (Sandbox Code Playgroud)

我有一个实例B* b,我投它下来A*,然后我可以通过任何id[(A*)b foo:obj],但潜在的类B只希望NSString*秒.因此我违反了类型系统.

属性

这是一个棘手的问题.声明属性的类型时,您将声明getter的返回类型 setter的参数类型.根据上述规则,这意味着您无法更改属性的类型,因为在这两种情况之一中您将违反类型系统.


以上是理论.在实践中,我不知道GCC或Clang是否强制执行这些约束.他们可能认为程序员最了解,并且不正确地推广或专门化类型会默默地破坏你背后的类型系统.你必须要做实验.但是如果编译器确实是正确的,那么它将禁止泛化返回类型和专门化参数.这意味着它将禁止更改属性的类型.

即使编译器允许它,您也可能不应该这样做.默默地打破类型系统是引入错误的好方法,也是糟糕架构的一个指标.

  • 很棒的答案,但遗憾的是Clang没有强制执行规则. (2认同)
  • “实际上有一个名称,但我不记得它是什么”-> 逆变方法参数类型?https://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science) (2认同)
  • @DiegoFreniche 是的,方法参数是逆变的,方法返回类型是协变的。 (2认同)

Max*_*Max 1

你实际上不能这样做。对我来说,我收到一个错误

property 'obj' attempting to use ivar 'obj_' declared in super class of 'Derived'
Run Code Online (Sandbox Code Playgroud)

所以我认为这是显而易见的。即使你不使用@synthesize并自己定义函数,那么也只会调用派生版本(ObjC中没有函数重载或虚函数之类的东西)。

你必须回顾你的课程设计。