Accessing a method in a super class when it's not exposed - objective-c

In a subclass, I'm overriding a method that is not exposed in the super class. I know that I have the correct signature as it is successfully overriding the superclass implementation. However, as part of the the new implementation, I need to call the superclass's implementation from the subclass's implementation.
Because it's not exposed I have to invoke the method via a call to performSelector:
SEL superClassSelector = NSSelectorFromString(#"methodToInvoke");
[super performSelector:superClassSelector];
However, in my application this results in an infinite recursive loop where the subclass's implementation is invoked every time I try to invoke the superclass's implementation.
Any thoughts?
I realize this is an atypical situation but unfortunately there's no way to get around what I'm trying to do.

The way I've dealt with this is to re-declare your super class' interface in your subclass implementation file with the method you want to call from the subclass
#interface MySuperclass()
- (void)superMethodIWantToCall;
#end
#implementation MySubclass
- (void)whateverFunction {
//now call super method here
[super superMethodIWantToCall];
}
#end
I'm not sure if this is the best way to do things but it is simple and works for me!

This doesn't work because you're only sending performSelector:, not the selector you pass to that, to the superclass. performSelector: still looks up the method in the current class's method list. Thus, you end up with the same subclass implementation.
The simplest way to do this may be to just write in your own call to objc_msgSendSuper():
// Top level (this struct isn't exposed in the runtime header for some reason)
struct objc_super
{
id __unsafe_unretained reciever;
Class __unsafe_unretained superklass;
};
// In the subclass's method
struct objc_super sup = {self, [self superclass]};
objc_msgSendSuper(&sup, _cmd, other, args, go, here);
This can cause problems in the general case, as Rob Napier has pointed out below. I suggested this based on the assumption that the method has no return value.

One way to go is to create a category of your class in a separate file with the method you are trying to expose
#interface MyClass (ProtectedMethods)
- (void)myMethod;
#end
and on the .m
#implementation MyClass (ProtectedMethods)
- (void)myMethod {
}
#end
Then, import this category from your .m files, and you're good to go. It's not the prettiest thing, but it'll do the trick

Related

Can subclass override non-public methods

I have two classes: BatchDownloader, SpeechDownlader
BatchDownloader is the base class, and SpeechDownloader inherited it.
In BatchDownloader, whenever one file was downloaded, -(void)downloadComplete:task will be called.
But in SpeechDownloader, I also want to post a notification in downloadComplete:task.
Can I just write the method with the same name in SpeechDownloader's implementation ? or there is a better way ?
Thanks.
p.s. I don't want to make -(void)downloadComplete:task public, because it should only be called by itself.
If you implement a method in a subclass that has the same name as a private method in a superclass, your subclass method will be called on instances of your subclass.
i.e., if you implement a method in your superclass like this, without declaring it anywhere:
#implementation classA
- (void)doSomething {
NSLog("a");
}
Then, in your subclass implementation, implement a method with the same name:
#implementation subclassOfA
- (void)doSomething {
NSLog("b");
}
When you call doSomething on an instance of your subclass, the subclass implementation will be called instead of the superclass implementation, so the code in this example will result in "b" being printed to the console.
However, if you also want to access the superclass implementation of the method, you can use:
- (void)doSomething {
[super doSomething];
NSLog("b");
}
This will also call the superclass implementation. If you get a compile error (due to the method being private and super not appearing to implement it), you can use [super performSelector:#selector(doSomething)] instead to do exactly the same thing.
This happens because of the way the Objective-C runtime looks up method calls. Since these methods have exactly the same method signature (same name, return type and arguments [none]), they are considered equal, and the runtime always checks the class of the object before looking in superclasses, so it will find the subclass method implementation first.
Also, this means you can do this:
classA *test = [subclassOfA new];
[test doSomething];
And, surprise surprise, the console will print "b" (Or "a b" if you called the super implementation too).
If you implement the method with the same method signature it will be called faith your implementation, public or not.

How to avoid subclass inadvertently overriding superclass private method

I'm writing a library, which will potentially be used by people that aren't me.
Let's say I write a class:
InterestingClass.h
#interface InterestingClass: NSObject
- (id)initWithIdentifier:(NSString *)Identifier;
#end
InterestingClass.m
#interface InterestingClass()
- (void)interestingMethod;
#end
#implementation InterestingClass
- (id)initWithIdentifier:(NSString *)Identifier {
self = [super init];
if (self) {
[self interestingMethod];
}
return self;
}
- (void)interestingMethod {
//do some interesting stuff
}
#end
What if somebody is using the library later down the line and decides to create a subclass of InterestingClass?:
InterestingSubClass.h
#interface InterestingSubClass: InterestingClass
#end
InterestingSubClass.m
#interface InterestingSubClass()
- (void)interestingMethod;
#end
#implementation InterestingSubClass
- (void)interestingMethod {
//do some equally interesting, but completely unrelated stuff
}
#end
The future library user can see from the public interface that initWithIdentifier is a method of the superclass. If they override this method, they'll probably assume (correctly) that the superclass method should be called in the subclass implementation.
However, what if they define a method (in the subclass private interface) which inadvertently has the same name as an unrelated method in the superclass 'private' interface? Without them reading the superclass private interface, they won't know that instead of just creating a new method, they've also overridden something in the superclass. The subclass implementation may end up getting called unexpectedly, and the work that the superclass is expecting to be done when calling the method will not get done.
All of the SO questions I've read seem to suggest that this is just the way that ObjC works and that there isn't a way of getting around it. Is this the case, or can I do something to protect my 'private' methods from being overridden?
Alternatively, is there any way to scope the calling of methods from my superclass so I can be sure that the superclass implementation will be called instead of a subclass implementation?
AFAIK, the best you can hope for is declaring that overrides must call super. You can do that by defining the method in the superclass as:
- (void)interestingMethod NS_REQUIRES_SUPER;
This will compile-time flag any overrides that don't call super.
For framework code a simple way to deal with this is to just give all of your private methods a private prefix.
You'll often notice in stack traces that the Apple frameworks call private methods often starting with an under bar _.
This would only really be a real concern if you are indeed providing a framework for external use where people can not see your source.
NB
Don't start your methods with an under bar prefix as this convention is already reserved

Exposing/Synthesizing iVar properties in Objective c

I have a class that essentially acts as a light weight wrapper class around another class. It holds that other class as an iVar. I want to be able to expose certain properties (quite a few actually) of the iVar, but to do so I have to write out each property accessor like so:
- (void) setProperty:(Class *)value{
_iVar.property = value;
}
- (Class *) property{
return _iVar.property;
}
Of course, I have to do this for every single property, which is a pain (there are about 30 of them). I would love to be able to synthesize this but I haven't been able to figure out how.
Is it possible to synthesize?
Also, I can't subclass....well, I might be able to but it's really not recommended. The iVar class is really quite heavy (it implements CoreText). I'd rather write out the methods by hand.
Ok, so here's the solution I found...ended up being pretty simple once you knew what to do. First overwrite '- (id) forwardingTargetForSelector:(SEL)aSelector' and return the iVar:
- (id) forwardingTargetForSelector:(SEL)aSelector{
return iVar;
}
When the runtime is looking for a method and cannot find one, it will call this method to see if there is another object to forward the message to. Note that this method normally returns nil and if you return nil here, your program will crash (which is the appropriate behavior).
The second part of the problem is to shush the compiler errors/warnings you'll get when you try to send a message that's not declared. This is easily done by declaring a category you don't implement.
#interface Class (iVarClassMethods)
#propoperty (strong) Class *property1;
......more properties
#end
As long as you don't put in an implementation anywhere, aka #implementation Class (category), the compiler won't complain (it'll assume that the implementation is somewhere....).
Now the only drawback I see is if you change any of the properties in the interface of the iVar Class, you need to make sure you update all other classes that use the method described above, otherwise you'll crash when another class tries to send what is now the wrong method (and the compiler won't warn you beforehand). However, this can be gotten around. You can declare protocols in a category. So instead you create a separate protocol for the iVar class and move the methods/properties you wish out of the iVar class into the protocol.
#protocol iVarClassProtocol
#propoperty (strong) Class *property1;
......more properties
#end
Add that protocol to the iVar subclass so it has those methods declared through the protocol now.
#interface iVarClass <iVarClassProtocol>
....other methods/properties you don't need forwarded
#end
Finally, simply add the protocol to the category. So instead of the aforementioned category with explicit declarations you'll have:
#interface Class (iVarClassMethods) <iVarClassProtocol>
#end
Now, if you need to change any of the to-be-fowarded properties/methods, you change them in the protocol. The compiler will then warn you when you try to send the wrong method to the forwarding class.
I think you can forward the messages to the ivar:
- (void) forwardInvocation: (NSInvocation*) invocation
{
[invocation invokeWithTarget:ivar];
}
- (NSMethodSignature*) methodSignatureForSelector: (SEL) selector
{
NSMethodSignature *our = [super methodSignatureForSelector:selector];
NSMethodSignature *ivars = [ivar methodSignatureForSelector:selector];
return our ? our : ivars;
}
Then you have to hide or fake the type of your object, for example by casting to id, otherwise the compiler will complain that your class does not implement those methods.
Of course it would be best if you could come up with some better design that would do without such tricks.

Overloaded method in obj-c category: how to pass it to original class?

As I know, in my overloaded method (in category) I may call [super method] to pass it to original class.
In my case I don't have header file of class, so I write:
#interface OriginalClass : NSObject
#end
#interface OriginalClass (overloadMethod)
-(void) method;
#end
#implementation OriginalClass (overloadMethod)
-(void) method
{
// some my code
[super method]; // here is warning that "NSObject may not respond to '-method'
}
#end
So is it possible to pass method to OriginalClass correctly without having its header file? Maybe it would be better to look at method_setImplementation?
You're adding a category, not a subclass. When adding a category, think of it as tacking your own methods on to the existing class. Instead of sending messages to super (which in this case is NSObject), just send them to self. Imagine you're in the implementation of the class that you're adding a category to.
I'm not sure if you think you're subclassing or if you're trying to swizzle...
If i remember correctly, the intro to ObjC programming in the docs mentions that when you override a method with a category, you can no longer access the original method.
Your question is pretty much identical to the one here: How do I call the original function from the overloaded function in a category?
Note the quote from the docs in the first answer

Override a method via ObjC Category and call the default implementation?

When using categories, you can override implementation methods with your own like so:
// Base Class
#interface ClassA : NSObject
- (NSString *) myMethod;
#end
#implementation ClassA
- (NSString*) myMethod { return #"A"; }
#end
//Category
#interface ClassA (CategoryB)
- (NSString *) myMethod;
#end
#implementation ClassA (CategoryB)
- (NSString*) myMethod { return #"B"; }
#end
Calling the method "myMethod" after including the category nets the result "B".
What is the easiest way for the Category implementation of myMethod to call the original Class A myMethod? As near as I can figure out, you'd have to use the low level calls to get the original method hook for Class A and call that, but it seemed like there would be a syntactically easier way to do this.
If you want a hackish way to do this that involves mucking with the objective-c runtime you can always use method swizzling (insert standard disclaimers here.) It will allow you to store the different methods as arbitrariliy named selectors, then swap them in at runtime as you need them.
From comp.lang.objective-C FAQ listing: "What if multiple categories implement the same method? Then the fabric of the Universe as we know it ceases to exist. Actually, that's not quite true, but certainly some problems will be caused. When a category implements a method which has already appeared in a class (whether through another category, or the class' primary #implementation), that category's definition overwrites the definition which was previously present. The original definition can no longer be reached by the Objective-C code. Note that if two categories overwrite the same method then whichever was loaded last "wins", which may not be possible to predict before the code is launched."
From developer.apple.com: "When a category overrides an inherited method, the method in the category can, as usual, invoke the inherited implementation via a message to super. However, if a category overrides a method that already existed in the category's class, there is no way to invoke the original implementation"
Check out my article about a solution found on the Mac Developer Library:
http://codeshaker.blogspot.com/2012/01/calling-original-overridden-method-from.html
Basically, it's the same as the above Method Swizzling with a brief example:
#import <objc/runtime.h>
#implementation Test (Logging)
- (NSUInteger)logLength {
NSUInteger length = [self logLength];
NSLog(#"Logging: %d", length);
return length;
}
+ (void)load {
method_exchangeImplementations(class_getInstanceMethod(self, #selector(length)), class_getInstanceMethod(self, #selector(logLength)));
}
#end
With the swizzling "helper" methods included in ConciseKit, you actually call the default implementation… weirdly enough.. by calling your SWIZZLED implementation..
You set it up in + (void) load, calling + (BOOL)swizzleMethod:(SEL)originalSelector with:(SEL)anotherSelector in:(Class)klass;, i.e.
[$ swizzleMethod:#selector(oldTired:)
with:#selector(swizzledHotness:) in:self.class];
and then in the swizzled method.. let's suppose it returns -(id).. you can do your mischief, or whatever reason you are swizzling in the first place… and then, instead of returning an object, or self, or whatnot..
return [self swizzledHotness:yourSwizzledMethodsArgument];
As explained here…
In this method, it looks like we're calling the same method again, causing and endless recursion. But by the time this line is reached the two method have been swapped. So when we call swizzled_synchronize we're actually calling the original method.
It feels and looks odd, but.. it works. This enables you to add endless embellishments to existing methods, and still "call super" (actually self) and reap the benefits of the original method's handiwork… even without access to the original source.