如何防止特定类被子类化?我不知道final
该语言中的此类功能(例如关键字)。然而,Apple 表示它已经为 AddressBookUI.framework 中的所有类(在 iOS 中)这样做了
出于教育目的,我怎样才能实现相同的功能,或者他们会如何做这样的事情?
如何防止特定类被子类化?我不知道final
该语言中的此类功能(例如关键字)。然而,Apple 表示它已经为 AddressBookUI.framework 中的所有类(在 iOS 中)这样做了
出于教育目的,我怎样才能实现相同的功能,或者他们会如何做这样的事情?
这是一种方法: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
'ed (因此init
也是 'ed ),因为NSObject
'sallocWithZone:
必须最终被调用,并且通过拒绝super
从你的“最终”类调用,你将阻止这种情况。
由于 Swift 互操作,有一种更简单的方法可以防止 Xcode 6 中的子类化。为了防止 Swift 类在 Objective-C 中被子类化,文件objc_subclassing_restricted
中的所有类定义中都添加了Swift 类{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
with Cannot subclass a class with objc_subclassing_restricted 属性
这是可能的解决方案:
@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% 保证的,因为无论如何它都是运行时检查,但它应该足以阻止并警告人们他们不应该将其子类化。子类可能会跳过超类的初始化,但是实例将无法使用,因为它没有被超类完全初始化。
类似下面的内容将确保每次“不可能的子类”调用+alloc
时,都会分配一个对象,该对象是 的实例FinalClass
,而不是子类。这本质上就是 NSObject 的+alloc
方法所做的,但这里我们指定一个显式的类来创建。这就是NSObject 分配实例的方式(在 Obj-C 2 中),但不能保证总是如此,因此您可能需要添加适当的-dealloc
which calls 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
注意:我不确定我自己是否会使用它——指定一个类不应该被子类化更多地是与程序员的设计合同,而不是编译或运行时的强制规则。