8

如何防止特定类被子类化?我不知道final该语言中的此类功能(例如关键字)。然而,Apple 表示它已经为 AddressBookUI.framework 中的所有类(在 iOS 中)这样做了

出于教育目的,我怎样才能实现相同的功能,或者他们会如何做这样的事情?

来自iOS7 发行说明(需要登录)

在此处输入图像描述

4

4 回答 4

13

这是一种方法:allocWithZone:从“最终”类中覆盖(替换MyFinalClassName您的实际类名),如下所示:

+ (id)allocWithZone:(struct _NSZone *)zone
{
    if (self != [MyFinalClassName class]) {
        NSAssert(nil, @"Subclassing MyFinalClassName not allowed.");
        return nil;
    }

    return [super allocWithZone:zone];
}

这将防止一个不是成员的子类MyFinalClassNamealloc'ed (因此init也是 'ed ),因为NSObject'sallocWithZone:必须最终被调用,并且通过拒绝super从你的“最终”类调用,你将阻止这种情况。

于 2013-10-05T06:49:43.877 回答
9

由于 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

编译器将停止定义Barwith Cannot subclass a class with objc_subclassing_restricted 属性

于 2014-12-08T20:20:49.113 回答
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% 保证的,因为无论如何它都是运行时检查,但它应该足以阻止并警告人们他们不应该将其子类化。子类可能会跳过超类的初始化,但是实例将无法使用,因为它没有被超类完全初始化。

于 2013-10-05T07:49:23.533 回答
0

类似下面的内容将确保每次“不可能的子类”调用+alloc时,都会分配一个对象,该对象是 的实例FinalClass,而不是子类。这本质上就是 NSObject 的+alloc方法所做的,但这里我们指定一个显式的类来创建。这就是NSObject 分配实例的方式(在 Obj-C 2 中),但不能保证总是如此,因此您可能需要添加适当的-deallocwhich 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

注意:我不确定我自己是否会使用它——指定一个类不应该被子类化更多地是与程序员的设计合同,而不是编译或运行时的强制规则。

于 2013-10-05T10:03:25.467 回答