I'm developing an app that needs to perform some swizzling.
I'm swizzling a method -(void)m1:(CMAcceleration)a; with another one that I provide.
-(void)newM(id self, SEL _cmd, ...){
va_list args;
va_start(args, _cmd);
//...
NSInteger returnValue=((NSInteger(*)(id,SEL,...))origImp)(self,_cmd,args);
va_end(args);
}
To swizzle it I use:
origImp=method_setImplementation(method, newImp);
I then call it normally like [ClassInstance m1:a];
The thing is, args seems to be filled with garbage when I expected a structure like {name=type...} as described in here.
I need to pass the arguments to the original implementation after doing some operation like NSLog.
Searching the Internet it seems this is a Simulator problem related but I'm not sure and I have no access to a device to confirm this.
Am I doing something wrong or is there a way to fix this?
You are doing it very wrong.
The method signature should match i.e. -(void)newM:(CMAcceleration)a;
and
Method method = class_getInstanceMethod([SomeClass class],#selector(newM:));
IMP newImp = method_getImplementation(method);
origImp=method_setImplementation(method, newImp);
A different way is make C function
void newM(id self, SEL _cmd, CMAcceleration a) {
}
origImp=method_setImplementation(method, (IMP)newM);
Related
I have a class set up that ideally will read the methods of any class passed in and then map all of them to on single selector at runtime before forwarding them off to their original selector.
This does work right now, but I can only do it for one method at a time. The issue seems to be that once I swizzle the first method, my IMP to catch and forward the method has now been swapped with that other methods IMP. Any further attempts at this screw up because they use newly swapped IMP to replace the others.
1)So I have MethodA, MethodB, and CustomCatchAllMethod.
2)I swap MethodA with CustomCatchAllMEthod. MethodA->CustomCatchAllMethod, CustomCatchAllMethod->MethodA
3)Now I try to swap to MethodB with CustomCatchAllMethod as well, but since CustomCatchAllMethod now = MethodA, MethodB becomes MethodA and MethodA->MethodB.
So how do I get/copy a new instance of my IMP for each new selector I want to intercept?
Here's a rough mockup of the above flow:
void swizzle(Class classImCopying, SEL orig){
SEL new = #selector(catchAll:);
Method origMethod = class_getInstanceMethod(classImCopying, orig);
Method newMethod = class_getInstanceMethod(catchAllClass,new);
method_exchangeImplementations(origMethod, newMethod);
}
//In some method elsewhere
//I want this to make both methodA and methodB point to catchAll:
swizzle(someClass, #selector(methodA:));
swizzle(someClass, #selector(methodB:));
That common method-swizzling pattern only works when you want to intercept one method with one other. In your case you are basically moving the implementation for catchAll: around instead of inserting it everywhere.
To properly to this you'd have to use:
IMP imp = method_getImplementation(newMethod);
method_setImplementation(origMethod, imp);
This leaves you with one problem though: how to forward to the original implementation?
That is what the original pattern used exchangeImplementations for.
In your case you could:
keep a table of the original IMPs around or
rename the original methods with some common prefix, so you can build a call to them from catchAll:
Note that you can only handle methods of the same arity when you want to forward everything through the same method.
You can capture original IMP with block, get block's IMP and set it as implementation of method.
Method method = class_getInstanceMethod(class, setterSelector);
SEL selector = method_getName(method);
IMP originalImp = method_getImplementation(method);
id(^block)(id self, id arg) = ^id(id self, id arg) {
return ((id(*)(id, SEL, id))originalImp)(self, selector, arg);
};
IMP newImp = imp_implementationWithBlock(block);
method_setImplementation(method, newImp);
In the book The Pragmatic Programmer, the authors suggest that all method inputs should be validated. This allows problems with a method to be caught early and their sources traced easily.
In my Mac application, I accomplished this by creating an Assert class. This class has several class methods. These methods determine if some precondition is met, and if it is not, then an exception is thrown. A typical assertion might looks something like this:
-(void) setWidth: (int) theWidth {
[Assert integer: width isGreaterThanInteger: 0];
width = theWidth;
}
This works really well, and significantly reduced the amount of time I've spend bug hunting. However, I've noticed lately some of the assertion methods are very useful as predicates. For example, my integer:isGreaterThanInteger:andLessThanInteger: and my stringIsNotEmpty: methods are equally useful. To this end, I created a second class Predicate, which I filled with several of my more useful predicate methods. So I took the logic from the assert methods, and moved it into Predicate, and then rewrote my Assert methods like the following:
if ![Predicate predicateMethod]
throw exception
This has turned into a maintenance nightmare. If I change the name of a method name in Predicate, I must also change it in Assert to stay consistent. If I update the documentation of an Assert method, then I must do the same to a Predicate method.
Ideally, I would like the reconstruct the Assert class so that when any method is called on it, it intercepts the selector. The Predicate class can then be checked to see if it responds to the selector, and if it does, the method is called on Predicatewith the same arguments that were passed into the Assert method. If the Predicate method returns false, then an exception is thrown.
Is there a way to do this in Objective-C?
Thanks.
You could use -forwardingTargetForSelector: to simply forward the method to another object, but if you want advanced behavior (like checking the return value to see if it's false), you may need to use -forwardInvocation:. (However, note that the documentation says this is "much more expensive" than the former option.)
If you're using pure Objective-C, you should see the "Forwarding" discussion here. It basically describes how to do exactly what you want, including example code.
If you're using Cocoa then you might have to use forwardInvocation: instead.
I ended up overriding resolveClassMethod:. While overriding forwardInvocation might have worked (I would have had to figure out some way to override it for the class object), resolveClassMethod: seems like it's the easier and more efficient method. Here's what my final implementation ended up looking like:
#import "Assert.h"
#import "Predicate.h"
#include <objc/objc-runtime.h>
void handlePredicateSelector(id self, SEL _cmd, ...);
#implementation Assert
+(void) failWithMessage: (NSString *) message
{
NSLog(#"%#", message);
[NSException raise:#"ASSERTION FAILURE" format:message];
}
+(void) fail
{
[Assert failWithMessage:#"An unconditional failure has been detected."];
}
+(BOOL) resolveClassMethod: (SEL) selector
{
if ([(id) [Predicate class] respondsToSelector:selector])
{
/*
The meta class fix was taken from here: http://iphonedevelopment.blogspot.com/2008/08/dynamically-adding-class-objects.html
*/
//get the method properties from the Predicate class
Class predicateMetaClass = objc_getMetaClass([[Predicate className] UTF8String]);
Method predicateMethod = class_getClassMethod(predicateMetaClass, selector);
const char *encoding = method_getTypeEncoding(predicateMethod);
Class selfMetaClass = objc_getMetaClass([[self className] UTF8String]);
class_addMethod(selfMetaClass, selector, (IMP) handlePredicateSelector, "B#:?");
return YES;
}
return [super resolveClassMethod:selector];
}
#end
void handlePredicateSelector(id self, SEL _cmd, ...)
{
//get the number of arguments minus the self and _cmd arguments
NSMethodSignature *predicateMethodSignature = [(id) [Predicate class] methodSignatureForSelector:_cmd];
NSUInteger numberOfArguments = [predicateMethodSignature numberOfArguments] - 2;
NSInvocation *predicateInvocation = [NSInvocation invocationWithMethodSignature:predicateMethodSignature];
[predicateInvocation setTarget:[Predicate class]];
[predicateInvocation setSelector:_cmd];
va_list ap;
va_start(ap, _cmd);
for (int i = 0; i < numberOfArguments; i++)
{
void *arg = va_arg(ap, void *);
[predicateInvocation setArgument:&arg atIndex:i+2];
}
va_end(ap);
BOOL returnValue;
[predicateInvocation invoke];
[predicateInvocation getReturnValue:&returnValue];
//determine if the assertion is true
if (!returnValue)
{
[Assert failWithMessage:[NSString stringWithFormat: #"The following assertion failed: %#", NSStringFromSelector(_cmd)]];
}
}
The only thing I couldn't really figure out was how to get the type encoding from the method signature. It didn't seem to affect the output of the methods, but I would like to fix it if I can.
Objective-C keeps all its methods in a huge hashtable - so shouldn't it possible to patch this table and replace an existing method with my own patched method (which then calls the original)?
I need a way to hook up the NSWindow KeyUp method in a window which i can't subclass cause it's already created.
I need some code or at least some keywords i can use for further searching.
You should NOT swizzle methods for this. This is deprecated behavior. This will affect ALL windows in your app not just the one you wanted to change. However, what you should do instead is to subclass NSWindow already and then change the class of that window at runtime. This can be done using this runtime function:
Class object_setClass(id object, Class cls)
Reference is here: http://developer.apple.com/mac/library/documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html#//apple_ref/doc/uid/TP40001418-CH1g-SW12
Your code should then look like this:
object_setClass(theWindow, [MyWindowSubclass class]);
On problem you might experience is that window already being a subclass of NSWindow. If that's the case there are more complicated ways to achieve this. You can construct a class dynamically at runtime. Here's some more code. Given that window is the target window:
Class newWindowClass = objc_allocateClassPair([window class], "MyHackyWindowSubclass", 0);
Method upMethod = class_getInstanceMethod(newWindowClass, #selector(keyUp:));
method_setImplementation(upMethod, new_NSWindow_keyUp_);
object_setClass(window, newWindowClass);
I'm not totally sure this does not change the implementation of the superclass. The documentation is a bit unspecific about it. However, you should still try it. If it does not work, replace the second and third line by this one:
class_replaceMethod(newWindowClass, #selector(keyUp:), new_NSWindow_keyUp_, "v#:#");
In any case you need to define the new Method implementation. It could look like that (partially by KennyTM):
void new_NSWindow_keyUp_(NSWindow* self, SEL _cmd, NSEvent* evt) {
[super keyUp: evt];
... // do your changes
}
Of course it is possible. In fact, you don't even need to look into the hash table — there's standard API for this.
For example:
typedef void (*NSWindow_keyUp__IMP)(NSWindow* self, SEL _cmd, NSEvent* evt);
static NSWindow_keyUp__IMP original_NSWindow_keyUp_;
void replaced_NSWindow_keyUp_(NSWindow* self, SEL _cmd, NSEvent* evt) {
NSLog(#"Entering keyUp:. self = %#, event = %#", self, evt);
original_NSWindow_keyUp_(self, _cmd, evt);
NSLog(#"Leaving keyUp:. self = %#, event = %#", self, evt);
}
...
Method m = class_getInstanceMethod([NSWindow class], #selector(keyUp:));
original_NSWindow_keyUp_ = method_setImplementation(m, replaced_NSWindow_keyUp_);
Using spacemanager, I need to perform an action on select bodies after each step, so I figured that defining my own C function for iterateFunc would be the way to go.
Everything works great, except I'm not sure how to then call an obj c method in the same class. In other words, an obj c class contains both the c function replacing iterateFunc, and the method that needs to be called. I don't see how to tell the c function what 'self' is, such that I can call the method. As far as i can tell, there's no way to pass in any extra info to the new iterateFunc.
Any ideas, or a better way to go about things?
Update:
Thanks for the response. Declaring a new spacemanager, one can redefine its iterateFunc:
smgr = [[SpaceManager alloc] init];
smgr.iterateFunc=doThisFunc;
In the same class, a "doThisFunc" function can be declared.
In spacemanager, this iterateFunc is called from the "step" method:
-(void) step: (cpFloat) delta
{
.....
cpSpaceHashEach(_space->activeShapes, _iterateFunc, self);
....
}
So my first thought was to subclass spacemanager, and in my custom step method, call cpSpaceHashEach with my own class, instead of self (the spacemanager, that is). Halfway there, I realized that I didn't even have to do that, as subclassing and defining my own step method was all I needed to do. My new step method:
-(void) step: (cpFloat) delta
{
[super step:delta];
//Having of course set the "myObject" variable elsewhere as my other object
[myObject doThis];
}
Thanks, bbum for both your answers, and for helping me craft better questions in the future.
Holy vagueness, batman, where's the code snippet? Thankfully, the Magic Powers of Google save the day.
To answer this question requires a few bits of detail:
What is the declaration of iterateFunc?
Oh. It is a cpSpaceHashIterator. Not helpful.
Ah... there it is:
typedef void (*cpSpaceHashIterator)(void *obj, void *data);
It looks like the void *data argument is your answer. Specifically, it looks like that is passed through transparently to your iterator function. That is, if you call:
cpSpaceEachBody(cpSpace *space, cpSpaceBodyIterator func, void *data)
Like this:
cpSpaceEachBody(space, funcPtr, (void *)self);
Then your iterator func could do this:
void iteratorFunc(void *obj, void *data) {
[(MyClass *)data iterateThis: obj];
}
I'd like (at runtime) to bind a parameter to a function as you can do in boost::bind - a little like the following:
-(void)myFuncWithParameter:(NSString*)param {
NSLog(param);
}
-(void)init {
UIButton *helloButton = [UIButton buttonWithType:UIButtonTypeCustom];
[helloButton addTarget:self action:#selector(myFuncWithParameter:#"hello") forControlEvents:UIControlEventTouchUpInside];
}
So... I'm dynamically binding (at runtime) the value #"hello" to a parameter.
Obviously the above isn't the correct Syntax. Does anyone know if this is possible and the correct syntax?
Cheers,
Nick.
The short answer is no, or at least not at that level.
The long answer is that it is technically possible to build something akin to using NSInvocations (and/or forwardInvocation:), doing something clever in methodForSelector: and or by dynamically registering method implementations, but it is very tricky, especially if you care at all about speed.
If I had some code where building curried methods like that was really worthwhile, what I would do is something like this (written in this comment, untested);
//FIXME: In a real implementation you would do some mangling, this code will get confused if you have _s in the curried selector, and thus could be exploitable
//This method makes a unique selector by mangling the arguments
- (SEL) selectorForSelector:(SEL)bindSel withString:(NSString *)bindString {
NSString *mangle = [NSString *stringWithFormat:#"LGBind_%#_%#"], NSStringFromSelector(bindSel), bindString];
SEL retval = NSSelectorFromString(mangle);
//Register the imp. You probably want to check if it is already reg
if (![self respondsToSelector:retval]) {
class_addMethod([self class], retval, LGBind_IMP, "v#:")l
}
}
//Generic dispatcher imp
void LGBind_IMP(id self, SEL _cmd) {
NSString *selectorName = NSStringFromSelector(_cmd);
NSArray *array [selectorName componentsSeparatedByString:#"_"];
//Skip index 0; it is #"LGBind"
NSString *originalSelectorString = [array objectAtIndex:1];
NSString *originalArgString = [array objectAtIndex:2];
//Get our the SEL and the IMP
SEL originalSEL = NSSelectorFromString(originalSelectorString);
IMP originalIMP = [self methodForSelector:originalSEL];
//call the original imp
originalIMP([self class], originalSEL, originalArgString);
}
Obviously depending on your exact needs you could do things somewhere differently, for instance you could lazily by the imps in forwardInvocation, or stash data about the managled selector in a dict in the instance instead of just managling it into the selector name.
The general answer is that the target-action mechanism only allows for a target, a sender and a message that takes the sender; therefore, if you need to access data, you must get it from the target or the sender.
One option would be to create a class that represents the binding of a parameter value, a method and an object. This class would have an action that invokes the method on the object, passing the value. Use an instance of this class as the target. Here's a simplistic example:
#interface UnaryBinder : NSObject {
id target;
SEL selector;
id parameter;
}
#property id target;
#property SEL selector;
#property (retain) id parameter;
-(id)initWithTarget:(id)anObject selector:(SEL)aSelector param:(id)aParameter;
-(void)action:(id)sender;
#end
#implementation UnaryBinder
...
-(void)action:(id)sender {
[target performSelector:selector withObject:parameter];
}
#end
If you want to support an arbitrary number of parameters, you'd need to use NSInvocation (as Louis mentions) rather than performSelector:withObject. Of course, controls don't retain their targets, so you need some way of keeping the UnaryBinder around. At that point, you might as well skip the special class and just store the data in the control, as you mention in your comment about using KVP. Alternatively, factor out the action into a controller class and use an instance of that as the target. UnaryBinder and its ilk doesn't really offer any advantages when it comes to target-action. For related topics, google "higher order messaging".