0

I have a category on NSObject that defines a method with code like:

- (NSMutableDictionary *)myMethod
{
    NSMutableDictionary *myDict;
    if ([self isMemberOfClass:[NSObject class]]) {
        myDict = [NSMutableDictionary dictionary];        
    }
    else {
        myDict = [super myMethod];        
    }
    // DO STUFF HERE WITH myDict ...
    return myDict;
}    

It fails with NSObject cannot use super because it is a root class.

I can fix this by making it a base class rather than a category and having all my subclasses inherit from that instead of from NSObject, but that seems a bit lame. [Actually, this is wrong. The compiler won't let me call super from the base class implementation, either -- but see gabriel_101's workaround, below.] Is there any way around this?

Phil Mitchell
  • 699
  • 8
  • 25
  • Are you trying to override a method using a category? That is not their intended use. – CrimsonChris Aug 24 '14 at 22:38
  • possible duplicate of [Overriding methods using categories in Objective-C](http://stackoverflow.com/questions/5272451/overriding-methods-using-categories-in-objective-c) – CrimsonChris Aug 24 '14 at 22:39
  • I'm not overriding an existing method. I'm writing a serializer and need to walk up the inheritance chain because class_copyPropertyList does not pick up superclass properties. – Phil Mitchell Aug 24 '14 at 22:45
  • The reason to call super (conditionally) in the base class is because most subclasses will not need to override this. – Phil Mitchell Aug 24 '14 at 22:48

3 Answers3

1

I would suggest doing something like this:

NSMutableDictionary *myDict = [NSMutableDictionary dictionary];
Class currentClass = [self class];
while (currentClass != [NSObject class])
{
    // Add stuff to myDict using currentClass
    currentClass = [currentClass superClass];
}
hypercrypt
  • 15,389
  • 6
  • 48
  • 59
1

Sending a message to super is just a way to send that message to self but telling the runtime to start the search for the implementation in a different place. It makes no sense in a category that adds a new method. There's one and only one implementation of that method. So, the search can only have one of two results: it finds that one implementation or it finds nothing. Since you're already running the one implementation, the best an adjusted search could do is find nothing.

You have also left out whatever DO STUFF HERE would be. From what you've said in comments, I suspect it involved a misguided use of [self class]. [self class] will always have the same result for a given object. No amount of messaging to super will cause that to somehow return a superclass.

If you want to call class_copyPropertyList() with the chain of classes, then you must do something similar to what hypercrypt has suggested: iterate over the class chain yourself.

Ken Thomases
  • 88,520
  • 7
  • 116
  • 154
  • DO STUFF HERE does not involve [self class], it involves runtime introspection of the current instance's properties. Since that introspection only picks up self's properties, not super's, the method needs to call super and walk up the chain, gathering properties from all of self's ancestors. – Phil Mitchell Aug 25 '14 at 00:28
  • 1
    `self` and `super` are the same object (to the extent that `super` is an object at all). There's no chance that calling the method on `super` would produce different results from the runtime functions. – Ken Thomases Aug 25 '14 at 00:29
0

In one of your comments you are saying that you are implementing a serialiser, hence it will be a good idea to look at NSCoding and NSKeyed​Archiver. You can find an example of how to use these here.

However if the above is not suitable for your problem I will suggest the following.

As NSObject is the root class, it does not have any state to save. Hence you could implement an empty myMethod in your category to NSObject, and you could override it in subclasses which need to store state. In these subclasses it will be ok to call [super myMethod] since it is declared in your NSObject category.

gabriel_101
  • 773
  • 3
  • 19
  • But then there's no benefit of making it a category on NSObject -- no code reuse across the different classes that need the serialization code. – Phil Mitchell Aug 24 '14 at 23:13
  • 1
    Typically code reuse is achieved by putting the reusable code in a base class. Hence if you have some state which is common to two classes you will make a MyBase class where you have your common state and the serialisation code for it, and will create subclasses A and B which will call the serialisation code from MyBase using super during their serialisation. The category on NSObject was intended so the MyBase could also call super. – gabriel_101 Aug 24 '14 at 23:31
  • Got it, thanks for the explanation. I am editing original question to reflect the fact that it won't work to call super in base class implementation, either -- without this. – Phil Mitchell Aug 24 '14 at 23:36