I am trying to set the delegate of a UITableViewController using Storyboards. The problem I am having is that the UITableViewController's delegate I want to set, is not simply the initial view controller destination. Therefore I decided I would use this method once launching the app:
- (void)viewDidLoad {
AddListTermsViewController *addListTerms = [self.storyboard instantiateViewControllerWithIdentifier:#"AddListTerms"];
addListTerms.delegate = self;
}
I then set the Storyboard ID of the UITableViewController like so:
But when I launch the UITableViewController and log the delegate, I receive null.
Any ideas? Thanks in advance.
EDIT
When I log the output in the initial view controller like so, I get a positive result:
AddListTermsViewController *addListTerms = (AddListTermsViewController*)[self.storyboard instantiateViewControllerWithIdentifier:#"AddListTerms"];
addListTerms.delegate = self;
NSLog(#"%#", addListTerms.delegate);
But when I log the output on the UITableViewController I again receive null
i guess you need to typecast storyboadcontroller to AddListTermsViewController
try this
AddListTermsViewController *addListTerms = (AddListTermsViewController*)[self.storyboard instantiateViewControllerWithIdentifier:#"AddListTerms"];
Related
I was trying to push a viewcontroller B into navigation controller from A and then assigning some properties of B in A.
In this case, the assigning of properties was done and then viewDidLoad of viewcontroller A was executed.
Here, assigning properties in A should be done only after viewDidLoad of A has done.
For example,
[b.navController pushViewController:a animated:YES];
a.status = #"loaded";
Here, status was assigned first and then viewDidLoad of A was executed.
This happens only in iOS 7 whereas in iOS6 it works fine.
Can anyone please let me know where the problem is?
UPDATE: For me in some cases in iOS7, Push view is not working. How cna I debug and fix it?
Just access the viewcontroller.view (set any thing immediately after the alloc) property after the alloc init;
Which will loadview/viewdidload.
See Apple Documentation
In my experience, a UIViewController view is loaded lazily, no matter which iOS version you're working on. If you want to trigger a view load, and therefore its UIViewController viewDidLoad, you should access the view after the UIViewController is allocated. For example:
UIViewController *aViewController = [[CustomViewController alloc] init];
[aViewController view];
Make sure you don't code it as
aViewController.view
since that would generate a compiler warning.
So, in your case it would have to be something like this:
...
CustomViewController *a = [[CustomViewController alloc] init];
[b.navController pushViewController:a animated:YES];
[a view];
a.status = #"loaded";
Let me know if you have further problems with it.
You can know when a View Controller has been pushed onto the stack by implementing the UINavigationControllerDelegate and setting yourself as the delegate self.navigationController.delegate = self; then you will get this callback after every push
navigationController:didShowViewController:animated:
So you can check if the shown viewController is the one your interested in, then set your a.status.
I would suggest you call a delegate method once the view is loaded.
Set the delegate to be controller B.
and after viewDidLoad finishes (in controller A) call the delegate method. You can even pass parameters as you wish to the delegate.
Here's some example code:
Controller B:
a.delegate = self;
[b.navigationController pushViewController:a animated:YES];
Implement the delegate method:
- (void)controllerIsLoaded:(ControllerA *)controllerA status:(NSString *)status
{
a.status = status;
}
Controller A .h file:
#class ControllerA;
#protocol ControllerADelegate <NSObject>
- (void)controllerIsLoaded:(ControllerA *)controllerA status:(NSString *)status;
#end
#interface ControllerA : UIViewController
#property (nonatomic, weak) id <ControllerADelegate> delegate;
Controller A .m file:
- (void)viewDidLoad:(BOOL)animated
{
[super viewDidLoad:animated];
/* your viewDidLoad code here... */
if ([_delegate respondsToSelector:#selector(controllerIsLoaded:status)])
[_delegate controllerIsLoaded:self status:#"Loaded"];
}
Turn off animation for ios7, in my case its work
[b.navController pushViewController:a animated:NO];
a.status = #"loaded";
No documentation provides enough information to know exactly when viewDidLoad would be called.
UIViewController's documentation just says this
This method is called after the view controller has loaded its view hierarchy into memory
I would suggest that you create a custom initializer like this
- (id)initWithStatus:(NSString *)status {
}
But, if you are trying to use this variable to check if the viewController's view has 'loaded' or not, it may not be possible to do that because the pushViewController or presentViewController methods are not guaranteed to be synchronous.
Even in iOS 6, there was no explicit guarantee that the view would be loaded as soon as that method returned.
Please write the code in viewWillAppear method instead of viewDidLoad in next class i.e. where you are pushing the object to
-(void)viewWillAppear:(BOOL)animated
{
}
I'm understand of your question like this:
B *b = [[B alloc] init];
b.status = #"loaded";
[self.navigationController pushViewController:b animated:Yes];
If you want to pass a value from one controller to another means, you have to assign a value before using pushViewController method.
Wondering how I can set properties of view controllers that are already on the NavigationController's stack
My situation:
I want to set up an image uploading flow like this
(Navigation Stack)
RootViewController -> TakePictureViewController -> EditPictureViewController -> UploadPictureViewController
When user confirms the upload from the UploadPictureViewController, rather than start to upload, I want to set an NSDictionary property on RootViewController which contains the upload query, then pop the navigation stack back down to the RootViewController and have it handle initiating and status reporting of the query.
Here's my code in the uploadpictureviewcontroller, currently, the code does pop to the right view controller, but the uploadPackage property is still nil, also I have tried to -setUploadPackage
RootViewController *rvc = (RootViewController *)[self.navigationController.viewControllers objectAtIndex:0];
rvc.uploadPackage = uploadPackage;
[self.navigationController popToViewController:rvc animated:YES];
All help appreciated, thanks.
try using [self.navigationController popToRootViewControllerAnimated:YES]. That should do it.
EDIT:
If you have only one instance of RootViewController, then you can set it up as a singleton and therefore you can access it from any other controller (just like the appDelegate). To do so you need to add the following to your RootViewController.m under synthesize...; :
static RootViewController *rootViewController;
+(id)sharedRootController {
return rootViewController;
}
inside your init method for RootViewController add the following line:
rootViewController = self;
now back to your UploadPictureViewController you can set the uploadPackage like this:
RootViewController *rvc = [RootViewController sharedRootController];
rvc.uploadPackage = uploadPackage;
Please note that you should NOT use the singleton method if there is to be more than one instance of RootViewController.
hope this helps!
Basically, I have a TabBarController and some sub-views attached to this controller. The TabBarController has some properties that I would like to access in the sub-views.
Here's what I have :
MyTabBarController's .m
-(void)setDetails:(id)sender
{
self.myVariable = #"This is a test";
NSLog(#"Here I set my variable");
}
- (void)viewDidLoad
{
NSLog(#"[LOAD] My Tab Bar Controller");
[self setDetails:nil];
}
First subView's .m
- (void)viewDidLoad
{
NSLog(#"[LOAD] FirstViewController");
MyTabBarController *myTBC = (MyTabBarController *)self.tabBarController;
self.headerName.text = myTBC.myViariable; // Here I just set the UILabel's text
NSLog(#"Header name = %#", self.headerName);
}
Here's what I have in the logs :
2012-08-07 11:43:23.001 MyFirstproject[23632:15203] [LOAD] My Tab Bar Controller
2012-08-07 11:43:23.012 MyFirstproject[23632:15203] [LOAD] FirstViewController
2012-08-07 11:43:23.072 MyFirstproject[23751:15203] Header name = (null)
2012-08-07 11:43:23.116 MyFirstproject[23751:15203] Here I set my variable
My question is : As I can see in the logs, the viewDidLoad function of MyTabBarController is called before the FirstViewController's one. However, it seems the function setDetails of MyTabBarController is called after the function viewDidLoad of the FirstViewController.
How can this be possible ? Is there something I'm doing wrong here ?
Thanks !
Try to put the code for firstViewController in viewDidAppear method instead of viewDidLoad
Happy Coding :)
And for the difference bet'n those two just check it out the documentation regarding it on Apple's developer site :)
Formally viewDidLoad call's once at the time of loading the view
And viewDidAppearcall's when ever the view is about to appeared on the screen :)
Happy Coding :)
I have two view Controllers in my project ViewController, SettingsView. Here I am trying to update the ViewController's label, when i click on the SettingsView's back button. NSLog is working fine, but the label is not updating...
Please help me....
SettingsView.m
-(IBAction)backToMain:(id) sender {
//calling update function from ViewController
ViewController * vc = [[ViewController alloc]init];
[vc updateLabel];
[vc release];
//close the SettingsView
[self dismissModalViewControllerAnimated:YES];
}
ViewController.m
- (void)updateLabel
{
NSLog(#"Iam inside updateLabel");
self.myLabel.text = #"test";
}
Could you please tell me whats wrong with my code? Thank you!
You have to implement protocols for that. Follow this:
1) In SettingView.h define protocol like this
#protocol ViewControllerDelegate
-(void) updateLabel;
#end
2) Define property in .h class and synthesis in .m class..
#property (nonatomic, retain) id <ViewControllerDelegate> viewControllerDelegate;
3) In SettingsView.m IBAction
-(IBAction)backToMain:(id) sender
{
[viewControllerDelegate updateLabel];
}
4) In ViewController.h adopt protocol like this
#interface ViewController<ViewControllerDelegate>
5) In viewController.m include this line in viewDidLoad
settingView.viewControllerDelegate=self
Your label is not updating because , you are trying to call updateLabel method with a new instance.
You should call updateLabel of the original instance of viewcontroller from which you have presented your modal view.
you can use a delegate mechansim or NSNotification to do the same.
Delegate mechnaism would be clean. NSNotification is quick and dirty.
You are not exactly calling the correct vc. This is because you are creating a new instance of that class and calling the updateLabel of that instance.
You have a few options.
Either implement it as a delegate callBack (delegate messagePassing, or delegate notification - however you want to call it) to notify that class instance to call the updateLabel method.
Use the original instance VC as a dependency injection into the class that you are on right now, and use that instance to call the updateLabel
Use NSNotifications / NSUserDefaults to communicate between viewControllers and setup a notification system for your actions. This is quite easy, but not really great in the long run.
I would RECOMMEND option 1 (or) option 2.
Simply declare like this in SettingsView class:
UILabel *lblInSettings;// and synthesize it
Now assign like below when you presenting Settings viewController:
settingsVC.lblInSettings=self.myLabel;
Then whatever you update in lblInSettings it will be present in MainView obviously....
no need for any delegate methods or updating methods.
Means if you assign at the time of dismissing like
lblInSettings.text=#"My new value";
then self.myLabel also will be updated.
Let me know if you have any queries?
I have this in one view:
-(void)viewWillDisappear:(BOOL)animated
{
RootViewController *rVC = [[RootViewController alloc] initWithNibName:#"RootViewController" bundle:nil];
[rVC setMessage:[label text]];
NSLog(#"ihere - %#",rVC.message);
}
The NSLog returns the correct string. How would I reload the data in the RootViewController to update the string message there?
doing this doesn't work in my RootViewController (which i go back to in navcontroller):
-(void)viewWillAppear
{ [[self message] reloadData]; }
because the message is just a string. Can somebody show me how to fix this please?
Hi can someone else try to help me please?
In the viewWillAppear event, i need to reloadData on a NSString. So i need to convert it somehow to an object before i can use reloadData on it.
That's because NSString doesn't have a reloadData method.
And as it is immutable it wouldn't make sense if it did.
What you probably want to do is display your string in viewWillAppear and change the model property in the controller where it gets this from.
Delegation is the usual way to do this and I've written a couple of examples that might help you see what is happening;
DelegationExample
TableViewDelegation
Presuming you're using a NavigationController: Consult your navigation controller's stack (property navigationController in your current controller) to access the element for your root view controller (this would generally be the zeroth element -- use viewControllers). Set your message property using that pointer. Then be sure that your root view controller, in viewWillAppear, uses the property you just set to reset the text of the label of interest (using a simple assignment statement -- self.myLabel.text = self.message;.