Using iterateFunc to call objective c method - objective-c

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];
}

Related

Proper way of method swizzling in objective-C

Currently experimenting with method swizzling in Objective-C and I have a question. I am trying to understand the proper way to method swizzle and after researching online I stumbled upon this NSHipster post:
http://nshipster.com/method-swizzling/
In the post the author has some method swizzling sample code. I am looking for someone to better explain to me what the author is doing.. In particular I am confused on the didAddMethod logic. Why is the author not just directly swapping/exchanging method implementations? My only theory on this is maybe there is some off chance that viewWillAppear: is not added to UIViewController's method dispatch_table yet. Particularly if maybe the category is loaded into memory first before UIViewController... Is this the reason why? It seems rather odd? Just looking for some more insight/clarity, thanks :)
In particular I am confused on the didAddMethod logic. Why is the author not just directly swapping/exchanging method implementations?
Your confusion is understandable as this logic is not explained clearly.
First ignore the fact that the example is a category on the specific class UIViewController and just consider the logic as though the category was on some arbitrary class, let's call that class TargetClass.
We'll call the existing method we wish to replace existingMethod.
The category, being on TargetClass, adds the swizzling method, which we'll call swizzlingMethod, to TargetClass.
Important: Note that the function to get an method, class_getInstanceMethod, will find the method in the supplied class or any of its superclasses. However the functions class_addMethod and class_replaceMethod only add/replace methods in the supplied class.
Now there are two cases to consider:
TargetClass itself directly contains an implementation of existingMethod. This is the easy case, all that needs to be done is exchange the implementations of existingMethod and swizzlingMethod, which can be done with method_exchangeImplementations. In the article the call to class_addMethod will fail, as there is already and existingMethod directly in TargetClass and the logic results in a call to method_exchangeImplementations.
TargetClass does not directly contain an implementation of existingMethod, rather that method is provided through inheritance from one of the ancestor classes of TargetClass. This is the trickier case. If you simply exchange the implementations of existingMethod and swizzlingMethod then you would be effecting (instances of) the ancestor class (and in a way which could cause a crash - why is left as an exercise). By calling class_addMethod the article's code makes sure there is an existingMethod in TargetClass - the implementation of which is the original implementation of swizzlingMethod. The logic then replaces the implementation of swizzlingMethod with the implementation of the ancestor's existingMethod (which has no effect on the ancestor).
Still here? I hope that makes sense and hasn't simply sent you cross-eyed!
Another exercise if you're terminally curious: Now you might ask what happens if the ancestor's existingMethod implementation contains a call to super... if the implementation is now also attached to swizzlingMethod in TargetClass where will that call to super end up? Will it be to implementation in ancestor, which would see the same method implementation executed twice, or to the ancestor's ancestor, as originally intended?
HTH
load is called when a class is added in obj-c runtime.
https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSObject_Class/#//apple_ref/occ/clm/NSObject/load
So let's say if a UIViewController gets added in obj-c runtime which already contains viewWillAppear: but you want it to be replaced by another implementation. So first you add a new method xxxWillAppear:.
Now once xxxWillAppear: has been added in ViewController class, only then you can replace it.
But the author also said :
For example, let’s say we wanted to track how many times each view controller is presented to a user in an iOS app
so he is trying to demonstrate a case where an app might have many view controllers but you do not want to keep replacing for each ViewController the viewWillAppear: implementation. Once the point of viewWillAppear: has been replaced, then instead of adding, only the exchange will need to be done.
Perhaps source code of Objective C runtime might help :
/**********************************************************************
* addMethod
* fixme
* Locking: runtimeLock must be held by the caller
**********************************************************************/
static IMP
addMethod(Class cls, SEL name, IMP imp, const char *types, BOOL replace)
{
IMP result = nil;
rwlock_assert_writing(&runtimeLock);
assert(types);
assert(cls->isRealized());
method_t *m;
if ((m = getMethodNoSuper_nolock(cls, name))) {
// already exists
if (!replace) {
result = _method_getImplementation(m);
} else {
result = _method_setImplementation(cls, m, imp);
}
} else {
// fixme optimize
method_list_t *newlist;
newlist = (method_list_t *)_calloc_internal(sizeof(*newlist), 1);
newlist->entsize_NEVER_USE = (uint32_t)sizeof(method_t) | fixed_up_method_list;
newlist->count = 1;
newlist->first.name = name;
newlist->first.types = strdup(types);
if (!ignoreSelector(name)) {
newlist->first.imp = imp;
} else {
newlist->first.imp = (IMP)&_objc_ignored_method;
}
attachMethodLists(cls, &newlist, 1, NO, NO, YES);
result = nil;
}
return result;
}
BOOL
class_addMethod(Class cls, SEL name, IMP imp, const char *types)
{
if (!cls) return NO;
rwlock_write(&runtimeLock);
IMP old = addMethod(cls, name, imp, types ?: "", NO);
rwlock_unlock_write(&runtimeLock);
return old ? NO : YES;
}
IMP
class_replaceMethod(Class cls, SEL name, IMP imp, const char *types)
{
if (!cls) return nil;
rwlock_write(&runtimeLock);
IMP old = addMethod(cls, name, imp, types ?: "", YES);
rwlock_unlock_write(&runtimeLock);
return old;
}
You can dig more if you want:
http://www.opensource.apple.com/source/objc4/objc4-437/

