#selector to a function in a separate class - iphone

If I have a function that is defined in class Foo, and my class Bar has a reference to class Foo, can I use the #selector to call that function? Something like
#selector([Foo someFunctionInFoo:])
I have only used the #selector to call functions in the same class. I tried doing something similar to the above code, but it didn't work and I wasn't sure if it was even possible. Thanks.

#selector doesn't store any calls information, just the selector.
[Foo performSelector:#selector(someFunctionInFoo:) withObject:nil];
You can also do:
Class class = SomeClass;
id obj = [class someObject];
SEL sel = #selector(someFunction);
[class performSelector:sel];
[obj performSelector:sel];
As long as both implement someFunction.
To specify which target is used by buttons etc you set the target and the action as two properties, e.g.:
[[UIBarButtonItem alloc] initWithTitle:#"Filter"
style:UIBarButtonItemStyleBordered
target:foo // The object to send the message to
action:#selector(someFunctionInFoo:)]; // The message to send

Related

Objective-c Is super init a class method or instance method?

I am new in objective c. I understand that -init() is an instance method and return an object
e.g. myObj=[myObj init]; will return an object myObj.
However, if self =[super init]; normally super refer to parent class e.g. NSObject which is a class, not instance.
So, Is -init() instance method or class method for super init?
thanks
init is an instance method. The fact that you call it on super does not change it.
Keep in mind that super does not represent the class of your object, but your object seen as an instance of its parent class in the class hierarchy.
And you never call myObj=[myObj init]; — you call myObj = [[MyObj alloc] init]. Notice the case difference between myObj (a variable) and MyObj (the class of which this variable is an instance).
Generally init is used after alloc in this way:
MyObject* obj = [[MyObject alloc] init];
and alloc create the object instance, so init is an instance method, and when you override it, it's good habit to call always the parent class init.
Try to read this article.
Super is referring to the methods of the parent class in the current object. Calling super init will call the method init on the current object (self), but will use the implementation of the super class. So no - init is not a static method (this would be visible due to a + before the init method). you can call super whatMethodYouWantFromSuperclass even though it is not static. Static methods are not called on an object (self) but on a class ([NSObject yourStaticMethod]).

Return customized UIButton in method?

I have a method that takes a UIButton, modifies its properties and returns a UIButton. However, it doesn't ever seem to be initialized. I'm sure I'm doing something wrong with the memory management here, but don't exactly know how to fix it. No runtime errors occur.
It is called like so...
newGameBtn = [self customButtonFromButton:newGameBtn
withText:[NSString stringWithFormat:#"NEW GAME"]
withFontSize:22
withBorderColor:[UIColor orangeColor]
isSilent:YES];
[dashboardContainer addSubview:newGameBtn];
The method is defined as follows...
- (UIButton*) customButtonFromButton:(UIButton*)button withText:(NSString*)text withFontSize:(int)fontSize withBorderColor:(UIColor*)borderColor isSilent:(BOOL)isSilent {
button = [[[UIButton alloc] init] autorelease];
// Set properties from parameters
// Other conditional custom stuff here
return button;
}
NOTE: newGameBtn is of type UIButton* and is initialized with:
newGameBtn = [[UIButton buttonWithType:UIButtonTypeCustom] retain];
Another option might be to subclass UIButton, but I figured I'd try to fix this since I've already walked down this path.
You should use +[UIButton buttonWithType:] when creating buttons to get a properly initialized button.
Most classes are not properly initialized by the default -[NSObject init] method. So please look at the class reference, or superclass reference, for a usable initialization method.
In this case you should also set a frame.
You don't modify this button with your method, you're creating a completely new one with alloc-init!
If you want to change the button in your first argument just remove the first line of your method

How do I call methods in a class that I created dynamically with NSClassFromString?

The reason I am doing dynamic class loading is because I am creating a single set of files that can be used across multiple similar projects, so doing a #import and then normal instantiation just won't work. Dynamic classes allows me to do this, as long as I can call methods within those classes. Each project has this in the pch with a different "kMediaClassName" name so I can dynamically load different classes based on the project I'm in:
#define kMediaClassName #"Movie"
Here is the code I am using to get an instance of a class dynamically:
Class mediaClass = NSClassFromString(kMediaClassName);
id mediaObject = [[[mediaClass alloc] init] autorelease];
Then I try to call a method within that dynamic class:
[mediaObject doSomething];
When I then type this into Xcode, the compiler shows a warning that the class doesn't have this method, even though it does. I can see it right there in my Movie.h file. What is going on? How do I call a method from a dynamically instantiated class?
And what if I need to pass multiple arguments?
[mediaObject loadMedia:oneObject moveThe:YES moveA:NO];
Thanks for the help in advance.
you can declare a protocol, like so:
#protocol MONMediaProtocol
/*
remember: when synthesizing the class, you may want
to add the protocol to the synthesized class for your sanity
*/
- (BOOL)downloadMediaAtURL:(NSURL *)url toPath:(NSString *)path loadIfSuccessful:(BOOL)loadIfSuccessful;
/* ...the interface continues... */
#end
in use:
Class mediaClass = NSClassFromString(kMediaClassName);
assert(mediaClass);
id<MONMediaProtocol> mediaObject = [[[mediaClass alloc] init] autorelease];
assert(mediaObject);
NSURL * url = /* expr */;
NSString * path = /* expr */;
BOOL loadIfSuccessful = YES;
BOOL success = [mediaObject downloadMediaAtURL:url toPath:path loadIfSuccessful:loadIfSuccessful];
Well it might be there, but the Compiler doesn't know about it because it assumes that mediaClass is just some Class object, but nothing specific. NSClassFromString() is a runtime function and thus can't give the compiler a hint at compile time about the object.
What you can do:
Ignore the warning
Use [media performSelector:#selector(doSomething)];
And btw, this is wrong:
Class mediaClass; = NSClassFromString(kMediaClassName);
it should be:
Class mediaClass = NSClassFromString(kMediaClassName);
An easier and fancier solution than NSInvocation :)
Class mediaClass = NSClassFromString(kMediaClassName);
if(mediaClass){
id mediaObject = class_createInstance(mediaClass,0);
objc_msgSend(mediaObject, #selector(doSomethingWith:andWith:alsoWith:), firstP, secondP,thirdP);
}
Explanation:
class_createInstance(mediaClass,0); does exactly the same as [[mediaClass alloc] init];
if you need to autorelease it, just do the usual [mediaObject autorelease];
objc_msgSend() does exactly the same as performSelector: method but objc_msgSend() allows you to put as many parameters as you want. So, easier than NSInvocation right? BTW, their signature are:
id class_createInstance(Class cls, size_t extraBytes)
id objc_msgSend(id theReceiver, SEL theSelector, ...)
For more info you can refer the Objective-C Runtime Reference
As Joe Blow says, NSInvocation will help you here, though NSObject has a couple of shortcut methods that you can use: -performSelector:, -performSelector:withObject:, and -performSelector:withObject:withObject:.

calling a method of current class from a method of another class

I am working on a class A which has a method -(void)DoSmthing1. I am making a call to
another method-(void)DoSmthing2 in class B. Now after doing some operations in class B, the method is supposed to call back a method-(void)DoSmthing3 previous class.
How will i call a method of current class from another class?? Can someone please help me....
Thanks in advance
edit1::
My Code:
Class A
{
-(void) MethodA {
}
-(void) MethodB {
ClassB *clsB = [[ClassB alloc] init];
[clsB MethodC];
}
}
Class B
{
-(void)MethodC:(selector) {
//here i want to call MethodA of classA, and i will prefer if it is possible by sending the name of the method as selector in this method(methodC)
}
}
edit2::
Another example i want to do smthing like follwoing:
ClassB *b = [[ClassB alloc] nitWithTarget:self selector:#selector(methodfromClassA) object:nil];
Here i want to call a method of class A once some task in Class B is completed, and that too from class A.
I hope it is much clear now.
Edit3:
- (void)loadView {
AsyncConnection *async =[[AsyncConnection alloc] init];
[async getAsync:self callback:#selector(test1)];
}
above code is from first class
-(void)getAsync:(id)anObject callback:(SEL)selector {
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:anObject
selector:#selector(selector)
object:nil];
[queue addOperation:operation];
[operation release];
}
and above code is from second class. Here i want to call a method of first class which is passed as selector.
- (void)loadView {
AsyncConnection *async =[[AsyncConnection alloc] init];
[async getAsync:self callback:#selector(test1)];
}
Other class:
-(void)getAsync:(id)anObject callback:(SEL)selector {
NSInvocationOperation *operation = [[NSInvocationOperation alloc]
initWithTarget:anObject
selector:#selector(selector)
object:nil];
[queue addOperation:operation];
[operation release];
}
First, if you want to use the above pattern, remove the #selector() from #selector(selector). You already have the selector. Doing #selector(selector) will create the SEL named selector and not the selector passed in as the argument.
Next, this seems like an odd pattern to start with; it'll work, but any experienced Obj-C/iOS/Cocoa developer will get the willies looking at it. Since you wrote the AsyncConnection class, use the delegate pattern. I.e. in the class that implements loadView.
That is, in AsyncConnection.h:
#property(retain) ClassA *callbackHandler;
And then:
- (void)loadView {
AsyncConnection *async =[[AsyncConnection alloc] init];
[async setCallbackHandler: self];
}
Then, in AsyncConnection, you would refer to the callback handler directly as self.callbackHandler (or [self callbackHandler]).
It sounds like you would benefit from reading the introductory material: The Objective-C Programming Language and Cocoa Fundamentals Guide. Additionally, you should read up on the basics of object-oriented programming (there are dozens of overviews all over the web and Amazon).
Essentially, you're confusing a class (the blueprint for creating an object, in its most basic description) and an instance of a class (an actual "instantiated" object of a given class). Somewhere you're going to have to have a reference from one instance to another (like objectB = [[ClassB alloc] init]) to send a message (like [objectB doSomethingAnObjectOfClassBWouldDo]). You might accomplish this by storing the reference as an instance variable or inside a collection (array, dictionary, etc.) that is an instance variable of the class that needs to "remember" who it needs to talk to.
It's important to realize you're trying to walk before you've learned to crawl with this platform. The only cure is to study. A lot. Guided books help.
Then new approach:
Should be something like:
classB.h
classA *aObj;
#property(nonatomic, retain) classA *aObj;
classB.m
#synthetize aObj;
classA.m
// after init class b obj
[bOjb setAObj:self];
classB.m
[aObj whateverMethodOfClassA];
Let me know if not clear.
My sugestion, is that generally if you want to avoid a real mess and a nightmare to debug, you should use observers and notifications rather than this kind of cross methods calls.
Make class A an observer of a notification of class B:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(classA-method-name:) name:#"notification-name" object:class-B-object ];
And when ready in class-B notify class A with parms:
[[NSNotificationCenter defaultCenter] postNotificationName:#"notification-name" object:self];
Just an idea.
One option is to use the delegate pattern in Objective C. Have the object of class A pass itself to an object of class B to be the handler for certain methods.

Declaring an object type in an if statement

I'm trying to declare a variable inside an if statement. If the result of a query is YES then the object will be of one type, otherwise it will be of another type. A bit like this...
if (YES) {
ObjectTypeA *object = [[ObjectTypeA] alloc] init];
}
else {
ObjectTypeB *object = [[ObjectTypeB] alloc] init];
}
Once that's done I want to use object with the same methods no matter what type it is. I tried declaring object as an id before the if statement but get an error: member reference type 'struct objc_object *' is a pointer; maybe you meant to use '->'?
I also tried declaring both to be separate objects outside the if and then make the pointer point to whichever it was once I knew. That wouldn't work either.
I know that the compiler is trying to protect me from myself by doing this but in this circumstance I need a way round it please.
Thanks.
The most common pattern for this problem in Cocoa/Cocoa Touch is to define a protocol.
A protocol is a collection of methods that can be implemented by any object.
If you make ClassA and ClassB conform to a protocol containing the methods you need them to respond to then you don't need to worry about which type of object you get.
The idea is "if it looks like a duck and quacks like a duck, then it's probably a duck".
You can use dynamic typing and create your objects depending on the outcome of your query, but ensure that the resulting object conforms to a particular protocol, like so:
id <MyProtocol> myObject;
if (YES)
myObject = [[ClassA alloc] init];
else
myObject = [[ClassB alloc] init];
[myObject myMethod];
[myObject release];
I think this code should work well:
id obj = nil;
if (YES) {
obj = [[ObjectTypeA] alloc] init];
} else {
obj = [[ObjectTypeB] alloc] init];
}
[obj performSelector:#selector(YOUR_METHOD) withObject:YOUR_OBJECT];
You want dynamic typing :)
The way around this is to declare a third object that both of these inherit from
OR
You could use the adapter pattern and create an object that accepts both of these objects as a member and then wrap the functions you wish to call into that object
good luck!
--> These are genral OO solutions; I'm not a Objective-C developer