首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >NSUUID可以通过继承来扩展吗?多么?

NSUUID可以通过继承来扩展吗?多么?
EN

Stack Overflow用户
提问于 2014-10-23 21:49:52
回答 2查看 270关注 0票数 1

最近(回顾一些代码),我偶然发现了一个奇怪的问题,导致我们的程序中出现了一个bug。

我们正在使用的API有以下实现(我将用Swift编写它,即使原始代码在Objective中)

代码语言:javascript
复制
internal class MyUUID: NSUUID { }

这是完全无用的,因为它总是返回一个空实例。

为了解释起见,我将把操场上的代码粘贴到这里。

例如:创建一个简单的NSUUID如下所示:

代码语言:javascript
复制
let a = NSUUID()
a.description //this creates a valid uuid

创建MyUUID时,应该是类似的

代码语言:javascript
复制
let b = MyUUID()
b.description //it returns an instance, but is completely empty.

但不起作用。

再检查一下,就会发现NSUUID初始化器创建了一个__NSConcreteUUID实例,而MyUUID不创建一个适当的UUID,不管我尝试做什么都不重要。

那么,我的问题是:是否有可能创建一个NSUUID的子实现?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-10-23 22:04:00

您可以使用class_setSuperclass在运行时更改MyUUID的超类。由于类型安全,这种方法在Swift中是非法的,但是您仍然可以在目标-C中这样做。

根据您的实际目标,您可能可以使用CFUUIDRef代替。

按照要求,下面是class_setSuperclass方法的一个示例。只需将其放入一个新的单一视图项目即可。

代码语言:javascript
复制
#import <objc/runtime.h>

@interface MyUUID : NSUUID

- (void) UUIDWithHello;

@end

@implementation MyUUID

- (void) UUIDWithHello {
    NSLog(@"Hello! %@", self.UUIDString);
}

@end

@interface ViewController ()


@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    // Make a UUID that you want to subclass
    NSUUID *uuid = [[NSUUID alloc] init];
    NSLog(@"Initial UUID: %@", uuid.UUIDString);

    // Ignore deprecation warnings, since class_setSuperclass is deprecated
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"

    // Change MyUUID to inherit from the NSUUID's hidden subclass instead of NSUUID
    class_setSuperclass([MyUUID class], [uuid class]);  // [uuid class] is __NSConcreteUUID

    // Turn deprecation warnings back on
#pragma GCC diagnostic pop

    // Make a new myUUID and print it
    MyUUID *myUuid = [[MyUUID alloc] init];
    [myUuid UUIDWithHello];
}

@end    

请注意,这有点危险。如果任何秘密子类NSUUID都有额外的实例变量,那么它将需要更多的内存,而[MyUUID alloc]不会请求这些内存。当某些东西请求这些实例变量时,这可能导致稍后的崩溃。

为了解决这个问题,您可以实例化MyUUID实例,如下所示:

代码语言:javascript
复制
NSLog(@"Initial UUID's class: %@", NSStringFromClass(uuid.class));
Class topSecretUUIDSubclass = uuid.class; // __NSConcreteUUID
MyUUID *myUuid2 = [[topSecretUUIDSubclass alloc] init];
[myUuid2 UUIDWithHello];
object_setClass(myUuid2, [MyUUID class]);

基本上,这将使myUuid2成为一个__NSConcreteUUID,然后将其更改为MyUUID。但是,只有当MyUUID不添加任何实例变量时,这才能起作用。

如果MyUUID确实需要添加它自己的实例变量,那么它将需要重写+alloc,以便使用class_createInstance()为这些实例变量提供额外的内存。

票数 2
EN

Stack Overflow用户

发布于 2014-10-23 22:19:42

你的证据会以经验的方式回答你自己的问题:这是不可能的。NSUUID似乎是一个类集群,而不是单个类,这有效地防止了子类化。

亚伦的另一个想法是:

实现一个具有NSUUID的对象,而不是那个对象。实现-forwardingTargetForSelector:并返回您的NSUUID实例。考虑覆盖-isKindOfClass:,但最好不要这样做,除非您必须这样做。然后,您应该能够将您的类作为一个NSUUID传递给任何期望它的人,而他们却不知道它们之间的区别。

考虑到解决方案取决于动态消息传递中内置的回退机制,我怀疑没有Swift等效;但是,如果您将类定义为Objective,那么它应该在Swift中同样可用。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26538056

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档