Objective-C: How Can Class call global method safely? - objective-c

I have tried and got "SIGBRT" exception.
In Global.m, I have methodBGlobal().
In ClassA, I included Global.h in order to use methodGlobal().
ClassA.methodA() has methodGlobal() in it.
Then I have button in Global.m. Since I do not know how to call methodGlobal() properly in Global.m. SO I call the methodGlobal() through ClassA instance.
[mybutton addTarget:ClassA instance action:#selector(methodA:) ...];
It does not work. I got "SIGBRT" exception and I do not know that methodGlobal() in ClassA.methodA() was called or not? I want methodGlobal to work.

Two things you need to consider here.
If the method is a class method, then the target should be [ClassA class].
If the method signature doesn't include any arguments , for ex., -(void) methodA; then, there should be not colon(":") included in the #selector. So, the selector should be just #selector(methodA).
Finally the addTarget: method should look like,
[mybutton addTarget:[ClassA class] action:#selector(methodA) ...];
References:
Target-Action from Cocoa Application Competencies for iOS.
The Target-Action Mechanism from Cocoa Fundamentals Guide.

you can do this by making class method like + (void) doAction now you can use this method with the class name like [ClassName doAction]

Try this :
[mybutton addTarget:[ClassA class] action:#selector(methodA:) ...];

Related

how to call a method from a class in another class

I'm working to a new app for mac osx where i'm using a drag and drop system to let the user to input some files [this part works well] and i have a tabelView where i would like to display the paths of files inputed.
I have the next method in tabelViewController.m:
-(void)add{
NSLog(#"da");
[list addObject:[[Source alloc] init]];
[tableView reloadData];
}
In the DropView.m i included the tabelViewController.h and i'm trying to call the add method but it does nothing:
#import "TableViewController.h"
.....
- (void)concludeDragOperation:(id<NSDraggingInfo>)sender{
[self setNeedsDisplay:YES];
TableViewController *tvc;
[tvc add];
}
Can someone to figure out why it doesn't do anything ?
Edit1:
Ok after I fallow the answers, my concludeDragOperation method looks like this:
- (void)concludeDragOperation:(id<NSDraggingInfo>)sender{
[self setNeedsDisplay:YES];
TableViewController *tvc = [[TableViewController alloc] init];
[tvc add];
[tvc rD];
}
rD is a method from tableViewController which contain the reloadData method.
But it doesn't want to work it don't reload the table view.
Any ideea ???
tvc needs to point to an actual object. [[tvc alloc] init]
Otherwise you are simply calling add on nil. This doesn't cause your program to crash as you might expect in other languages. Try it out and see what happens.
it seems as if you missed a great chunk regarding how OOP and Objective-C work (seriously, no offense there).
What link is there between DropView.m and tableViewController.h do you have?
By typing TableViewController *tvc; all you are doing is creating a pointer. You are neither creating an object nor pointing to an object, you have just simply created a pointer that can eventually point to an object in memory of type tableViewController.
Solution:
What you will need to do, is to somehow create a link between the two classes. For instance, you could create a custom delegate method for DropView that could communicate with any class who uses that custom DropViewDelegate methods. So, you could create a delegate method that tells objects that follow that delegate protocol that you just concluded a drag operation. A tutorial how to do so can be found at my blog [it's a permalink].
I am happy to post code, or you can read it on my blog. Good Luck.

Objective C custom class methods not being called

So I have this custom class with just a test method that does nslog. I am going to reuse this method many times in my app. The interface looks like this.
#interface TestViewController: UIViewController { CMImageMover * imageMover }
Then in the view did load I:
imageMover = [[CmImageMover alloc] init];
If I do:
[imageMover testMethod];
Right after the alloc and init it works in the viewDidLoad function but if I call it again from another function in the view controller nothing works and the class method does not get called.
What am I doing wrong here. Every other var I declare like NSArray/NSTimer, I do the say way and I am able to access and use it throughout my controller.
When you say "if I call it again from another function in the view controller nothing works" then first thing to check is what you are sending the testMethod. It could be nil, in which case nothing will happen. In objective C sending a message to nil does nothing. Add an NSLog to find out, e.g.
NSLog(#"imageMover object is: %#", imageOver);
[imageMover testMethod];
If the NSLog shows it is nil - or something crazy - then follow up what you are doing with the imageMover ivar.
You mention a class method in your question, but don't refer to it in your code snippets.
If you have defined testMethod as a class method it will, of course, fail if you send that message to an instance. (And it will fail noisily.) A class method would be introduced like this:
+ (void) testMethod
{
NSLog(#"CMImageMover testMethod called on Class");
}
An instance method would be introduced like this:
- (void) testMethod
{
NSLog(#"testMethod called on an instance of CMImageMover");
}
Apologies if this is all screamingly obvious to you and missing the point of the question. It's not that clear from your question where the issue lies.

Objective-C call function on another class?

Here are my objective-c classes:
AppDelegate
SomeScript
How might I call the function loggedIn on the SomeScript class from the app-delegate or any other class?
Thanks,
Christian Stewart
(I'll assume loggedIn is an instance method taking no parameters.) First, several terminology issues:
They're not functions, they're methods (same idea, though).
You don't call methods, you send messages (usually same idea, though).
Most importantly, we usually send messages not to classes, but to instances of those classes. (If you can't visualize the difference, imagine placing a letter in the idea of mailboxes vs. placing a letter in your mailbox. Only one makes sense!)
So, our new plan is to first instantiate SomeScript, then send a message to the instance.
SomeScript* myScript = [[SomeScript alloc] init]; //First, we create an instance of SomeScript
[myScript loggedIn]; //Next, we send the loggedIn message to our new instance
This is good. However! I bet you want your script to stick around for later use. Thus, we should really make it an instance variable of your app delegate. So, instead, in AppDelegate.h, add this inside the braces:
SomeScript* myScript;
Now our variable will stick around, and our first line from before becomes simply:
myScript = [[SomeScript alloc] init];
Last complication: we don't want to create a new script every time we call loggedIn (I assume)! So, you should place the instantiation somewhere it will only be run once (for example, application:DidFinishLaunchingWithOptions:). Ta-da!
You shall have an initialized reference of a SomeScript object in your AppDelegate class (supposing you do not need SomeScript to be a Singleton class like your AppDelegate). Something like:
SomeScript * myScript;
as an ivar in your AppDelegate interface, while in its application:DidFinishLaunchingWithOptions:
you have inited it (let's suppose with the default alloc/init combo calling):
myScript = [[SomeScript alloc] init]
Done all of this, when you need to call a method of myScript you can simply do:
[myScript myMethod:myParameter]
Here you can find a nice guide for beginners from Apple
If you don't want to use instances of SomeScript ... you can follow a different approach. Use NSNotificationCenter for sending a notification to your SomeScript object and make it run a selector after that.
In your -(void)awakeFromNib{} method, from SomeScript place the following code :
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(mySelector:)
name:#"aUniqueNameForTheNotification"
object:nil];
Create the method "mySelector:" and place the the call to your loggedIn method. (Or if you prefer, you could replace "mySelector:" with loggedIn directly)
-(void) mySelector:(id)elem
{
[self loggedIn];
}
Then don't forget to remove the observer on dealloc, so place the following piece of code in your SomeScript class also :
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
Then you can send a notification from any other like so :
[[NSNotificationCenter defaultCenter] postNotificationName:#"aUniqueNameForTheNotification" object:self];
That last piece of code sends a notification to SomeScript and your selector is executed.
Hope it helps you guys!
We can call it like [self loggedIn] When loggedIn method is in SomeScript class, using simple syntaxes in latest xcode.
[[SomeScript new] loggedIn];

call method in different from #selector in Objective-C

How do we call a method which is in classB from #selector tag of classA.??
Can i do it in this way??
[tis_obj authenticate:self action:#selector([classB method]:)
accName:#"BOOK" User:#"User"];
Is there a possibility to call a method of different class form#selector tag?? or should the method be always in same class?
Thank You.
No you can't. To call a -[classB method:], the authenticate: parameter must have a classB instance, e.g.
classB* b = [[clasB alloc] init];
[tis_obj authenticate:b action:#selector(method:) …];
self.b = b;
[b release];
It looks like you want tis_obj to use the method selector on classB. I'm not sure what tis_obj is, but I see you're passing an argument self there. Perhaps what you're really looking for is:
[tis_obj authenticate:classB
action:#selector(method:)
accName:#"BOOK"
User:#"User"];
This will presumably mean that tis_obj will at one point perform the equivalent of [classB method:someArg].
A selector is just a name. The selector in the method call [someObject foo:5] is just foo:. It doesn't specify a method or a receiver, just the name.
What you pass to #selector() doesn't have a class name. A selector definition is simply a method name, so this will work:
[tis_obj authenticate:self action:#selector(method:)
accName:#"BOOK" User:#"User"];
(if "method:" is defined on your class of course)

Overriding / Swizzling methods from an existing shared delegate

Is it possible to override ONLY CERTAIN functions from an exisiting delegate, without ourself being a delegate totally?
I tried replacing the target IMP with mine, didn't work :'(
More detail:
+[SomeClass sharedDelegate]
-[sharedDelegate targetMethodToBeOverridden:Arg:] //OUR method needs to be called, not this
Method *targetMethod; // targetMethodToBeOverridden identified by class_copymethodlist magic
targetMethod->method_imp = [self methodForSelector:#selector(overriddenDelegateMethod:Arg:)];
NOT WORKING! My Method is not being called :(
You probably shouldn't be manipulating the Method struct directly. Use the runtime function instead. You'll need to #import the runtime header, but there's a nice method in there called method_setImplementation. It'll work something like this:
id targetObject = [SomeClass sharedDelegate];
Method methodToModify = class_getInstanceMethod([targetObject class], #selector(replaceMe:argument:));
IMP newImplementation = [self methodForSelector:#selector(overriddenDelegateMethod:Arg:)];
method_setImplementation(methodToModify, newImplementation);
This may not work for your specific case, since class_getInstanceMethod might not return the Method for a method defined by an adopted protocol, but this is the "proper" way to swizzle Method IMPs.