Objective-C swizzled method not receiving arguments

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);

What is the best way output the name of the class who's method is being called?

I am aware of NSStringFromClass.
My question relates to the situation where the same method is implemented in multiple classes in an inheritance tree, and you want to debugging information as to which class it is executing from.
Example:
Let us have three classes: A-->B-->C , inheriting as displayed by the arrows.
If each of them has a method foo(), defined:
-(void) foo
{
// Do some work particular to the class it is in.
.....
//Each method ends with the debugging statement:
NSLog("In foo of class:%$",NSClassFromString([self class]));
}
The problem occurs when foo of Class B, calls [super foo]. When [super foo] (i.e. Class A) reaches the NSLog statement, [self class] returns class B, and not A.
Likewise if C called [super foo], the log statement in super would log class C.
What I want to do, is output the class whose method implementation is being executed - so if class B calls [super foo], then the log statement in [A foo] outputs Class A.
The simple way is to replace NSClassFromString with a hardcoded string representing the class name, but I was wondering if there is a better way to do this ?
You can use __PRETTY_FUNCTION__ to include both the class and the method name:
NSLog(#"Greetings from %s", __PRETTY_FUNCTION__);
I don't believe that there is a compiler-time macro for just the class name.
There might not be a macro for class, but there is __FILE__ and __LINE__ macros in the C language. They expand to the current file and line number. You can use them in NSLog. I use __PRETTY_FUNCTION__ when I remember it, but I remember __FILE__ and __LINE__ more.
Example:
NSLog( #"%s %d", __FILE__, __LINE__ );
Remember that __FILE__ isn’t an Objective-C string.
The problem occurs when foo of Class B, calls [super foo]. When [super
foo] (i.e. Class A) reaches the NSLog statement, [self class] returns
class B, and not A.
Sure. That's because self points to an object, and that object's class doesn't change just because you call a method of the superclass.
The simple way is to replace NSClassFromString with a hardcoded string
representing the class name, but I was wondering if there is a better
way to do this?
As others have pointed out, you can use a macro like __PRETTY_FUNCTION__, but I think the simple and obvious approach is the best. You know the name of the class when you're writing the code, so you can write:
NSLog("In foo of class: %#", #"ClassA");
Each of your classes has its own implementation of your method, so each one can print its own class name in the message. Something like __PRETTY_FUNCTION__ is useful when you're writing a debug macro that you're going to use in multiple functions. That's not the case here. Using the obvious approach makes it that much easier to see what's going on, and that's important during debugging (which I assume is what you're trying to do here).
i think you would have to walk up the class hierarchy using class_getSuperclass and class_getInstanceMethod, comparing differences in the methods. do that to determine the objc class, then use class_getName or NSStringFromClass to get its name.
This would look something like:
NSString* MONClassNameWhichImplementsMethod(id Self, SEL cmd);
and
- (void)method
{
NSLog(#"%# - %#",
MONGetClassWhichImplementsMethod(self, _cmd),
NSStringFromSelector(_cmd)
);
}
and
// NOT COMPILED -- FOR ILLUSTRATION ONLY
Class MONClassWhichImplementsMethod(Class cls, SEL cmd) {
assert(cls && cmd && "srsly?");
Class super = class_getSuperclass(cls);
Method m1 = class_getInstanceMethod(cls, cmd);
assert(m1 && "srsly?");
Method m2 = class_getInstanceMethod(super, cmd);
if (0 == m2) {
return cls;
}
else if (m1 != m2) {
return cls;
}
else {
return MONClassWhichImplementsMethod(super, cmd);
}
}
NSString* MONClassNameWhichImplementsMethod(id Self, SEL cmd) {
return NSStringFromClass(MONClassNameWhichImplementsMethod(Self.class, cmd));
}
if it blows up from deep recursion, you've another problem.

Objective-C, how can i hook up a method in another class

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_);

Handling Callbacks

I have a method in an objective-C class. It has 2 callback functions written in C. The class pointer i.e. self is passed to these functions as void *. In the C functions I create a pointer of type class and assign the void * parameter.
The first callback function executes successfully. But the void * pointer becomes nil in the 2nd callback function. Note that I haven't tweaked pointer in the first callback but still I get nil in 2nd callback.
Any ideas what might be going wrong?
For example:
kr = IOServiceAddMatchingNotification(gNotifyPort, kIOFirstMatchNotification,
matchingDict, RawDeviceAdded, NULL,
&gRawAddedIter);
RawDeviceAdded(NULL, gRawAddedIter, self);
This works fine. But below function receives self as nil.
kr = IOServiceAddMatchingNotification(gNotifyPort, kIOFirstMatchNotification,
matchingDict, BulkTestDeviceAdded, NULL,
&gBulkTestAddedIter);
BulkTestDeviceAdded(NULL, gBulkTestAddedIter, self);
Are your problems specifically with the IOKit callback routines? The problem with the specific example you gave is that the IOServiceMatchingCallback takes only 2 parameters, not 3. You need your RawDeviceAdded() and BulkTestDeviceAdded() callback functions to match the IOServiceMatchingCallback prototype and to accept self as the first parameter (refCon), not the 3rd. Also, you need to pass in self as the second-to-last parameter of IOServiceAddMatchingNotification() to get it passed back to you by the callback.
A common method for handling C callbacks in Objective-C code is just to have a static function that forwards the callback to your instance. So, your example callback code would look like this:
static RawDeviceAdded(void* refcon, io_iterator_t iterator)
{
[(MyClass*)refcon rawDeviceAdded:iterator];
}
#implementation MyClass
- (void)setupCallbacks
{
// ... all preceding setup snipped
kr = IOServiceAddMatchingNotification(gNotifyPort,kIOFirstMatchNotification, matchingDict,RawDeviceAdded,(void*)self,&gRawAddedIter );
// call the callback method once to 'arm' the iterator
[self rawDeviceAdded:gRawAddedIterator];
}
- (void)rawDeviceAdded:(io_iterator_t)iterator
{
// take care of the iterator here, making sure to complete iteration to re-arm it
}
#end
Generally, callbacks in Objective-C are handled by passing a delegate object and a selector to perform on that delegate. For example, this method will call a method on its delegate after logging a message, passing both itself and the message that was logged.
- (void)logMessage:(NSString *)message
delegate:(id)delegate
didLogSelector:(SEL)didLogSelector
{
NSLog(#"%#", message);
if (delegate && didLogSelector && [delegate respondsToSelector:didLogSelector]) {
(void) [delegate performSelector:didLogSelector
withObject:self
withObject:message];
}
}
You might call it in code like this:
- (void)sayHello
{
[logger logMessage:#"Hello, world"
delegate:self
didLogSelector:#selector(messageLogger:didLogMessage:)];
}
- (void)messageLogger:(id)logger
didLogMessage:(NSString *)message
{
NSLog(#"Message logger %# logged message '%#'", logger, message);
}
You can also use objc_msgSend() directly instead, though you need to understand the Objective-C runtime enough to choose which variant to use and how to construct the prototype and function pointer through which to call it. (It's the mechanism by which message sends are actually implemented in Objective-C — what the compiler normally generates calls to in order to represent [] expressions.)
This is what Objective-C's selector is for:
http://developer.apple.com/iphone/library/documentation/Cocoa/Reference/NSInvocationOperation_Class
The API isn't very intuitive, but its fine once you understand it
You might need to do some refactoring as well, now there might be a better way, but when I had this problem my solution was to refactor and use InvoationOperation.