Dynamically implementing a delegate during runtime - ios

In my class, I have a reference on an UIViewController and want to implement a delegate on this ViewController during runtime. The delegate has only one method (with two parameters) and when the delegate-method on the ViewController is invoked, my class should handle the call.
I am quite sure this is possible with some kind of method swizzling, etc. but I don't know how to accomplish this.

What you want is possible, but it's not method swizzling, since you don't want to switch to methods but add a new one. It can be done, thanks to Objective-C's dynamic nature, but it's still a dirty hack so also file a feature request with the library vendor.
What you want is class_addMethod() and a C function with the actual implementation for that. One more thing, Objective-C methods are C methods, but with two implicit parameters, self and _cmd, which have to keep in mind (both when creating your C method and when telling class_addMethod your methods signature. And here is an SSCE of how to pull something like that off:
#import <Foundation/Foundation.h>
#import <objc/runtime.h> // Required for class_addMethod()
#interface MyClass : NSObject
#end
#implementation MyClass
#end
#protocol MyProtocol <NSObject>
- (void)printString:(NSString *)string;
#end
// Note the method signature containing the
// two implicit parameters self and _cmd!
void MyClassPrinStringIMP(id self, SEL _cmd, NSString *string)
{
NSLog(#"Hi I'm %#:%s and this is the string: %#", self, sel_getName(_cmd), string);
}
void PimpMyClass()
{
// The last argument is the signature. First character is the return type, in our case void
// Then comes self and _cmd, followed by the NSString. You can use #encode() to find out how your
// type is encoded. Best is to build this string at runtime, since the encoding can change with architectures
class_addMethod([MyClass class], #selector(printString:), (IMP)MyClassPrinStringIMP, "v#:#");
}
int main(int argc, const char * argv[])
{
#autoreleasepool
{
PimpMyClass();
id foo = [[MyClass alloc] init]; // id, to silence the compiler!
[foo printString:#"Hello World"];
}
return 0;
}
Example output:
Hi I'm <MyClass: 0x100101810>:printString: and this is the string: Hello World
Edit: Something that you may find is that the passed object is checked at runtime wether it conforms to a protocol or not using conformsToProtocol:. Since this code just adds the method implementation, it would still fail, but you can tell the runtime that you totally do implement that protocol with this one function call:
class_addProtocol([MyClass class], #protocol(MyProtocol));
Alternative: proxies
Objective-Cs dynamism and message forwarding is already praised by #JasperBlues, however, there is one particular class in Objective-C that is designed to do just that: NSProxy. It is designed to intercept sent messages and dispatching them dynamically to the relevant target, and does use the high-level NSInvocation approach. If you can pass a proxied object in some way as the delegate (depending on what your code allows for and what not), creating a NSProxy subclass might be the cleanest way to go.
However, note though that you then end up with a shim object that wraps over your other object, which comes with its own bag of pain and will break when you try to directly access variables via -> syntax. It's not a perfectly invisible proxy, but good enough for most cases.

Firstly, some comments indicate that what you're asking is instantly "a bad thing to do" or a "dirty hack". I disagree here. Most modern Object Oriented languages support these features, and they are used to good effect by numerous system-level frameworks. Of course it is human-nature to perhaps use these dynamic features where they're not really required (for fun or practice), even when a simpler approach would work fine. Beware of this.
Objective-C is admirable in that its somewhat of a legacy language and close to the "bare metal", and yet features a surprising level of dynamism, making it relatively easy to support these requirements without any external libraries or frameworks.
Besides using the class_addMethod guide that another answer correctly indicates, some other approaches are:
Message Forwarding: (recommended)
All NSObject sub-classes have the ability to forward a method that they're not able to respond to, to another target object. This is similar to the lower-level concept of trampolines. Apple publishes a guide on using this approach.
The advantages of using forward invocation is that it uses the NSInvocation level of abstraction, instead of directly calling the C ObjC runtime API. This abstracts the following details away:
Structs and primitives will be box/unboxed automatically
Dispatching to methods with a dynamic/unknown number of arguments becomes easy. Until arm64, this could be done using va_args, however on arm64 va_args can be copied directly to registers, and not popped off the stack.
Resolve Instance Method:
Instance methods are created by by registering a C function as the implementation to respond to a given message. This can be done neatly with blocks, using IMP_ImplementationWithBlock:
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
IMP imp = imp_implementationWithBlock((__bridge id) objc_unretainedPointer(
^(id me, BOOL firstParam, NSString* secondParam)
{
//Implementation goes in here
return something; //something of type 'id'
}));
class_addMethod(self, sel, imp, "##:");
return YES;
}
return NO;
}
Using libffi:
Libffi can also do this kind of thing, though it should not be necessary if you're using pure Objective-C, as the runtime already has these features baked in.

Related

No known class method for selector 'simplePingWithHostName: SimplePing iOS Objective C

Hello I am having trouble using SimplePing I receive the following error when copying over the SimplePing.h and SimplePing.m files I downloaded from Apple SimplePing
No known class method for selector 'simplePingWithHostName:'
From this method in my SimplePingClient.m class:
-(void)pingHostname:(NSString*)hostName andResultCallBlock:(void(^)(NSString* latency))result
{
_resultCallback = result;
_pingClient = [SimplePing simplePingWithHostName:hostName]; // No known class method for selector 'simplePingWithHostName:'
_pingClient.delegate = self;
[_pingClient start];
}
I'm calling this method from another file like this, where there are no errors:
-(void)testNetworkLatency {
[SimplePingClient pingHostname:#"www.apple.com"
andResultCallback:^(NSString *latency) {
NSLog(#"your latency is: %#", latency ? latency : #"unknown");
}];
}
I tried changing [SimplePing simplePingWithHostName... in SimplePingClient.m to variations of pingHostname, initWithHostName, sendPingWithData but nothing has worked so far. Did something change with SimplePing or am I going wrong somewhere?
Link to a screenshot of all the methods available in SimplePing.h as you can see, there is no simplePingWithHostName
it is wise to read the class definitions before coping and pasting but once done you can take them for granted because thats what they are for. You will have much more fun when following them. But keep on trying as this is a classic beginner mistake in objC when taking over language concepts from elsewhere but not objC.
You will want to set a global variable to keep your simple ping object around.
#implementation YourClass {
SimplePing *_pingClient;
}
alternative in
#interface YourClass : YourInheritingClass <NeverGiveUpProtocol>
#property (nonatomic) SimplePing *pingClient;
#end
and in your implementation method allocation and initiation of your ping object is done like
_pingClient = [[SimplePing alloc] initWithHostName:hostName];
Also you will have to be careful with the definition of block parameters that are doing nothing and are set up to accept NSStrings. You can read about block definitions in methods here
https://riptutorial.com/objective-c/example/1761/blocks-as-method-parameters
You can tell the compiler that you don't need a specific parameter like so ..
if you cant avoid to define it.
-(void)yourmethod:(NSString*)hostname resultBlock:(void(^)())result {
#pragma unused(result)
// your stuff
}
Hint: SimplePing and SimplePingClient seem to be total different classes where the last one contains pingHostname: as external method. (Means you can call it without explicit initiation.) Ending up in a method definition like..
+(void)pingHostname:(NSString *)hostname; which is why you would need to call it directly on the ClassName.
The Apple example does not contain a class named SimplePingClient.
Thats probably result of your creative process. Yeah maybe you want to ping from the app you create to the same app on a different device - well, why not. Cheers

Is it possible to silence the warning on "performSelector" and receive the return value or object?

I am familiar with the solutions to this ARC warning (performSelector may cause a leak because its selector is unknown) and have implemented them in most cases, but I can't seem to find a way to properly get the return value for a selector without just suppressing a warning.
It seems that maybe it can't or shouldn't be done, but a rewrite of code logic (developed by others) is too time consuming.
Code example:
NSString *message = [callback performSelector:validatorSel withObject:textCell.textField.text];
If validatorSel is known to not to begin with allocor new, or to have copy (or Copy) in its name, and you know there are no memory-management overrides involved (which are rare), then the default memory management will be correct here, and you can suppress the warning with an appropriate #pragma. If you cannot prove those things, then this may crash, which is why there's a warning.
If you cannot prove the above requirements, then there is no way to make this safe under ARC. You will either have to build it without ARC or rewrite it.
From your code sample it looks like you are expecting a selector for a method which takes an NSText * and return an NSString *. So from your linked answer you can determine that the implementation of this method has the function type:
NSString *(*)(ID, SEL, NSText *)
Here ID may be replaced by the type of callback, and NSText * can be replaced by the actual type of textCell.textField.text if our guess is wring.
Again from your linked answer, you can obtain the implementation and call it using:
NSString *(*implementation)(ID, SEL, NSText *)
= (void *)[callback methodForSelector: performSelector:validatorSel];
NSString *message = implementation(callback, validatorSel, textCell.textField.text);
As #RobNapier correctly points out this is only safe under ARC if the selector does not return a retained value, i.e. for normal[*] selectors if it is a member of the init, copy, or new method families. Now you are very unlikely to be passed an init family method for validatorSel as that would require callback to be a reference to an alloc'ed but not init'ed object, so we can ignore that one for now[#]. To test for the other two families you can use code along the lines of:
NSString *message; // for the return value of the selector
NSString *selName = NSStringFromSelector(validatorSel); // get string name of selector
if ([selName hasPrefix:#"new"] // starts with new,
|| [selName hasPrefix:#"copy"] // or copy,
|| [selName rangeOfString:#"Copy"].location != NSNotFound) // or contains "Copy"
{
// need to handle returning a retained object
...
}
else
{
// normal case
NSString *(*implementation)(ID, SEL, NSText *)
= (void *)[callback methodForSelector: performSelector:validatorSel];
message = implementation(callback, validatorSel, textCell.textField.text);
}
Which just leaves how to handle the return value correctly under ARC for copy and new family methods...
Handling copy and new family methods
ARC knows that a method, or function, returns a retained object by an attribute being placed on the method/function type. The naming convention is just the language's way of inferring the attribute if it is not present, it can be manually specified using the NS_RETURNS_RETAINED macro on a method/function declaration. So the missing code above is just:
{
// need to handle returning a retained object
NSString *(*implementation)(ID, SEL, NSText *) NS_RETURNS_RETAINED
= (void *)[callback methodForSelector: performSelector:validatorSel];
message = implementation(callback, validatorSel, textCell.textField.text);
}
The modified type for implementation tells ARC that it will return a retained object and ARC will handle the call the same way it does for known copy or new family methods.
HTH
Note: Handling init family methods
We skipped the init family not just because it is highly unlikely but also because it behaves differently - init family methods consume the object reference they are called on, that is they expect to be passed an owned object which they take ownership of, and will release it if needed. Unsurprisingly consuming an argument is also indicated by an attribute, just as for returning a retained object. The curious reader might wish to determine the code required, even though needing it is highly unlikely.
[*] A "normal" selector is one for a method which follows the standard naming conventions of Objective-C and does not use attributes to alter the memory ownership behaviour in ways contrary to the standard conventions. Only supporting standard conventions is not a big restriction, the whole point of the conventions is that code relies on them!
[#] You are of course very unlikely to be passed a new family selector as well, callback would usually have to be a reference to a class object, but handling it is the same as for the copy family so we've included it.

In Objective-C, does the binding of method really happen at "run-time"?

I heard that Objective-C is influenced by the "message passing mechanism" of SmallTalk.
Objective-C, like Smalltalk, can use dynamic typing: an object can be
sent a message that is not specified in its interface. This can allow
for increased flexibility, as it allows an object to "capture" a
message and send the message to a different object that can respond to
the message appropriately, or likewise send the message on to another
object.
And I felt for codes like [anObject someMethod], the binding of someMethod to the machine code may happen at run-time..
Therefore, I write a demo like this:
#import <Foundation/Foundation.h>
#interface Person : NSObject {
#private char *name;
}
#property (readwrite, assign) char *name;
- (void)sayHello;
#end
#implementation Person
#synthesize name;
- (void)sayHello {
printf("Hello, my name is %s!\n", [self name]);
}
#end
int main() {
Person *brad = [Person new];
brad.name = "Brad Cox";
[brad sayHello];
[brad sayHelloTest];
}
I tried [brad sayHelloTest] to send brad a message sayHelloTest which brad doesn't know how to handle with.. I expect the error will NOT happen at compile-time..
However, the compiler still throws an error:
main.m:24:11: error: instance method '-sayHelloTest' not found (return type defaults to 'id') [-Werror,-Wobjc-method-access]
[brad sayHelloTest];
^~~~~~~~~~~~
main.m:3:12: note: receiver is instance of class declared here
#interface Person : NSObject {
^
Change [(id)brad sayHelloTest] to [(id)brad sayHelloTest]; doesn't work either.. (The compiling command is clang -Wall -Werror -g -v main.m -lobjc -framework Foundation -o main)
In Objective-C, does the binding of method really happen at "run-time"? If so, why will there be a compiler error like this?
If the binding doesn't happen at "run-time", why was "Objective-C" called "dynamic typing language"?
Does anyone have any ideas about this?
One job of a compiler is to catch as many errors at compile time as possible. If it can tell that the call will fail at runtime, you generally want it to complain.
You can suppress this via casting to show that runtime resolution is happening:
[(id)brad sayHelloTest];
Because the IDE can infer the obvious error from the context.
When you write if (a = 1),you will get a warning. A good IDE should help you find mistakes as early as possible.
I figured out the reason finally..
It throw errors during compiling because -Werror flag is included, which will turn warning into error..
http://clang.llvm.org/docs/UsersManual.html#cmdoption-Werror
After I delete -Werror flag, everything works as expected and the error only happens at run-time.
It has become a compiler error only within the last five years for there to be no known declaration of a method. It has to do with Automatic Reference Counting. Under ARC, the compiler is now responsible for the reference-counting-based memory management that Cocoa uses.
Given that responsibilty, it must be able to see the declarations of methods for any messages before they are sent, so that it knows what retains and releases are appropriate.
The method resolution (the lookup of the method on the class) does still happen at runtime, and -- particularly if you disable ARC -- you can still take advantage of message forwarding.
One way around ARC's requirement was given by Marcelo Cantos -- cast the receiver to id. Another is to use performSelector:. A third -- though I can't recommend it -- is to use objc_msgSend() directly.
Note that the "binding" of the method does, and always did, happen at compile time. Methods are associated with classes, when the classes are defined. Messages are distinct from methods, and it is they that resolve at runtime to a method.

order of methods in objective C

Does it matter how I order my methods in objective-C (mainly in the implementation file)?
#implementation UDDPlayerDetailsViewController
- (IBAction)cancel:(id)sender
{
[self.delegate playerDetailsViewControllerDidCancel:self];
}
-(IBAction)done:(id)sender
{
[self.delegate playerDetailsViewControllerDidSave:self];
}
so in a situation like this, it obviously does not matter which one(either cancel or done) i place first but im wondering if this holds true for all methods? Does the compiler just read through everything and then takes action or are there circumstances where placing one ahead of another in the file will have different results?
The order of methods does not matter, both in the #implementation and in the #interface sections.
In the #interface section it does not matter because there is no dependencies between methods there,
In the #implementation section it does not matter, because the #interface section (perhaps in combination with the class extension #interface) has listed all methods for the compiler, providing their signatures and removing potential ambiguities
Finally, the compiler lets you define completely "private" methods in the implementation section itself. The compiler is smart enough to look ahead for these added methods.
It used to matter, but it doesn't any more. That is because of the compiler, not the language.
It used to be that you had to declare a method before using it. Thus, if you had
-(void) methodA;
{
[self methodB];
}
-(void) methodB;
{
//Do stuff
}
You would get a warning that methodB was not defined.
If methodB was declared in your #interface you were fine.
Newer versions of the Clang compiler are able to handle forward references. I don't remember exactly which version of Xcode included this change. Xcode 4.6, maybe?
I know of no situation where it matters in Objective-C. In regular C, you need to declare methods before using them, so
void usesUndeclared() {
undeclaredFunction();
}
void undeclaredFunction() {}
will be an error, but
void undeclaredFunction;
void usesUndeclared() {
undeclaredFunction();
}
void undeclaredFunction() {}

When to declare Class Extension Methods

I've made use of Class Extensions in the .m as a way to have "private" methods and variables. I've read that since Xcode 4.4, the compiler no longer needed the private methods declared.
For example this would compile even though helperMethodC is not declared:
in .h
#interface MyClass : NSObject
-(void)publicMethodA;
#end
in .m
#interface MyClass ()
- (void) pseudoPrivateMethodB;
#end
#implementation MyClass
- (void)publicMethodA
{
//Do Something
}
- (void)pseudoPrivateMethodB
{
[self helperMethodC];
}
- (void) helperMethodC
{
// Do something
}
While private methods no longer have to be declared to compile (helperMethodC), is there a style guide, historical reason, or rule that all private methods (i.e. helperMethodC) should still be declared? Or a "rule" for when to declare and not declare private methods?
Declare them if they help you. From a documentation point of view they are very useful. The compiler will also tell you if you have specified that a method will exist and then not implemented it. There is no rule, but its a good idea to add them. Consider how you'll feel if you have to come back in 6 months and edit the class - will having the methods listed there help you?
While private methods no longer have to be declared to compile (helperMethodC), is there a style guide, historical reason, or rule that all private methods (i.e. helperMethodC) should still be declared? Or a "rule" for when to declare and not declare private methods?
There are multiple conventions, but no standard.
You really should have them when/if you need to support older toolchains -- GCC or older versions of Clang.
Once that restriction is removed, I think it's best if you just phase the (redundant) declarations out where they are not needed. High warning levels and ARC semantics can guide you here.
If you introduce types:
Something * s = [array objectAtIndex:i];
s.string = #"string";
// rather than: [array objectAtIndex:i].string = #"string";
And name your selectors uniquely for the parameter/return types:
// BAD: May be ambiguous.
// Solution: Choose a more descriptive selector name.
// class A
- (void)setX:(int)x;
// class B
- (void)setX:(double)x;
then the compiler can inform you of ambiguities.

Resources