Objective-C passing methods as parameters - iphone

How do you pass one method as a parameter to another method? I'm doing this across classes.
Class A:
+ (void)theBigFunction:(?)func{
// run the func here
}
Class B:
- (void)littleBFunction {
NSLog(#"classB little function");
}
// somewhere else in the class
[ClassA theBigFunction:littleBFunction]
Class C:
- (void)littleCFunction {
NSLog(#"classC little function");
}
// somewhere else in the class
[ClassA theBigFunction:littleCFunction]

The type you are looking for is selector (SEL) and you get a method's selector like this:
SEL littleSelector = #selector(littleMethod);
If the method takes parameters, you just put : where they go, like this:
SEL littleSelector = #selector(littleMethodWithSomething:andSomethingElse:);
Also, methods are not really functions, they are used to send messages to specific class (when starting with +) or specific instance of it (when starting with -). Functions are C-type that doesn't really have a "target" like methods do.
Once you get a selector, you call that method on your target (be it class or instance) like this:
[target performSelector:someSelector];
A good example of this is UIControl's addTarget:action:forControlEvents: method you usually use when creating UIButton or some other control objects programmatically.

Another option is to look at blocks. It allows you to pass a block of code (a closure) around.
Here's a good write up on blocks:
http://pragmaticstudio.com/blog/2010/7/28/ios4-blocks-1
Here's the apple docs:
http://developer.apple.com/library/ios/#documentation/cocoa/Conceptual/Blocks/Articles/00_Introduction.html

Objective C makes this operation relatively easy. Apple provides this documentation.
To directly address your question, you are not calling a function, but a selector. Here is some sample code:
Big Function:
+ (void)theBigFunction:(SEL)func fromObject:(id) object{
[object preformSelector:func]
}
Then for class B:
- (void)littleBFunction {
NSLog(#"classB little function");
}
// somewhere else in the class
[ClassA theBigFunction:#selector(littleBFunction) fromObject:self]
Then for class C:
- (void)littleCFunction {
NSLog(#"classC little function");
}
// somewhere else in the class
[ClassA theBigFunction:#selector(littleCFunction) fromObject:self]
EDIT: Fix selectors sent (remove the semicolon)

You can use Blocks for this purpose. http://developer.apple.com/library/ios/#documentation/cocoa/Conceptual/Blocks/Articles/00_Introduction.html

Related

D: Delegates or callbacks?

I found conception of Delegates pretty hard for me. I really do not understand why I can't simply pass one function to another and need to wrap it to Delegate. I read in docs that there is some cases when I do not know it's name and Delegate is only way to call it.
But now I have trouble in understanding conception of callbacks. I tried to find more information, but I can't understand is it's simply call of other function or what is it.
Could you show examples of D callbacks and explain where they can be helpful?
import vibe.d;
shared static this()
{
auto settings = new HTTPServerSettings;
settings.port = 8080;
listenHTTP(settings, &handleRequest);
}
void handleRequest(HTTPServerRequest req,
HTTPServerResponse res)
{
if (req.path == "/")
res.writeBody("Hello, World!", "text/plain");
}
&handleRequest is it callback? How it's work and at what moment it's start?
So within memory a function is just a pile of bytes. Like an array, you can take a pointer to it. This is a function pointer. It has a type of RETT function(ARGST) in D. Where RETT is the return type and ARGST are the argument types. Of course attributes can be applied like any function declaration.
Now delegates are a function pointer with a context pointer. A context pointer can be anything from a single integer (argument), call frame (function inside of another) or lastly a class/struct.
A delegate is very similar to a function pointer type at RETT delegate(ARGST). They are not interchangeable, but you can turn a function pointer into a delegate pointer pretty easily.
The concept of a callback is to say, hey I know you will know about X so when that happens please tell me about X by calling this function/delegate.
To answer your question about &handleRequest, yes it is a callback.
You can pass functions to other functions to later be called.
void test(){}
void receiver(void function() fn){
// call it like a normal function with 'fn()'
// or pass it around, save it, or ignore it
}
// main
receiver(&test); // 'test' will be available as 'fn' in 'receiver'
You need to prepend the function name as argument with & to clarify you want to pass a function pointer. If you don't do that, it will instead call that function due to UFCS (calling without braces). It is not a delegate yet.
The function that receives your callable may do whatever it wants with it. A common example is in your question, a web service callback. First you tell the framework what should be done in case a request is received (by defining actions in a function and making that function available for the framework), and in your example enter a loop with listenHTTP which calls your code when it receives a request. If you want to read more on this topic: https://en.wikipedia.org/wiki/Event_(computing)#Event_handler
Delegates are function pointers with context information attached. Say you want to add handlers that act on other elements available in the current context. Like a button that turns an indicator red. Example:
class BuildGui {
Indicator indicator;
Button button;
this(){
... init
button.clickHandler({ // curly braces: implicit delegate in this case
indicator.color = "red"; // notice access of BuildGui member
});
button.clickHandler(&otherClickHandler); // methods of instances can be delegates too
}
void otherClickHandler(){
writeln("other click handler");
}
}
In this imaginary Button class all click handlers are saved to a list and called when it is clicked.
There were several questions in the OP. I am going to try to answer the following two:
Q: Could you show examples of D callbacks and explain where they can be helpful?
A: They are commonly used in all languages that support delegates (C# for an example) as event handlers. - You give a delegate to be called whenever an event is triggered. Languages that do not support delegates use either classes, or callback functions for this purpose. Example how to use callbacks in C++ using the FLTK 2.0 library: http://www.fltk.org/doc-2.0/html/group__example2.html. Delegates are perfect for this as they can directly access the context. When you use callbacks for this purpose you have to pass along all the objects you want to modify in the callback... Check the mentioned FLTK link as an example - there we have to pass a pointer to the fltk::Window object to the window_callback function in order to manipulate it. (The reason why FLTK does this is that back FLTK was born C++ did not have lambdas, otherwise they would use them instead of callbacks)
Example D use: http://dlang.org/phobos/std_signals.html
Q: Why I can't simply pass one function to another and need to wrap it to Delegate?
A: You do not have to wrap to delegates - it depends what you want to accomplish... Sometimes passing callbacks will just work for you. You can't access context in which you may want to call the callback, but delegates can. You can, however pass the context along (and that is what some C/C++ libraries do).
I think what you are asking is explained in the D language reference
Quote 1:
A function pointer can point to a static nested function
Quote 2:
A delegate can be set to a non-static nested function
Take a look at the last example in that section and notice how a delegate can be a method:
struct Foo
{
int a = 7;
int bar() { return a; }
}
int foo(int delegate() dg)
{
return dg() + 1;
}
void test()
{
int x = 27;
int abc() { return x; }
Foo f;
int i;
i = foo(&abc); // i is set to 28
i = foo(&f.bar); // i is set to 8
}
There are already excellent answers. I just want to try to make simple summary.
Simply: delegate allows you to use methods as callbacks.
In C, you do the same by explicitly passing the object (many times named context) as void* and cast it to (hopefully) right type:
void callback(void *context, ...) {
/* Do operations with context, which is usually a struct */
doSomething((struct DATA*)context, ...);
doSomethingElse((struct DATA*)context, ...);
}
In C++, you do the same when wanting to use method as callback. You make a function taking the object pointer explicitly as void*, cast it to (hopefully) right type, and call method:
void callback(void* object, ...) {
((MyObject*)object)->method(...);
}
Delegate makes this all implicitly.

Objective-C singleton only responds to class methods

I have a singleton class that is instantiated as follows:
#import "FavoritesManager.h"
static FavoritesManager *sharedFavoritesManager = nil;
#implementation FavoritesManager
+ (id)sharedManager {
#synchronized(self) {
if (sharedFavoritesManager == nil) {
sharedFavoritesManager = [[self alloc] init];
}
}
return self;
}
This returns an object, but for some reason it will only respond to class methods. If I call a instance method I get
+[FavoritesManager testMethod]: unrecognized selector sent to class 0x59198
For what it's worth, this is what testMethod looks like:
- (void)testMethod {
NSLog(#"Test");
}
and I'm absolutely positive it's declared in the interface. I've used this exact code in other classes and it works like a charm, so I don't really understand what the problem is here. One thing that is suspicious is the plus sign in +[FavoritesManager testMethod], but I can't explain it. Any ideas?
EDIT: I was confusing public/private and class/method terminology. Thanks to everyone who pointed that out.
If you want to call testMethod from another class method then you need:
+ (void)testMethod {
NSLog(#"Test");
}
The reason is that if you call a class method then there's no instance, so nothing on which to call instance methods. But probably you want to call:
[[FavoritesManager sharedManager] testMethod];
Which means 'get the shared instance, then call testMethod on it'. Thinking as I type, you might also like to add:
+ (void)forwardInvocation:(NSInvocation *)anInvocation
{
id sharedManager = [self sharedManager];
if ([sharedManager respondsToSelector:
[anInvocation selector]])
[anInvocation invokeWithTarget:sharedManager];
else
[super forwardInvocation:anInvocation];
}
Which is the Objective-C means for message forwarding. So if the metaclass FavoritesManager receives a message it can't respond to, it lets its shared manager instance have a go. That means that:
[FavoritesManager testMethod];
Becomes functionally equivalent to (though a little slower than):
[[FavoritesManager sharedManager] testMethod];
Providing that you haven't implemented a class method in addition to an instance method. You can learn more about message forwarding in Apple's official documentation.
The error indicates that you're sending the message testMethod to the class, rather than an instance.
The reason for this is that your sharedManager method is incorrect. You are currently returning self, which, in this class method, is the class itself. This means that when you write [[FavoritesManager sharedManger] testMethod] you end up sending testMethod to the class. Since testMethod isn't a class method, you get an error.
You should have return sharedFavoritesManager; at the end of sharedManager, not return self;. The latter is correct only in instance method initializers.
Also, as dbrajkovic commented, you seem to be confused about public/private and class/instance methods. Strictly, ObjC has no private methods. You can hide the declaration, which will cause a compiler warning, but the message will still be sent and the method will be called. The + and - distinguish class methods from instance methods; the distinction is which kind of object you send a message to. Info here: What is the difference between class and instance methods?
The error is right you must be calling [FavoritesManager testMethod] which means you're trying to call a class method. I believe you want [[FavoritesManager sharedManager] testMethod];
+ at the start of a method declaration means that it's a class method, - means that it's an instance method. Do this:
+(void)testMethod {
NSLog(#"Test");
}
If you want to invoke testMethod on your sharedManager, then keep the testMethod declaration as you have it and instead change your invocation to
[[FavoritesManager sharedFavoritesManager] testMethod];
Either will work, and choosing between the two is a matter of app design.
Instead try
[[FavoritesManager sharedFavoritesManager] testMethod];
there are no priavte methods in obj-c.
But anyway on a singleton you are always calling from the outside of the class, so only declare "public methods". for detailed help post your code.
Call your singleton instance:
[[ FavoritesManager sharedManager] testMethod];

Objective-C Runtime: How to remove a method from a class?

In the Objective-C Runtime Reference, I see class_addMethod but not class_removeMethod. How do I dynamically remove a method?
Also, does class_addMethod add an instance method or a class method?
As Inerdial mentioned in his comment, the main question (How can a method be removed from a class at runtime?) is somewhat exhaustively answered here.
MattDiPasquale asks as well:
Also, does class_addMethod add an instance method or a class method?
Inerdial is correct again:
class_addMethod adds an instance method, and that to add a class method, you need to add an instance method to the class' class.
Given a Class c, we can get our hands on the class of which it is an instance (known as its "metaclass") as simply as
Class metac = object_getClass(c);
To then "add a class method" to c, we add a method to metac using class_addMethod.
If, for example, elsewhere we have already defined
id myClassMethodImplementation(id self, SEL _cmd) {
//implementation
}
We can then add a class method to c as follows:
BOOL success = class_addMethod(metac, #selector(myClassMethod), (IMP)myClassMethodImplementation, "##:");
or equivalently
BOOL success = class_addMethod(object_getClass(c), #selector(myClassMethod), (IMP)myClassMethodImplementation, "##:");
To simply add this same method as an instance method on c, we simply write
BOOL success = class_addMethod(c, #selector(myClassMethod), (IMP)myClassMethodImplementation, "##:");
References:
1. Objective-C Runtime Reference 2. Objective-C Runtime Programming Guide - Type Encodings 3. Cocoa with Love - What is a meta-class in Objective-C?

Objective-C - Access method from other controller

i have a little question about getting access to a method in another controller, nu i am trying this.
So for example i have the controller A and B. In the controller A i have programmed a method, now i want to get access this through controller B.
What i have done in class A in the header file:
+(void)goBack;
and in the implementation file:
+(void)goBack {
NSLog(#"go back");
}
in the controller B i do this to get access to the method in controller A:
+(void)goPreviousArticle:(id)sender {
ViewProductInformation_ViewController *theInstance = [[ViewProductInformation_ViewController alloc] init];
[theInstance goBack];
}
However when i execute the program, then it does not work, the program just shuts down, when i do command click on the function goBack in controller B i get referred to the method in controller A.
Does anybody have an idea what the problem could be?
thanks in advance,
snowy
It's quite easy ... you just mixed the class and instance-method declaration: The "+" sign indicates that the method is a class method. In your case it should be a "-" so
-(void)goBack; // a instance method declaration!
Hope this helps.
Class vs instance method declaration ... see also What is the difference between class and instance methods?
You are declaring goBack as a CLASS method (with the preceding "+"). Change the + to a -.
Since goBack is a static method of Class A, you don't need an instance of A to call it's method, you can just call it like so:
[ClassA goBack];
You don'y need to declare static functions you can writ like this:
-(void)goBack {
NSLog(#"go back");
}
In the class A and same in the class B:
-(void)goPreviousArticle:(id)sender {
ViewProductInformation_ViewController *theInstance = [[ViewProductInformation_ViewController alloc] init];
[theInstance goBack];
}
Then use them. I think in that case application will not crashed.

iPhone Int with NSObject &/causes class can't reference itself

I've got a function called updateTheValue() that I have called using [self updateTheValue] for a while now. Two things happened recently; I added the method calling in the viewDidLoad() method and it spit out a warning saying my class may not respond to this. Second, I want to pass objects to updateTheValue() like strings, but mostly ints, so I declared an NSObject to pass into the method. Can an int fit into an NSObject slot, or what should I use instead?
I would have posted these seperately but they seem to be related since after updating updateTheValue() to accept an NSObject every reference to this function turns out the error that my class "May not respond to -updateTheValue"
You could make your method like this:
-(void)updateTheValue:(NSObject *)anObject
// or use -(void)updateTheValue:(id)anObject
{
if ([anObject isKindOfClass:[NSString class]]) {
// Do your string handling here
}
else if ([anObject isKindOfClass:[NSNumber class]]) {
// Do your number handling here
}
}
Use it like this:
[self updateTheValue:[NSNumber numberWithInt:42]];
I'd suggest doing two different methods though, i.e. updateTheValueWithInt: and updateTheValueWithString: making it easier to read and understand.
Make sure you make the method signature visible before using them, so that the compiler knows what this does.
If you use separate methods you can use int directly without wrapping them into NSNumber objects.
First problem:
updateTheValue() must be declared before you try to call it.
You can either move the definition of function before the calls to it, or add a prototype at the top - eg, add:
(void) updateTheValue;
near the top.
Second problem:
Use an NSNumber, eg [NSNumber numberWithInt:45];