I've been trying to use a UIButton
action to call a method in a different class (AppViewController). I first tried creating an instance of the view controller in the UIButton's
calling class (caller.m)
and then calling the method, but that kept resulting in EXC_BAD_ACCESS.
I'm realizing I need to point to the same instance of the view controller and am now trying to make sure the view controller instance is properly declared in caller.m.
I have a declaration of AppViewController *viewController
in the AppDelegate
, so my thought is to refer to that same instance from caller.m
.
#import "caller.h"
#import "AppDelegate.h"
@implementation caller
- (id)initWithFrame:(CGRect)frame {
...
[btnSplash addTarget:viewController action:@selector(loadSplashView) forControlEvents:UIControlEventTouchUpInside];
....
}
However, viewController still shows up as undeclared. I tried a few other things, but know I'm probably missing something basic.
::::UPDATE::::
Okay, so it turns out I needed to create the following so the target "viewController" was actually declared and pointing to the correct instance:
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
AppViewController* viewController = appDelegate.viewController;
The method in the view controller class is now being properly called.
For a more clearly explained and more general version of this question, go here: Objective-c basics: Object declared in MyAppDelegate not accessible in another class
There are multiple ways for objects to initiate actions, communicate with other objects and/or observe changes they are interested in including:
I don't think notifications are what you want in this case. Notifications are most appropriate when the object posting the notification does not care what object(s) are observing the notification and there can be one or more observers. In the case of a button press you would typically only want a specific object to handle the action.
I would recommend using a protocol. You'll see lots of protocols in use in the iOS frameworks, basically any class that has a delegate
property usually defines a protocol that delegate objects need to conform to. The protocol is a contract between the two objects such that the object defining the protocol knows that it can communicate with the object conforming to the protocol with out any other assumptions as to its class or purpose.
Here's an example implementation. Apologies if any typos/omissions.
In caller.h (I assumed caller is a UIViewController):
@class Caller
@protocol CallerDelegate
- (void)userDidSplashFromCaller:(Caller *)caller;
@end
@interface Caller : UIViewController
id <CallerDelegate> delegate;
@end
@property (nonatomic, assign) id <CallerDelegate> delegate;
@end
In caller.m:
@implementation Caller
@synthesize delegate;
- (void)viewDidLoad {
// whatever you need
// you can also define this in IB
[btnSplash addTarget:self forAction:@selector(userTouchedSplashButton)];
}
- (void)dealloc {
self.delegate = nil;
[super dealloc];
}
- (void)userTouchedSplashButton {
if (delegate && [delegate respondsToSelector:@selector(userDidSplashFromCaller:)]) {
[delegate userDidSplashFromCaller:self];
}
}
in otherViewController.m:
// this assumes caller is pushed onto a navigationController
- (void)presentCaller {
Caller *caller = [[Caller alloc] init];
caller.delegate = self;
[self.navigationController pushViewController:caller animated:YES];
[caller release];
}
// protocol message from Caller instance
- (void)userDidSplashFromCaller:(Caller *)caller {
NSLog(@"otherVC:userDidSplashFromCaller:%@", caller);
}
[EDIT: CLARIFICATIONS]
I realized after looking at your question and code again that I made some assumptions that may not be true in your code. You most likely should still use a protocol but the exact way to integrate my example depends on your app. I don't know what class Caller
is in your app but whatever it is, it is dealing with UIButtons so it is most likely a view controller or a view.
Your comment about not having the correct instance of your appViewController makes me wonder if you understand the difference between classes and instances of a class. If my answer doesn't help you, please post some more code showing how you create and present your view controller as well as how you are configuring the button and I can try to clarify my answer.
You should post a NSNotification when clicking the button that will be caught and executed in the AppViewController.
So this should be: In the sender class:
[btnSplash addTarget:self
action:@selector(loadSplashView)
forControlEvents:UIControlEventTouchUpInside];
-(void)loadSplashView:(id)sender
{
[[NSNotificationCenter defaultCenter] postNotificationName:@"notif_name" object:some_sender_object];
}
In the target class: Register to get the notification at view's load:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(some_function:) name:@"notif_name" object:nil];
Define the action to take in this class:
-(void) some_function:(NSNotification *)notif {
//do something
// to access the object do: [notif object]
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With