We have 2 files 'MainViewController' and 'View01'
The first file addSubView the second one.
In the first file we have a function named displayView.
I want to be able to call this function from the View01 file is the following code correct
part of View01 file
#import "MainViewController.h"
- (IBAction) changeView:id(sender){
MainViewControlle *appDelegate = [[UIApplication sharedApplication] delegate];
[appDelegate displayView:2];
}
is this the correct way to do it?
at the moment I use the NSNotificationCenter to send activate the functions :)
You should try using delegate methods :-)
It works like that :
// Delegate
#protocol MyViewDelegate <NSObject>
- (void)myViewAskedForSomethingWithOrWithoutParameters;
#end
In your view you must have this parameter :
id<MyViewDelegate> delegate;
And then in your Controller you must implement the delegate
#interface MainViewController : UIViewController <MyViewDelegate> {
}
In your implementation you need to add a :
myView.delegate = self;
And finally in your view when you need to call the function, just do :
[ delegate myViewAskedForSomethingWithOrWithoutParameters ];
Good Luck !
If I'm not mistaken, your code shouldn't work. Did you try it your self?
[[UIApplication sharedApplication].delegate]
will return your AppDelegate, called something like MyAppDelegate and not MainViewController. However, depending on the template you used or created, your AppDelegate might contain a MainViewController-property, most likely called viewController so you could use
[appDelegate.viewController displayView:2];
This is the quick way to do it. For a more tidy way, see Vinzius' answer.
Related
I am uploading data on server from my NSObject class, now i want to show MBProgressHUD when that data is uploading, I know how to show MBProgressHUD with ViewController but dont know how to show it with NSObject class.
AppDelegate* delegate = [[UIApplication sharedApplication] delegate];
[delegate.window addSubview:HUD];
...
[HUD removeFromSuperview];
There are several ways to solve this kind of problems. The most common one is using the delegation pattern, although you can use blocks, KVO, or Notifications.
You should start by creation a protocol, so you can communicate between your UIViewController and your NSObject that makes the calls. Although you don't need one to create this communication, you should use it to have a more flexible code.
Normally, I would do something like this:
#protocol CommunicationDelegate <NSObject>
#required
-(void)communicationSucceed;
-(void)communicationFailedWithError:(NSError*)anError;
Inside your NSObject, you will have a weak reference for an object that complies with the protocol CommunicationDelegate. In your .h you should have something like this:
#property(nonatomic, weak) id <CommunicationDelegate> communicationDelegate;
Just before you actually start your work with the NSObject, you should do:
myObjectThatWillDoSomething.communicationDelegate = self;
At this moment you have a valid reference between your UIViewController and your NSObject. Inside your UIViewController's .h file, add this:
#interface myViewController : UIViewController <CommunicationDelegate>
So your UIViewController complies to the CommunicationDelegate protocol.
You can now start your MBProgressHUD from your UIViewController. Once your NSObject has done his work, you can either call:
[communicationDelegate communicationSucceed];
or
[communicationDelegate communicationFailedWithError:anError]; //anError is used to describe what went wrong
Once (one of) those methods are called, you can remove your MBProgressHUD. Understand that this methods are called inside your UIViewController.
When you upload your NSObject, a view is displayed, right? So display your HUD in that view. You may need to create a delegate to notify the view when the download begin, when it ends and if there is an error.
Create a delegate protocol on your uploader object
#protocol UploaderThingyDelegate <NSObject>
-(void)stuffStarted;
-(void)stuffEnded;
#end
#interface UploaderThingy : NSObject
#property (weak) id<UploaderThingyDelegate> delegate;
Set your relevant View or ViewController as the uploaders delegate and trigger the MBProgressHUD add/remove there.
Use NSNotification Center to stop Indicator , Declare NSNotification with listening method in view controller . And post notification from Webservice file . Stop indicator in listening method of Notification center .
This link will help you
These Below Code Works fine in NSObject File
Step 1: Download the https://github.com/jdg/MBProgressHUD
Step 2: Add the Delegate MBProgressHUDDelegate
Step 3: Declare Instance MBProgressHUD *HUD;
Step 4: Write Code Where u want:
HUD = [[MBProgressHUD alloc] initWithWindow:[UIApplication sharedApplication].keyWindow];
[[UIApplication sharedApplication].keyWindow addSubview:HUD];
HUD.delegate = self;
HUD.labelText = #"Processing";
[HUD show:YES];
The situation I am running in is that, I have a login Button which is having NSURLConnection method in the main view controller and when button is pressed it will be active and and XML file will be downloaded. Now to parse that XML file the method which is parsing is in application delegate file.
Now I want to know that how can I call that function from within the login button. And also that from that parsed file I have to check a value that if it is more than 1 or less than one. So that the action would be taken that to which view it will be transitioned.
any help will be appreciated.
If the method to do your parsing lives in the application delegate, then getting a hook to it can be as easy as:
MyFineApplicationDelegate * appDelegate =
(MyFineApplicationDelegate *)[[UIApplication sharedApplication] delegate];
And then you can call [appDelegate parseMyXMLData: myXMLData];
Makes sense?
Try This..
In .h
#import "Appdelegatefile.h"
Appdelegatefile * appDelegate;
IN .m
{
appDelegate =(Appdelegatefile *)[[UIApplication sharedApplication] delegate];
[appDelegate //here you can call method of delegate file ];
}
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:
UIControl target/action bindings
Protocols
Key/Value Observing (KVO)
Notifications
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]
}
Communication between various objects of your app is a design level decision. Although iOS provides neat ways of doing this at code-time (properties) - it's through hard-coupling.
True inter-object communication does not bind objects at compile time - this is something that can only be assured by following design patterns.
Observers & Delegates are two most commonly used patterns, and it's worth for you to learn when to use which one - see Observer vs Delegate.
So, basically, I have four different views that are switched via a tab bar at the bottom of the screen. I have a view controller set up for each one, and they all work fine. The only problem is that I have no idea how to share information between the different views-for example, I have an IBAction on one that takes the output of a UISegmentedControl and stores the selection as an integer (1,2,3,4). The problem is, I don't know how to access that integer from the first view controller (the one that actually does stuff with that information). I'm sure this is a very basic problem but my google-fu doesn't seem to be working here. Thanks!
Using the MVC method, information should not be stored in the view controllers. You should have a separate object which stores the information, the view controllers load it, and the views display it. The easiest way to do this would be to store the information in your application's delegate. Then, whenever the view controller needs to find/change some information, it can use [[UIApplication sharedApplication] delegate] to get the delegate, and load/change the information as needed. Load the information to update the display in viewDidLoad or viewWillDisplay:, and change it in action methods.
Edit Example:
DelegateClass.h
#interface DelegateClass : NSObject {
//ivars
float number1;
}
#property (assign) float number1;
...
#end
DelegateClass.m
#import "DelegateClass.h"
#implementation DelegateClass
#synthesize number1;
...
#end
MyViewController.m
#import "DelegateClass.h"
#implementation MyViewController
- (void)viewDidLoad {
[super viewDidLoad];
DelegateClass *delegate = [[UIApplication sharedApplication] delegate];
float number1 = delegate.number1;
...
}
- (IBAction)actionMethod:(id)sender {
float number1 = sender.floatValue;//get new value
((DelegateClass*)[[UIApplication sharedApplication] delegate]).number1 = number1;
}
...
#end
You could have your views expose their variables to the UITabBarController. The UITabBarController can have methods that these views can call to see these variables.
Or, you could have your views directly set the values of variables in the UITabBarController. Not recommended (though a lot less typing :)
Just did a quick search on Google, btw, and came across this: Accessing parent view controller (custom) properties. Looks like there's sample code to be had there. :)
Hope this helps!
I use a general theme in all my apps where I have certain data that needs to be accessed practically in all main classes. I find it really easy to use and practically error free. (Thanks again to all the folks here in the forum for the super idea!)
I declare this variable in all the classes where I need it...
#class WebiDataManager;
#interface FirstViewController : UIViewController<MFMessageComposeViewControllerDelegate, SetupDelegate> {
WebiDataManager *webiDataManager;
...
In this code I get it from the AppDelegate...
#import "WebiAppDelegate.h"
- (void)viewWillAppear:(BOOL)animated {
// D_IN;
[super viewWillAppear:animated];
//get the dataManager global Object, so we always have a structured accesss to the data!
WebiAppDelegate *mainDelegate = (WebiAppDelegate *)[[UIApplication sharedApplication]delegate];
self.webiDataManager = mainDelegate.webiDataManager;
By the way, this also works great for coredata, since through this global variable I always have access to all the main coredata.
Hope I could explain it clearly enough...
I'm trying to figure out how I can call a function from another one of my classes. I'm using a RootViewController to setup one of my views as lets say AnotherViewController
So in my AnotherViewController im going to add in on the .h file
#class RootViewController
And in the .m file im going to import the View
#import "RootViewController.h"
I have a function called:
-(void)toggleView {
//do something }
And then in my AnotherViewController I have a button assigned out as:
-(void)buttonAction {
//}
In the buttonAction I would like to be able to call the function toggleView in my RootViewController.
Can someone clarify on how I do this.
I've tried adding this is my buttonAction:
RootViewController * returnRootObject = [[RootViewController alloc] init];
[returnRootObject toggleView];
But I dont think that's right.
You'll want to create a delegate variable in your AnotherViewController, and when you initialize it from RootViewController, set the instance of RootViewController as AnotherViewController's delegate.
To do this, add an instance variable to AnotherViewController: "id delegate;". Then, add two methods to AnotherViewController:
- (id)delegate {
return delegate;
}
- (void)setDelegate:(id)newDelegate {
delegate = newDelegate;
}
Finally, in RootViewController, wherever AnotherViewController is initialized, do
[anotherViewControllerInstance setDelegate:self];
Then, when you want to execute toggleView, do
[delegate toggleView];
Alternatively, you could make your RootViewController a singleton, but the delegate method is certainly better practice. I also want to note that the method I just told you about was Objective-C 1.0-based. Objective-C 2.0 has some new property things, however when I was learning Obj-C this confused me a lot. I would get 1.0 down pat before looking at properties (this way you'll understand what they do first, they basically just automatically make getters and setters).
I tried out the NSNotificationCentre - Works like a charm - Thanks for your reply. I couldn't get it running but the NS has got it bang on.
[[NSNotificationCenter defaultCenter] postNotificationName:#"switchView" object: nil];