passing in a method in Objective C - objective-c

In C# you can create a delegate method, assign it to a variable or pass it into a method as if it were a variable. For example:
public delegate int Lookup(String s);
//...
public static int Evaluate(String exp, Lookup variableEvaluator)
{
//...
}
I heard that in C you can create a pointer to any method and then pass that pointer to a method.
Can anyone give me a simple example of doing that in Objective-C? Of course, I can create an object with a singe method and pass that object into a method. But I am curious if there is a way of doing that similar to that of C# or C.

Lots of ways.
One: the good. Use blocks (closures, lambda calculus, however you call it):
typedef void (^MyCallback)();
- (void)callTheCallback:(MyCallback)blockToInvoke
{
blockToInvoke();
}
MyCallback cb = ^{
NSLog(#"I was called! :D");
};
[self callTheCallback:cb];
Two: the bad. Grab a pointer to the method function itself and call that. (Warning: if you use this approach, I'll sue you.)
- (void)callTheCallback:(IMP)funcPtrToCall withObject:(id)obj selector:(SEL)sel
{
funcPtrToCall(obj, sel);
}
- (void)someCallbackMethod
{
NSLog(#"I was called! :D");
}
IMP implemt = [[self class] instanceMethodForSelector:#selector(someCallbackMethod)];
[self callTheCallback:implemt withObject:self selector:#selector(someCallbackMethod)];
Three: the ugly. Use a delegate:
- (void)delegateMethodOfSomeObject:(SomeObject *)obj
{
NSLog(#"I was called! :D");
}
SomeObject *obj = [[SomeObject alloc] init];
obj.delegate = self;
[obj makeThisObjectSomehowCallItsDelegateThatIsCurrentlySelf];

Two quick thoughts come to mind.
The short answer is called "blocks", but it's lower level than is probably recommended for what you need.
The "cleaner" solution (read: higher level) is to pass two params: and object (called "target") and a selector (called "action"). This is a very common pattern in Objective-C, so I'll only demonstrate this one. If you are interested in the blocks idea, check out this doc.
Essentially, the object should be passed as an id, and the selector as a SEL, for which we have the handy #selector() construct:
-(void) doThingWithTarget:(id) targetObj action:(SEL) actionSel {
if([targetObj respondsToSelector:actionSel]) {
[targetObj performSelector:actionSel withObject:self];
}
}
// ...
[thatOtherObject doThingWithTarget:self action:#selector(myMethod:)];
// ... where
-(void) myMethod:(id) sender {
// sender is the calling object, or should be by contract.
}

Objective C uses selectors. http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/objectivec/Chapters/ocSelectors.html

Related

Calling original function from swizzled function

I am messing around with method swizzling and would like to call the original function after performing a method_exchangeImplementations. I have two projects I have setup for this.
The first project is the main project for the application. This project includes all of the logic for the application. Notice that originalMethodName is called when the view loads.
#implementation ViewController
- (void)originalMethodName
{
NSLog(#"REAL %s", __func__);
}
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"REAL %s", __func__);
[self originalMethodName];
}
#end
The second project includes only the code for swizzling. I have a method swizzle_originalMethodName which includes the code I want to inject into the main application with the originalMethodName function is called.
#implementation swizzle_ViewController
- (void)swizzle_originalMethodName
{
NSLog(#"FAKE %s", __func__);
}
__attribute__((constructor)) static void initializer(void)
{
NSLog(#"FAKE %s", __func__);
Class c1 = objc_getClass("ViewController");
Class c2 = [swizzle_ViewController class];
Method m1 = class_getInstanceMethod(c1, #selector(originalMethodName));
Method m2 = class_getInstanceMethod(c2, #selector(swizzle_originalMethodName));
method_exchangeImplementations(m1, m2);
}
#end
The swizzle is working just fine (as seen in the output below), but now I want to be able to call originalMethodName from the swizzle_originalMethodName
2016-08-17 14:18:51.765 testMacOS[7295:1297055] FAKE initializer
2016-08-17 14:18:51.822 testMacOS[7295:1297055] REAL -[ViewController viewDidLoad]
2016-08-17 14:18:51.822 testMacOS[7295:1297055] FAKE -[swizzle_ViewController swizzle_originalMethodName]
I have tried to use NSInvocation but am not having any luck. Any ideas what I am doing wrong?
Class c1 = objc_getClass("ViewController");
Method m1 = class_getInstanceMethod(c1, #selector(originalMethodName));
NSMethodSignature *methodSignature = [NSMethodSignature signatureWithObjCTypes:method_getTypeEncoding( m1)];
NSInvocation *originalInvocation = [NSInvocation invocationWithMethodSignature:methodSignature];
[originalInvocation invoke];
If you are swizzling within a class hierarchy, e.g. you have a subclass which swizzles one of its ancestors methods with one of its own, then you simply have the swizzled-in method apparently call itself – that call will actually call the swizzled-out method as the methods have been swapped. In your case you would have:
- (void)swizzle_originalMethodName
{
NSLog(#"FAKE %s", __func__);
[self swizzle_originalMethodName]; // call original
}
This does not work in your case as you are cross-class swizzling, so self doesn't reference the class with the swizzled-out method. And you don't have an instance of the swizzling class you can call the swizzled-out method on...
Here is one easy way to fix this, what your swizzle-in method needs to be able to do is call the original implementation, and you can get that when you setup the swizzling.
In Objective-C a method is implemented by a function whose first two arguments are the object reference the method is being called on and the selector and the remaining arguments are those of the method. For example the NSString method:
- (NSRange)rangeOfString:(NSString *)aString
is implemented by a function something like:
NSRange rangeOfStringImp(NSString *self, SEL cmd, NSString *aString)
You can obtain a function pointer to this implementation function using method_getImplementation.
To your code, first in your swizzle_ViewController declare a type for the implementation function of the method you are swizzling, and a global to store the function pointer:
typedef void (*OriginalImpType)(id self, SEL selector);
static OriginalImpType originalImp;
Now in your initializer method you need to save the method implementation, you can do this by adding the line shown:
Method m1 = class_getInstanceMethod(c1, #selector(originalMethodName));
originalImp = (OriginalImpType)method_getImplementation(m1); // save the IMP of originalMethodName
Finally have your swizzled-in method call the saved implementation:
- (void)swizzle_originalMethodName
{
NSLog(#"FAKE %s", __func__);
originalImp(self, #selector(originalMethodName)); // call the original IMP with the correct self & selector
}
Optional: The above works correctly, however it does a little more than is required – the method implementations are both exchanged and one is stored in a global variable, all you really need to do is save the original implementation of m1 and then set its implementation to that of m2. You can address this by replacing the call to method_exchangeImplementations with:
method_setImplementation(m1, method_getImplementation(m2));
It is a little more typing, but somewhat clearer as to what actually needs to be done.
HTH
There is a slightly easier option to call the original implementation that doesn't require you to store the method implementation directly. When you exchange implementations of the methods, the original implementation will be stored in the swizzler class. You can fetch the swizzled out implementation using the class_getMethodImplementation function. Here is a playground sample:
import Cocoa
let fooSelector = Selector("fooWithArg:")
let swizzledFooSelector = Selector("swizzled_fooWithArg:")
class A: NSObject {
#objc dynamic func foo(arg: String) {
print("Foo \(arg) in A")
}
}
class B: NSObject {
private typealias FooFunc = #convention(c) (AnyObject, Selector, String) -> Void
#objc func swizzled_foo(arg: String) {
print("Swizzled_foo \(arg) in B")
unsafeBitCast(
class_getMethodImplementation(B.self, swizzledFooSelector),
to: FooFunc.self
)(self, fooSelector, arg)
}
}
method_exchangeImplementations(
class_getInstanceMethod(A.self, fooSelector)!,
class_getInstanceMethod(B.self, swizzledFooSelector)!
)
A().foo(arg: "bar")

Objective-C dynamic properties at runtime?

Is it possible to create an Objective-C class that can have an arbitrary number of dynamic properties at runtime?
I want to be able to call mySpecialClass.anyProperty and intercept this inside my class to be able to provide my own custom implementation that can then return an NSString (for instance) at runtime with raising an exception. Obviously this all has to compile.
Ideal would be if I could refer to my properties using something similar to the new literal syntax, e.g. mySpecialClass["anyProperty"].
I guess in a way I want to create something like a dynamic NSDictionary with no CFDictionary backing store, that executes 2 custom methods on property getting and setting respectively, with the property name passed in to these accessor methods so they can decide what to do.
There are at least two ways to do this.
Subscripting
Use objectForKeyedSubscript: and setObject:forKeyedSubscript:
#property (nonatomic,strong) NSMutableDictionary *properties;
- (id)objectForKeyedSubscript:(id)key {
return [[self properties] valueForKey:[NSString stringWithFormat:#"%#",key]];
}
- (void)setObject:(id)object forKeyedSubscript:(id <NSCopying>)key {
[[self properties] setValue:object forKey:[NSString stringWithFormat:#"%#",key]];
}
Person *p = [Person new];
p[#"name"] = #"Jon";
NSLog(#"%#",p[#"name"]);
resolveInstanceMethod:
This is the objc_sendMsg executed by the runtime for all methods:
If you look at the bottom, you have the opportunity to resolveInstanceMethod:, which lets you redirect the method call to one of your choosing. To answer your question, you need to write a generic getter and setter that looks-up a value on a dictionary ivar:
// generic getter
static id propertyIMP(id self, SEL _cmd) {
return [[self properties] valueForKey:NSStringFromSelector(_cmd)];
}
// generic setter
static void setPropertyIMP(id self, SEL _cmd, id aValue) {
id value = [aValue copy];
NSMutableString *key = [NSStringFromSelector(_cmd) mutableCopy];
// delete "set" and ":" and lowercase first letter
[key deleteCharactersInRange:NSMakeRange(0, 3)];
[key deleteCharactersInRange:NSMakeRange([key length] - 1, 1)];
NSString *firstChar = [key substringToIndex:1];
[key replaceCharactersInRange:NSMakeRange(0, 1) withString:[firstChar lowercaseString]];
[[self properties] setValue:value forKey:key];
}
And then implement resolveInstanceMethod: to add the requested method to the class.
+ (BOOL)resolveInstanceMethod:(SEL)aSEL {
if ([NSStringFromSelector(aSEL) hasPrefix:#"set"]) {
class_addMethod([self class], aSEL, (IMP)setPropertyIMP, "v#:#");
} else {
class_addMethod([self class], aSEL,(IMP)propertyIMP, "##:");
}
return YES;
}
You could also do it returning a NSMethodSignature for the method, which is then wrapped in a NSInvocation and passed to forwardInvocation:, but adding the method is faster.
Here is a gist that runs in CodeRunner. It doesn't handle myClass["anyProperty"] calls.
You're asking different things. If you want to be able to use the bracket syntax mySpecialClass[#"anyProperty"] on instances of your class, it is very easy. Just implement the methods:
- (id)objectForKeyedSubscript:(id)key
{
return ###something based on the key argument###
}
- (void)setObject:(id)object forKeyedSubscript:(id <NSCopying>)key
{
###set something with object based on key####
}
It will be called everytime you use the bracket syntax in your source code.
Otherwise if you want to create properties at runtime, there are different ways to proceed, take a look at NSObject's forwardInvocation: method, or look at the Objective-C Runtime Reference for functions to dynamically alter a class...
Guillaume is right. forwardInvocation: is the way to go. This answer gives some more details: method_missing-like functionality in objective-c (i.e. dynamic delegation at run time)
This has even more details: Equivalent of Ruby method_missing in Objective C / iOS
And these are some other lesser known Obj-C features that might help you: Hidden features of Objective-C
Enjoy!

Dynamic method creation in Objective-C

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.

In Objective C what is the equivalent of passing a function pointer in C?

#implementation ThisObject
-(void)start {
SomeOtherObject *someOtherObject = [SomeOtherObject alloc];
[someOtherObject doSomethingAndCallThisFunctionWhenUrDone:myCallBackFunction :self];
}
-(void)myCallBackFunction {
// :)
}
Basically, how can I make this work?
There are four ways to make a callback:
Function Pointer You can do a function pointer if you really want, but it's not recommended. It's done the same way you would do it in C. The problem is you can't use a function pointer to an Objective-C method. It looks something like this:
void callback(/* Some args */) {
// Some callback.
}
- (void)doSomethingAndCallThisFunctionWhenDone:(void(*)(/* Some args */))func {
// Do something.
if (func)
func(/* Some args */);
}
- (void)start {
[self doSomethingAndCallThisFunctionWhenDone:&callback];
}
Selectors You can use -performSelector:. It looks like this:
- (void)doSomethingAndCallTarget:(id)target withSelector:(SEL)sel {
// Do something.
[target performSelector:sel];
}
- (void)start {
SomeOtherObject * someOtherObject = [[SomeOtherObject alloc] init];
[self doSomethingAndCallTarget:someOtherObject withSelector:#selector(MyCallback)];
}
Delegates Use a delegate. This is similar to UITableViewDelegate/UITableViewDataSource. See the Apple docs here. You might do it like this:
- (void)doSomethingDelegate:(id<MyCallbackObject>)delegate {
[delegate retain];
// Do something.
[delegate performMyCallback]; // -performMyCallback must be declared in the MyCallbackObject protocol and implemented by SomeOtherObject.
[delegate release];
}
- (void)start {
id<MyCallbackObject> someOtherObject = [[SomeOtherObject alloc] init];
[self doSomethingDelegate:someOtherObject];
[someOtherObject release];
}
Blocks The preferred way for callbacks is to use blocks. They are only available for iOS 4.0+ or Mac OS X 10.6+. It looks something like this:
- (void)doSomethingAndCallThisBlockWhenDone:(void(^)(/* Some args */))block {
[block copy];
// Do something.
if (block)
block(/* Some args */);
[block release];
}
- (void)start {
[self doSomethingAndCallThisBlockWhenDone:^void(/* Some args */){ // Return type and arguments may be omitted if you don't have any.
// Your callback
}];
}
As you can see with the block, it's easier to read and your callback is inline with your code. This is especially nice so you don't have to hunt it down. There are many more benefits of blocks, but I couldn't possibly cover them all here.
One last thing, if you use a block, you will want to use a typedef so you don't have to type obscure block types like void(^)(/* Some args */) all the time. The typedef could look like this:
typdef void(^MyCallback)(/* Some args */);
Then, you can declare your method like this:
- (void)doSomethingAndCallThisBlockWhenDone:(MyCallback)block;
Update:
I have shown more detail of how to implement the different techniques (see above).
Are you talking about this?
-(void)callSomePassedSelector:(SEL)callbackSelector {
[someObjectThatRespondesToThisSelector performSelector:callbackSelector];
}
I assume you want to store it and call it later, but this should give you all the needed information about how to pass and call it. There are other methods to invoke the selector, see more here
im a bit confused about what you talking about but is this it?
[self performSelector:#selector(myCallFunction)];

Can a C function be used as a selector in Cocoa?

I want to start a new thread using a C function, not an objective-C method. I tried
[NSThread detachNewThreadSelector: #selector(func) toTarget: nil withObject: id(data)];
where I have
void func(void *data) {
// ...
}
and data is a void *, but I get a runtime crash in objc_msgSend, called from
-[NSThread initWithTarget:selector:object:]
What can I do instead? Is it even possible?
Roll your own:
// In some .h file. #import to make the extension methods 'visible' to your code.
#interface NSThread (FunctionExtension)
+(void)detachNewThreadByCallingFunction:(void (*)(void *))function data:(void *)data;
-(id)initWithFunction:(void (*)(void *))function data:(void *)data;
#end
// In some .m file.
#implementation NSThread (FunctionExtension)
+(void)startBackgroundThreadUsingFunction:(id)object
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
void (*startThreadFunction)(void *) = (void (*)(void *))[[object objectForKey:#"function"] pointerValue];
void *startThreadData = (void *) [[object objectForKey:#"data"] pointerValue];
if(startThreadFunction != NULL) { startThreadFunction(startThreadData); }
[pool release];
pool = NULL;
}
+(void)detachNewThreadByCallingFunction:(void (*)(void *))function data:(void *)data
{
[[[[NSThread alloc] initWithFunction:function data:data] autorelease] start];
}
-(id)initWithFunction:(void (*)(void *))function data:(void *)data
{
return([self initWithTarget:[NSThread class] selector:#selector(startBackgroundThreadUsingFunction:) object:[NSDictionary dictionaryWithObjectsAndKeys:[NSValue valueWithPointer:function], #"function", [NSValue valueWithPointer:data], #"data", NULL]]);
}
#end
NOTE: I wrote the above code and here by place it in the public domain. (sometimes the lawyers like this kind of stuff) It is also completely untested!
You can always remove the NSAutoreleasePool bits if you can guarantee that the thread entry function also creates one... but it's harmless, has no speed penalty what-so-ever, and makes calling arbitrary C functions that much more simpler. I'd say just keep it there.
And you can use it like so:
void bgThreadFunction(void *data)
{
NSLog(#"bgThreadFunction STARTING!! Data: %p", data);
}
-(void)someMethod
{
// init and then start later...
NSThread *bgThread = [[[NSThread alloc] initWithFunction:bgThreadFunction data:(void *)0xdeadbeef] autorelease];
// ... assume other code/stuff here.
[bgThread start];
// Or, use the all in one convenience method.
[NSThread detachNewThreadByCallingFunction:bgThreadFunction data:(void *)0xcafebabe];
}
When run:
2009-08-30 22:21:12.529 test[64146:1303] bgThreadFunction STARTING!! Data: 0xdeadbeef
2009-08-30 22:21:12.529 test[64146:2903] bgThreadFunction STARTING!! Data: 0xcafebabe
Create an Objective-C class with a method that simply calls that function. Take the selector of that method and pass it to NSThread API.
Well, I'm not sure if it's possible, but keep in mind that every Objective-C method has two implicit/hidden arguments, self and _cmd. An IMP is usually typedef'd like this:
typedef id (*IMP)(id,SEL,...);
If you want to jerry-rig methods and selectors, you need to have a method that looks like that:
void func (id self, SEL _cmd, void *firstParameter);
But even after that, you need to register a selector name with the runtime, then you need to associate that selector with the method, but this is done on a class-by-class basis (i.e. classes can have different implementations of the same selector name), so you at least need to have a dummy class.
It is much, much simpler just to create a dummy class and dummy instance of that class than call the various runtime API just to get NSThread to invoke a single C function.
If you don't need NSThread stuff, you can also start a thread with direct POSIX interface.
I want to start a new thread using a C function, not an objective-C method
Then why don't you just use:
POSIX threads,
GCD?
dispatch_async_f() (man) is suited exactly for this purpose.