I have tried pushing to my ChatView view controller from my UserProfile view controller in a number of different ways:
UserProfile.m
ChatView *chatView = [[ChatView alloc] init];
[self.navigationController pushViewController:chatView animated:YES];
Also:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle: nil];
ChatView *chatView = [storyboard instantiateViewControllerWithIdentifier:#"chat_view"];
[self.navigationController pushViewController:chatView animated:YES];
And also I have tried modal presentations:
[self presentViewController:chatView animated:YES completion:nil];
These don't actually crash, but they all fail to get past this bit of viewDidLoad:
JSQMessagesViewController.m
-(void)viewDidLoad
{
...
NSLog(#"We see this log");
[[NSBundle mainBundle] loadNibNamed:NSStringFromClass([JSQMessagesViewController class])
owner:self
options:nil];
NSLog(#"We do not see this log");
...
}
Additional info
The above code all works absolutely fine when I push to this view from my RecentChats view controller. The key difference, I think, is that my UserProfile view controller itself loads nibs, whereas RecentChats is a more straightforward Storyboard-built UITableViewController, and I wonder if is the nib loading in UserProfile this is causing issues.
The short answer is you are doing many fundamental things wrong and they are culminating in your code not working.
You should read Apple's View Controller Fundamentals.
To name a few problems, you are using the wrong initialize function for a View Controller. Unless a subclass designates otherwise, -initWithNibNamed:bundle:(typing from memory on my phone; sorry if I'm not exact) is the correct method.
Your view controller's main view is loaded in the -loadView method, not -viewDidLoad. If you are using a NIB, the name of the NIB should be passed into the initialize method, not loaded via -loadNibNamed:.
I could go on for a while, but you get the point.
Related
I'm trying to pass some data to my view controller class like this:
MyViewController *vc = [[MyViewController alloc] init];
vc.myProperty = dataToBePassed;
[self.navigationController pushViewController:vc animated:YES];
I need to make some view configuring in viewDidLoad, but it seems that viewDidload called earlier than property assignment.
Then in MyViewController implementation:
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"%#", self.myProperty); // Here i get myProperty = nil
}
- (void)viewWillAppear
{
[super viewWillAppear];
NSLog(#"%#", self.myProperty); // Here i get myProperty = dataToBePassed but it's to late
}
How can i get passed data in viewDidLoad method without implementing singleton or delegate patterns?
Try doing this
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:
#"MainStoryboard" bundle:[NSBundle mainBundle]];
MyViewController *vc = [storyboard instantiateViewControllerWithIdentifier:#"storyboardIdentifier"];
vc.myProperty = dataToBePassed;
[self.navigationController pushViewController:vc animated:YES];
You have to set a storyboard identifier first in the storyboard for the view controller.
While the code sample you provide looks technically correct, I'm with #john-elemans in that you need to show more code.
There is something that is referencing the view which causes it to load and therefore causes viewDidLoad to fire prematurely.
In any case, if something (such as your property) is absolutely essential to the correct building of your view structure, I'd put in its own designated initializer, e.g.,
- (id)initWithPhotoDiameter:(CGFloat)diameter
{
self = [super init...]; // some VC initializer that you should call
if (self) {
_photoDiameter = diameter;
}
return self;
}
Notice the use of the backing instance variable _photoDiameter instead of self.photoDiameter. This is about the only place in a class where you should use the backing ivar, since self is still in the process of being initialized.
Technically there are two approaches that are quite common for lifecycle handling of view controllers related to an application.
Using XIBs
When using XIBs one of the most common if not the most common process to create and setup your view controllers is done programmatically. Following this process, when you initialise the view controller you have the option of either overriding your init method in order for your view controller to have the information prior to loading the view and easing up the process of adjusting drawn content. You can also create a method within your view controller to be called in which you pass the data to be used by the view controller.
Using Storyboard
If you are using storyboards I recommend that you trust segues setup through it. I have found that they make life easier and it will allow you to use certain methods to handle the transition. One of those is prepareForSegue:sender: Within that method I have found that it is easier to setup a view controller after it's initialized accessing the destination controller. You also might consider having all data there before viewDidLoad hence following the segue approach.
I'm trying to work on a simple login application which on successful login displays a menu page. On the action sheet of menu page, we have an option of looking at all the users logged in that phone and clicking on any user, it should do some login processing and direct to menu page again. This is how the workflow should go on.
Below is the image that explains it.
All the controllers are connected to segues except for accounts controller and middle controller. Navigation between those two is done using pushViewController as I had to pass some info from accounts controller(table view controller with list of all users) to middle Controller.
MiddleController *maController = [[MiddleController alloc] init];
if (maController.view) {
maController.ma_userId = mo_userId; // Set the exposed property
maController.ma_password = mo_password;
[self.navigationController pushViewController:maController animated:YES];
Middle controller is doing all the process perfectly after getting the details. But directing to menu controller is where I'm facing the problem. If I use a segue between middle controller and menu controller an error is thrown saying no identifier with the name segueName found. But if I use a pushViewController then it is displaying a blank black screen. Can some help me to solve this.
This is how I'm pushing it:
MenuTableViewController *mapMenuTableviewController = [[MenuTableViewController alloc]init];
[self.navigationController pushViewController:mapMenuTableviewController animated:NO];
I've tried all the ways that are posted in previous SO questions, but nothing helped.
Thanks in advance
Try not to alloc-init, but instantiate it fom storyboard like this (you should add it a storyboard id)
YourViewControllerClass *viewController = [[UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil] instantiateViewControllerWithIdentifier:#"ViewController"];
And then push it.
You need to add storyboard id like this
And use like
UIViewController *viewController = [[UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil] instantiateViewControllerWithIdentifier:#"ViewControllerID"];
Go to your storyboard, and set an identifier like this :
Now, in your view controller, do this :
YourViewController *viewController = [[UIStoryboard storyboardWithName:#"<your storyboard name>" bundle:nil] instantiateViewControllerWithIdentifier:#"myViewControllerID"];
[self.navigationController pushViewController:viewController animated:NO];
UPDATE -
Push you Accounts view controller and Middle view controller the way i told before.
Then, when your processing is done in the middle controller, just do this :
[[self presentingViewController]presentingViewController]dismissViewControllerAnimated:NO completion:nil];
Add storyboard Id to yput interface builder "SendSMSViewController" and call below code.
let SendSmsVC = self.storyboard?.instantiateViewControllerWithIdentifier("SendSMSViewController") as! SendSMSViewController
self.navigationController?.pushViewController(SendSmsVC, animated: true)
Plz use this code you will go to MenuTableViewController.
for (UIViewController *controller in self.navigationController.viewControllers)
{
if ([controller isKindOfClass:[MenuTableViewController class]])
{
[self.navigationController popToViewController:controller animated:YES];
break;
}
}
I have two views in the Tab Bar View. I want my second view to inform first view, when its Text Fields have changed value. I've done all the necessary coding for it, but there is one problem - first view doesn't see connected label outlets in the method declaration.
Code of the second view:
- (IBAction)textFieldHasChanged:(UITextField *)sender {
id<HPAAddCarOverallInfoTVCDelegate> strongDelegate = [[HPAAddCarMainViewController alloc] init];
if([strongDelegate respondsToSelector:#selector(addCarOverallInfoVC:textFieldValueChanged:)]) {
[strongDelegate addCarOverallInfoVC:self textFieldValueChanged:sender.text];
}
}
Code of the first view:
-(void)addCarOverallInfoVC:(HPAAddCarOverallInfoTableViewController *)viewController textFieldValueChanged:(NSString *)value
{
self.overallVCFieldCount.text = value;
NSLog(#"%#", value);
}
self.overallVCFieldCount.text = value; - value exist, but textField doesn't.
As I think, problem belongs at this line of code:
id<HPAAddCarOverallInfoTVCDelegate> strongDelegate = [[HPAAddCarMainViewController alloc] init];
I guess, that delegate isn't exact view with which I am working with. Bouth views are loaded at the same time via storyboard. If I am correct with my thought, can you tell me please, how can I give a pointer to exact first view which as second view are loaded when Tab Bar View controller goes on the screen?
You're creating a new view controller in textFieldHasChanged. If you have that view controller in IB, instantiate it like this:
UIStoryboard *st = [UIStoryboard storyboardWithName:[[NSBundle mainBundle].infoDictionary objectForKey:#"UIMainStoryboardFile"] bundle:[NSBundle mainBundle]];
id<HPAAddCarOverallInfoTVCDelegate> strongDelegate = st instantiateViewControllerWithIdentifier:#"identifier"];
Where identifier is the identifier you have given your view controller in your storyboard.
I'm using this code to programmatically move from my main screen (Login page) to the view behind it, but it gives a black screen;
LandingController *landingController = [[LandingController alloc] init];
[self presentViewController:landingController animated:YES completion:nil];
I've included the LandingController.h file into my ViewController.h and it also doesn't give any errors.
When I remove my Storyboard ID from my LandingController (which isn't referred to) in the above code, I get this message:
/Users/allendar/Desktop/iOS Apps/#HIDDEN# App/#HIDDEN# App/Base.lproj/Main_iPad.storyboard: Scene is unreachable due to lack of entry points and does not have an identifier for runtime access via -instantiateViewControllerWithIdentifier:.
I'm assuming this has something to do that I only call the associated Controller for the View, whereas it doesn't actually instantiate the View's internals.
I already tried some other examples by triggering the Storyboard ID of the LandingController, but it either gives errors or just does nothing (like this code does).
Any ideas how I can invoke the View itself when triggering its Controller, or either doing it through the Storyboard ID?
Try this:
UIStoryboard *storybboard = [UIStoryboard storyboardWithName:#"YOURSTORYBOARD" bundle:nil];
LandingController * landingController = [storybboard instantiateViewControllerWithIdentifier:#"STORYBOARD ID"];
[self presentViewController: landingController animated:YES completion:nil];
Try loading your view controller from the storyboard instead of doing alloc->init. Give your view controller an identifier in your storyboard and load it as follows:
[self presentViewController:[[UIStoryboard storyboardWithName:#"YourStoryBoardName" bundle:nil] instantiateViewControllerWithIdentifier:#"YourIdentifier"]];
I got an app with a storyboard and one window in .xib.
From the storyboard to the .xib i move in that way:
ShowDreamNIBController *detailViewController = [[ShowDreamNIBController alloc] initWithNibName:nil bundle:nil];
[self presentModalViewController:detailViewController animated:nil];
How can i move back from the .xib to the storyboard?
And one more question. Can i send some information when move to the .xib from storyboard? Like i do it throught segues in prepareForSegue method
UPD I got answer about closing .xib. Need answer about sending information.
you can get back to your storyboard by simply dismissing the modal view controller.
Like this:
- (IBAction)backPressed:(id)sender {
[self dismissModalViewControllerAnimated:YES];
}
You should put this method in your ShowDreamNIBController.
As for the second question, you can send back information to the view controller that presented the modal view controller by getting reference to it using delegation.
EDIT:
To "send information to the XIB" do you mean that you want to set information to the view controller that you want to present? If yes, than use this when you present the modal controller:
ShowDreamNIBController *detailViewController = [[ShowDreamNIBController alloc]initWithNibName:nil bundle:nil];
[detailViewController setSomething: something];
[detailViewController setAnotherThing: anotherThing];
[self presentModalViewController:detailViewController animated:nil];
I hope this helps.