如何防止特定类被子类化?
我不知道该语言中的此类功能(例如final
关键字)。然而,Apple表示它已经为AddressBookUI.framework(在iOS中)的所有类完成了这项工作
出于教育目的,我如何实现相同的功能,或者他们将如何做到这一点?
来自iOS7 Release Notes(Requires login):
答案 0 :(得分:12)
以下是一种方法:在“最终”类中覆盖allocWithZone:
(用MyFinalClassName
代替您的实际类名),如下所示:
+ (id)allocWithZone:(struct _NSZone *)zone
{
if (self != [MyFinalClassName class]) {
NSAssert(nil, @"Subclassing MyFinalClassName not allowed.");
return nil;
}
return [super allocWithZone:zone];
}
这将阻止不属于MyFinalClassName
成员的子类被alloc
'编辑(因此也init
',因为NSObject
的最终必须调用allocWithZone:
,并且拒绝从“最终”类中调用super
,您将阻止此操作。
答案 1 :(得分:6)
作为Swift互操作的结果,有一种更简单的方法来防止Xcode 6中的子类化。为了防止Swift类在Objective-C中被子类化,objc_subclassing_restricted
被添加到{ProjectName}-Swift.h
文件中的所有类定义。
您可以在项目中使用它:
#if defined(__has_attribute) && __has_attribute(objc_subclassing_restricted)
# define FOO_FINAL __attribute__((objc_subclassing_restricted))
#else
# define FOO_FINAL
#endif
FOO_FINAL
@interface Foo : NSObject
@end
@interface Bar : Foo
@end
编译器将停止Bar
的定义,其中不能使用objc_subclassing_restricted属性
答案 2 :(得分:2)
这是可能的解决方案:
@interface FinalClass : NSObject
@end
@implementation FinalClass
- (id)init
{
if (self.class != [FinalClass class]) {
return nil;
}
self = [super init];
if (self) {
// instance initialization
}
return self;
}
@end
@interface InvalidSubclass : FinalClass
@end
@implementation InvalidSubclass
- (id)init
{
self = [super init];
if (self) {
}
return self;
}
@end
我不确定这是100%保证,因为无论如何它都是运行时检查,但它应该足以阻止并警告人们不应该将其子类化。子类可能会跳过超类的init,但实例将无法使用,因为它没有被超类完全初始化。
答案 3 :(得分:0)
以下内容将确保每次“不可能的子类”调用+alloc
时,将分配一个对象,该对象是FinalClass
的实例,而不是子类。这本质上是NSObject的+alloc
方法所做的,但在这里我们指定一个要创建的显式类。这是NSObject allocates instances (in Obj-C 2)的方式,但无法保证始终如此,因此您可能需要添加一个调用-dealloc
的相应object_dispose
。如果您尝试实例化子类,此方法还意味着您不会获得nil对象 - 您确实获得了FinalClass
的实例。
@interface FinalClass: NSObject
//...
+ (id)alloc; // Optional
@end
// ...
#import <objc/runtime.h>
@implementation FinalClass
+ (id)alloc {
if (![self isMemberOfClass:[FinalClass class]]) {
// Emit warning about invalid subclass being ignored.
}
self = class_createInstance([FinalClass class], 0);
if (self == nil) {
// Error handling
}
return self;
}
@end
@interface InvalidSubclass : FinalClass
// Anything not in FinalClass will not work as +alloc will
// create a FinalClass instance.
@end
注意:我不确定自己是否会使用它 - 指定不应将类子类化为与程序员签订设计合同的本质,而不是编译或运行时强制规则。