【问题标题】:Objective-C: Force a class to be a subclass of otherObjective-C:强制一个类成为其他类的子类
【发布时间】:2014-03-29 17:53:02
【问题描述】:

B 是 A 的子类。C 是 A 的子类。当我创建 c 时,我在 C 中的 .m 内执行 if((self = [NSKeyedUnarchiver unarchiveObjectWithFile:…])) { }

因此,尽管我将 C.h 中的超类设置为 B(这是我想要的),但当我从 unarchiveObjectWithFile: 创建 C 对象时,因为该对象是 A 的子类,我不能强迫它成为子类B.(很难解释抱歉)。

有什么办法吗???

换句话说:当我unarchiveObjectWithFile:… 一个属于A 类的对象,而我有另一个属于A 子类的B 类时,unarchiveObjectWithFile: 可以是B 的子类吗? (这是允许的,因为 B 是 a 的子类)

【问题讨论】:

    标签: ios objective-c nskeyedarchiver nskeyedunarchiver


    【解决方案1】:

    如果我理解正确:没有。

    如果您存档B 的实例,那么当您取消存档时,您将获得B 的实例,AC 的实例也是如此。

    然而,在非技术语言中,子类就是它的父类加上一些额外的部分。您不能 [*] 获取直接创建或通过取消归档创建的超类的实例,并将其变为其子类之一的实例 - “额外位”不存在。

    HTH

    [*] 在某人遇到之前:是的,这并非在所有情况下都绝对正确,但是您正在进入晦涩、高度专业化和危险的水域。不要去那里。

    附录

    似乎您可能属于更改对象类是安全的类别:您应该能够将实例的类更改为子类提供子类不添加实例变量或属性.为此,您可以使用Objective-C runtime functions:

    id obj = ... some instance of class A
    object_setClass(obj, [B class]); // where B is a subclass of A which adds no properties or variables
    

    您也可以使用解档类来设置类。

    不要随便这样做。考虑替代方案,但有时这是一个合适的解决方案。

    【讨论】:

    • @user588125 - 听起来您确实有一种可以安全地更改类的情况,如果是这样,请使用运行时函数进行操作。您还可以考虑使用可用于替换方法的类别(而不是覆盖它们)——这也是一个需要小心的领域。
    • 两个 cmets 1:object_setClass 在我的环境中不存在,我无法输入没有错误,我只是得到 object_getClassName(id obj) 但 _setClass 不存在。 2:这个解决方案不适合我。在这里,我粘贴了问题所在 pastebin.com/M1aGZ7S3 。我有一个使用 XCode Buildin 工具创建的 SKEmitterNode,所以当我解压缩它时,我得到一个 SKEmitterNode (A),但是我解压缩的所有 SKEmitterNode 都有一些属性和其他它们共享的东西,所以我创建了一个 Emitter:SKSpriteNode (B ) 来分享这个功能,最后我创建了 Smoke:Emitter (C) 并执行 [[C alloc] init]
    • @user588125 - 重新评论1:object_setClass是运行时的标准函数,你有#import <objc/objc-runtime.h>吗?
    • 现在我可以看到函数了。谢谢!无论如何问题仍然存在,但此时我正在考虑再次询问问题
    • @user588125 - 重新评论 2:附录似乎不适用于您的情况,并且您不能使用 object_setClass,因为您的子类添加了属性。
    【解决方案2】:

    取消存档者想要创建与之前存档相同类型的类,而这通常也是您想要的。

    您可以考虑使用setClass:forClassName: 更改将取消归档的类,但您迟早很有可能毁掉所有内容...


    基于粒子评论:

    另一种选择是采用超类实例并将其“包装”在您的子类实例中。因此,您可以归档和取消归档您的子类实例,它将包含超类实例。您的子类不直接响应您的任何方法都可以转发到超类实例。

    通过这种方式,您有 2 个对象,但您不会篡改任何东西,也不会依赖您不拥有的类的实现细节。

    【讨论】:

    • 好吧,我解释得更好:我用 XCode Build in 工具创建了一个粒子发射器,它不允许我更改它的类(我将放置它的子类而不是 SKEmitterNode(A) (B).) 然后,当我解压它时,我得到了一个 A 的实例,但我有一些功能可以添加到这些发射器中。
    • 有趣...所以你的子类只是添加/覆盖了一些方法?没有新的属性/实例变量?给setClass:forClassName: 一个尝试,但要对你的编码进行防御。不过,我将使用不同的选项更新我的答案...
    • 是的,只是添加了一些方法,反正我这里不知道怎么用setClass:forClassName:pastebin.com/9i4TpUAA
    • 您将创建 unarchiver,然后在它开始取消归档之前:[unarchiver setClass:[Emitter class] forClassName:NSStringFromClass([SKEmitterNode class])] --- 如果 SKEmitterNode 现在或将来的任何时候是类集群的一部分,您将遇到问题,因此不建议这样做!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-04
    • 2018-03-16
    • 1970-01-01
    • 2010-12-12
    • 1970-01-01
    相关资源
    最近更新 更多