Accessing a instance method within another view controller
I have a tab bar controller with 4 tabs. Each tab has its own view controller and a UIWebView.
Let's say I have a button (button1) in vc1 and an instance method onClick1 as well. In vc2 I have a method named reload. My question is, how do I access the specific instance method, onClick1 in vc2, from vc1?
For further detail, I'm actually 开发者_C百科trying to code a simple shopping utility for the iPhone. When a user adds an item to the cart from the browse view, I want to be able to automatically reload the cart view.
Below are some examples of what I mean. This problem has been more difficult than I thought. I'm not sure if I have redesign my application or what. Perhaps have both vc1 and vc2 belong to a subclass of vcmain and have reference to each of them there? However, if I do that, then how do I refer them to their corresponding .xib? Thanks guys!
@implementation viewController 1
//Reloads vc2
-(IBAction) onClick1: (id) sender {
//Calls vc2 reload
[vc2 reload];
}
@end
@implementation viewController 2
//Reload View
-(void)reload {
[webView reload];
}
@end
You've basically got three approaches, each one of which has plusses and minuses. I'm going to give you a high-level overview and let you go to Apple's quite comprehensive documentation for details. Hopefully I can give you the right terms to google for more specific help.
The approach that @dredful quite ably details is to have a handle to the "other" view controller(s) and call methods on them directly. That works fine, but it can be confusing and cumbersome handing pointers to all your controllers around, and traversing the view hierarchy to get get at the controller you want can be very tricky indeed.
The second approach is Key-Value Observing. You can register one view controller to "watch" a particular key (named property) of another view controller, and fire a particular selector when various things happen with it. This is kind of magical and nice, although at some point you have to have pointers to both controllers at the same time, which doesn't entirely relieve the downside of the "call it directly" method above. It is also a sort of unfortunate coupling of view control and data, kind of breaks MVC.
The third approach is using NSNotificationCenter. A class can post a notification, and any other object that registers itself to listen for that sort of notification can be triggered when that happens. It's nice because you might have LOTS of different objects adding items to the cart, and they can just shoot the notification center a note (even passing it an object or arbitrary data, if it wants), and the cart view can consume those notifications, catch the passed objects, and do its thing, not caring in particular who's talking to it. It keeps separate pieces of your application nicely decoupled. The downside is, it's got a bit of overhead to it, and whatever selector the notification-consuming class performs happens synchronously, so you can't hide network activity or some other long process there.
I'm thinking you should already have something like a base UIViewController
(let's call it MyTabBars
) that has a UITabBarController *tabBarController
containing all your Tab Bar View Controllers. If that sounds familiar, you will want a method in MyTabBars
called -(void)reloadCart
. reloadCart
will walk the array of tabBarController.viewControllers
. On each viewController
you can perform a respondsToSelector:@selector(reload)
and if the specific viewController
qualifies then it calls that selector method.
In order to do this you probably want all your vc1, vc2, ... files to have an id delegate
defined and synthesized. When MyTabBars
creates the different tab bars it sets the vc1 and vc2 delegate
to self
.
@implementation MyTabBars
//Reload Cart View
-(void)reloadCart {
for (UIViewController *thisUIViewController in tabBarController.viewControllers){
if ([thisUIViewController respondsToSelector:@selector(reload)]) {
[thisUIViewController reload];
}
}
}
@end
Assuming you know how to pass a delegate of MyTabBars
into your vc1 and vc2, then you can now have the following code in vc1:
@implementation viewController1
//Reloads vc2
-(IBAction) onClick1: (id) sender {
//Calls MyTabBars reloadCart which will look for all tab bar view controllers
//that have the 'reload' method
[delegate reloadCart];
}
@end
This solution idea will cause MyTabBars to trigger any reload
method found in any of our tab bar view controllers. Therefore be careful with the naming of such a method in your vc1, vc2, etc files. This solution will trigger a unique vc method or multiple vcs with the same method depending on your naming convention.
Hope this helps.
精彩评论