如何将allocWithZone指向:ARC下的子类(不是单例!)

时间:2014-08-05 18:18:34

标签: ios objective-c subclass objective-c-category

我已经看到了一些类似于这个问题的SO问题,但它们都涉及单身人士,并且答案都是(正确地)“不要那样做,而是使用dispatch_once()代替。”

在我的特定实例中,我没有制作单例,我需要超类的allocWithZone:来返回我的子类的实例。

我要做的是:我想对我不拥有的现有库进行扩展。而不是在类别中做一堆行为 - 如果我覆盖现有行为,甚至无法正常工作,因为没有定义调用哪些相同的签名方法 - 我希望它是那样的当有人包含我的(非常小的)类别时,然后拨打

LibObject *myObj = [[LibObject alloc] init];

他们回来了,好像他们打电话一样

LibObject *myObj = [[MyLibObjSubclass alloc] init];

其中LibrarySubclass是我正在创建的子类。特别是,作为LibObject的子类的所有库的对象,我希望它们是MyLibObjSubclass的子类。

我已经搞砸了混合和类别以及我能想到的其他一切,但我总是遇到两个问题之一:

  • [MyLibObjSubclass alloc]致电[LibObject alloc]致电[MyLibObjSubclass alloc]等,或
  • 的无限递归后,我最终崩溃了
  • 作为LibObject的子类的所有内容,而不是MyLibObjSubclass的子类及其新行为,它只是 a MyLibObjSubclass,没有任何其他行为。

对于第二个问题,举例来说,假设我试图将所有UIView - s覆盖为MyView - s,其中MyView是{UIView的子类1}}。问题在于,当我尝试分类时(作为UIView+MyShim的一部分),那么这一行:

UILabel *label = [[UILabel alloc] init];

而不是返回作为MyView的子类的UILabel - > UIView - > UIResponder - > NSObject,它只返回MyView,例如,它不包含text属性,因此所有UILabel - s都被破坏。

所以我的问题是:我该怎么办?

谢谢!

1 个答案:

答案 0 :(得分:3)

听起来你想要修改类层次结构:

CCResponder
 └─ CCNode
     ├─ CCControl
     └─ CCSprite

到此:

CCResponder
 └─ MyResponder
     └─ CCNode
         ├─ CCControl
         └─ CCSprite

由于不推荐class_setSuperclass,因此没有受支持的方法在运行时进行更改。

注意:是的,这正是我希望做的.~Ollie。)

您是否考虑过只修改Cocos2D源代码?短期来说,这应该是最简单的方法。如果您需要的是足够的,也许您可​​以将您的更改合并到上游。或者也许你可以添加上游接受的钩子,并使用这些钩子做你需要的。

如果您将代码保存在git中,那么我建议使用git-subtree扩展将Cocos2D源代码导入项目的存储库。这样可以很容易地跟踪您对Cocos2D的本地更改,并在您想要导入更新版本时重新应用它们。

如果这对你不起作用,我认为你应该把它搞砸,然后对你想要改变行为的方法进行调整。

如果您是一个贪婪的惩罚者,您可以在运行时根据需要创建每个CCResponder子类的新子类。你最终会得到这样的层次结构:

CCResponder
 └─ CCNode
     ├─ CCControl
     │   └─ hacked_CCControl
     └─ CCSprite
         └─ hacked_CCSprite

(我知道CCControl不是你可能直接实例化的东西,而是让我们假装。)

我认为这是可能的,但非常复杂。要做到这一点,请与{您自己的} +[CCResponder alloc]混合+[CCResponder allocHack]。你会实现这样的东西:

static Class createHackedClassForClass(Class originalClass) {
    NSString *name = [@"hacked_" stringByAppendingString:NSStringFromClass(originalClass)];
    Class hackedClass = objc_allocateClassPair(originalClass, name.UTF8String, 0);

    // Here add methods as necessary to hackedClass using class_addMethod.

    objc_registerClassPair(hackedClass);
    return hackedClass;
}

+ (void)allocHack {
    static NSMutableDictionary *hackedClassForClass = [NSMutableDictionary dictionary];
    Class hackedClass = hackedClassForClass[self];
    if (hackedClass == nil) {
        hackedClass = createHackedClassForClass(self);
        hackedClassForClass[self] = hackedClass;
    }
    return class_createInstance(hackedClass, 0);
}

我没试过这个,所以我不知道它是否有任何重大问题。它至少会使调试变得比仅修改Cocos2D源代码更难。