在Objective-C中覆盖@property声明 [英] Overriding @property declarations in Objective-C

查看:94
本文介绍了在Objective-C中覆盖@property声明的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I often find that I know that a certain property of a base class will always be a certain type in a subclass. For instance, in the example below, property obj will always be an NSString object in Derived. However, I need this property to be the more generic id type in class Base.

@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

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

Is this code correct? I am concerned that @synthesize appears twice. Is this creating two properties, or does the @synthesize declaration in Derived override the one in Base?

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

Changing @synthesize to @dynamic in Base makes more sense.

编辑:这需要iOS SDK 5.

This requires iOS SDK 5.

推荐答案

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

Subclasses can change types associated with methods. In general, a subclass may specialize a return type, and may make argument types more generic. There's actually a name for this but I can't remember what it is. Anyway, here's the rational:

如果我有课

@interface A
- (id)foo;
@end

和另一个班

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

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

And I have an instance B* b, I can cast it down to A* and still conform to the type signature of the method -[A foo], because any NSString* is also an id.

但是,我无法对此进行更广泛的概括.如果相反,我有

However, I cannot make this more generalized. If instead I have

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

@interface B : A
- (id)foo;
@end

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

And I have an instance B* b and I cast it down to A*, then the type of [(A*)b foo] is NSString * and yet the actual value may be any id, because that's the type I declared -[B foo] to be. This is a violation of the type system.

如果我有课

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

和另一个班级

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

我有一个实例B* b,并将其转换为A*,那么[(A*)b foo:obj]的任何有效参数也都符合-[B foo:]的类型,因为任何NSString *也是id

And I have an instance B* b and I cast it down to A*, then any valid argument to [(A*)b foo:obj] also conforms to the type of -[B foo:], because any NSString * is also an id.

但是,如果我有以下内容

However if I have the following

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

@interface B : A
- (void)foo:(NSString *)obj;
@end

我有一个实例B* b,并将其强制转换为A*,然后可以将任何id传递给[(A*)b foo:obj],但是基础类B仅期望NSString*.因此,我违反了类型系统.

And I have an instance B* b and I cast it down to A*, then I could pass any id to [(A*)b foo:obj], but the underlying class B only expects NSString*s. And thus I've violated the type system.

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

Here is the sticky point. When you declare the type of a property, you're declaring both the return type of the getter and the argument type of the setter. According to the above rules, this means you cannot change the type of a property, because in one of the two cases you'll be violating the type system.

以上是理论.实际上,我不知道GCC或Clang是否强制执行这些约束.他们可能会假设程序员最了解,并且不正确地泛化或专门化类型将无声地破坏背后的类型系统.您必须进行试验.但是,如果编译器确实是正确的,那么它将不允许泛化返回类型和特殊化参数.这意味着它将不允许更改属性的类型.

The above is the theory. In practice, I have no idea if GCC or Clang enforce these constraints. It's possible that they assume the programmer knows best, and improperly generalizing or specializing a type will silently break the type system behind your back. You'll have to experiment. But if the compiler is truly correct then it will disallow generalizing return types and specializing arguments. And that means it will disallow changing the type of a property.

即使编译器允许,您也可能不应该这样做.静默破坏类型系统是引入错误的好方法,并且是体系结构不佳的指示.

Even if the compiler allows it, you probably shouldn't do it. Silently breaking the type system is a great way to introduce bugs, and an indicator of poor architecture.

这篇关于在Objective-C中覆盖@property声明的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