iOS 5 MainStoryBoard : When linking a view as PUSH, can we set a property? - properties

I know we still can do it by programmation,.. that's what i'm using for now (as iOS 4).
The old way was to init your controller, set property, then Push.
But with iOS 5, since the main storyboard is the "new" way to design your application.
I was wondering if it is any possible way to do the same, setting a property then pushing using the link in your mainstoryboard ?
It is so easy now to push, but not really useful if you want to set a property....
I don't know if I explained it clearly.. but it is really basic stuff.
Anyone?

You'd now use prepareForSegue: method to do any customisation. You can grab a reference to the view you're about to push and manipulate it, similar to this...
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Check we're referring to the right segue
if ([[segue identifier] isEqualToString:#"YOUR_SEGUE_NAME_HERE"])
{
// Get reference to the destination view controller
YourViewController *vc = [segue destinationViewController];
// Do your customisations here
}
}
I just wrote two blog posts on how to do this. You can read it here and it should clarify (with example) how to do it.

Related

Pass variable to view controller before viewDidLoad

I perform a segue which is defined in the Storyboard to open a new view controller. I need to configure the destination view controller of the segue in a special state where some of it's buttons does not needed to be displayed.
I know that I can do this by setting a variable on this controller in my source view controller's -prepareForSegue:sender:. The problem with this is, that firstly it instantiates the controller, so it's -viewDidLoad: will run, then only after can I set anything on it.
I can't create the controller entirely from code, because it's user interface is in Storyboard. -instantiateViewControllerWithIdentifier: also calls -viewDidLoad first obviously.
I could probably use a semaphore and add the initialization code into my destination controller's -viewWillAppear, but that's ugly, it has to be some more elegant way to do this than doing a check every time the view appears. (My settings need to be done only once.)
Is there some way to pass variables into the controller before it's -viewDidLoad runs?
EDIT: It looks like this happens only if I trigger the segue from code using -performSegueWithIdentifier:.
On my machine and on iOS 8.0 and iOS 9.0, viewDidLoad is called after prepareForSegue. So, something like the following worked for my test case of your answer.
In your source controller:
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
TimViewController * controller = segue.destinationViewController;
if( [controller isKindOfClass:[TimViewController class]] )
controller.name = #"tim";
}
In your destination controller (TimViewController):
- (void)viewDidLoad
{
[super viewDidLoad];
// Do view setup here.
NSLog( #"view did load %#", self.name );
}
Add a segue (a show segue) from your source control to the destination view controller.
Output:
2015-09-17 19:09:04.351 Test[51471:7984717] view did load tim
I think there is some confusion here. -prepareForSegue:sender: gets called before -viewDidLoad gets called. Please double check your implementation.
Edit:
May be this thread will help you understand this and one of the mentioned cases fall in your case.

Presenting correct View Controller instance depending on cell selection in UITableView

I understand this might be covered in parts in answers to other questions (see references) I've seen on the site, but due to my limited experience I haven't been able to understand each part as it relates to my code. Please forgive me for any duplications.
I have a PFQueryTableViewController (essentially a UITableViewController) called threadsViewController that sources cell information from a Parse backend. The table view consists of threads similar to what you would see on a web forum.
I then have a separate class postsViewController which is another PFQueryTableViewController that I wish to display a table of all the responses ('posts') to that particular thread.
The functionality I'm looking for is for a user tapping on a thread (left screen in the image) to be presented with a postsViewController (right screen) containing only those posts/responses related to that thread. (See basic diagram below).
What I do know from my research:
The Parse backend is established with classes for Thread and Post.
I'm probably going to use the didSelectRowAtIndexPath delegate method
What I need help with:
How can I know which thread cell a user tapped on, and then pass that on so that the postsViewController only displays posts from that Thread?
A layman's description of how to use indexPath.row etc
I understand how to complete PFQueries etc to get the data for the cells, I just don't know how to implement the navigation and how to tell postsViewController which posts to show.
In case it helps somehow, here is my implementation so far. I have tried addign a property to the postsViewController called fromThread to somehow store the thread but apart from that I'm out of ideas!
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[super tableView:tableView didSelectRowAtIndexPath:indexPath];
postsViewController *postsVC = [[postsViewController alloc] init];
postsVC.fromThread = //?
[self performSegueWithIdentifier:#"threadsToPosts" sender:self];
}
References
How to filter a Parse query by an tableview index?
Pass Index Number between UITableView List segue
didSelectRowAtIndexPath and prepareForSegue implementation
You're on the right track. You need know how to do two things: (1) access your parse objects by indexPath, and (2) push a new view controller in a navigation controller.
(1) is simpler: PFQueryTableVC provides a method called objectAtIndexPath: that does just what you need.
// indexPath is the indexPath parameter to the didSelectRow delegate method
PFObject *fromThread = [self objectAtIndexPath:indexPath];
(2) is simple, too. But more complicated because there are a couple ways to do it. Segue is the more modern way, but I think the old way is simpler, and certainly easier to describe in code. View Controllers are given storyboard ids on the "Identity" tab in the storyboard editor. Give your Posts-presenting VC a storyboard id like "PostVC".
To get a new instance, use that storyboard id as follows:
MyPostVC *postVC = [self.storyboard instantiateViewControllerWithIdentifier:#"PostVC"];
// initialize it with the PFObject we got above
postVC.fromThread = fromThread;
// present it on the navigation stack
[self.navigationController pushViewController:postVC animated:YES];
And fromThread is just what the PostVC will need to form a query for posts associated with the selected thread.
You can pass data of cell to next ViewController in prepareForSegue with something like this
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"threadsToPosts"]) {
UINavigationController *navCon = segue.destinationViewController;
postsViewController *postsViewController = [navCon.viewControllers objectAtIndex:0];
// Whatever you are populating your tableView with
Thread *thread = [self.thread objectAtIndex:self.tableView.indexPathForSelectedRow.row];
postsViewController.thread = thread;
}
}

Replace PlaceHolder View With other ViewControllers leads to Thread 1:EXC_BAD_ACCESS Code 1

hey guys created a custom segue tab bar, using this guys tutorial,
http://www.scott-sherwood.com/tutorial/ios-5-creating-a-custom-side-tabbar-using-storyboards-and-custom-segues/
after trying to figure out why why my app doesn't work, i realised that the technique i was using was about replacing the existing view with the linked ViewController as a subview.
////////////////////////////////////////// the over-written perform method as follows /////////////////////////
-(void) perform {
ViewController *src = (ViewController *)[self sourceViewController];
UIViewController *dst = (UIViewController *) self.destinationViewController;
for (UIView *view in src.placeholderView.subviews ) {
[view removeFromSuperview];
}
src.currentViewController = dst;
[src.placeholderView addSubview:dst.view]; }
////////////////////////////////////////////// /////////////////////// /////////////////////// ///////////////////////
now once i am on the linked ViewControllers i was hoping to add another link to another ViewController which would hold the Editing functions for the information each respective pervious ViewControllers. Now when i try to connect a the ViewControllers via any Segue the app crashes and give me a Thread 1:EXC_BAD_ACCESS. When i use NSZombie its give me this in the console,
[UIStoryboardSegueTemplate performSelector:withObject:withObject:]: message sent to deallocated instance 0x7c3a4d20
no i understand what is happening in theory, the viewController is trying to ad the next one to an empty space (i think the entire placeHolder has been deleted thus giving the viewController nowhere to go) i think, i was wondering if anyone could help with this i mean i a have been looking everywhere for a solution but i keep getting the same error.
i even created a VieController class for the ProfileViewController.m/ProfileViewController.h in which i add
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([[segue identifier] isEqualToString:#"ProfileEditSegue"]){
ProfileViewController *cvc = (ProfileViewController *)[segue destinationViewController];
[cvc.placeholderView addSubview:cvc.view];
}
}
this to leads me to the same errors. I will be glad to send anyone my source files, the same error occurs when i do it on the supplied files from the tutorial.
PS. i am using this method so that i can have a vertical navigation bar, but i want to do it simply so i could also learn how one works and be able to use/develope it further.
any help would be great
The problem wasnt in those methods it was because the currentViewController instances was set to weak instead of strong

Pass data between storyboards, not master detail template

Is it possible to pass data between storyboards in objective-c with segue when the application is not made from a master detail template?
The only examples I have seen is the one with master detail views.
Yes, it is. You could implement prepareForSegue:sender: in the viewController you are segueing from, like so:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"MySegue"]) {
MyOtherViewController *destination = (MyOtherViewController *)segue.destinationViewController;
destination.someProperty = self.someOtherProperty;
}
}
This will get called before your segue is performed, giving you a hook into the viewController you are segueing to.
Edit:
I didn't realise your ViewControllers were in different Storyboard. This question has already been pretty much answered, here: https://stackoverflow.com/a/9610972/1716763
You wouldn't actually be using a segue though, you would do things programatically and either push your second view controller onto the navigation stack, or present it modally.
I've adapted some of the code from #Inafziger's answer to fit your example:
UIStoryboard *secondStoryBoard = [UIStoryboard storyboardWithName:#"secondStoryBoard" bundle:nil];
MyOtherViewController *myViewController = (MyOtherViewController *)[secondStoryBoard instantiateViewControllerWithIdentifier:#"myOtherViewController"];
myViewController.someProperty = self.someOtherProperty;
[self.navigationController pushViewController:myViewController animated:YES];

How to Properly Switch Between Views

I'm making an iOS app (first actual app that isn't Hello World), and it will have 2 screens. I asked on here before how to make one screen (or View Controller) open another, and this is what I figured out to use:
[self presentViewController:[[self storyboard] instantiateViewControllerWithIdentifier:#"statView"] animated:YES completion:nil];
It works. However, it gives me the following message when this runs:
Unknown class statView in Interface Builder file.
(Note: this doesn't stop me from using the app, it just seems to be a warning.
This leads me to believe I'm doing something wrong. Also, it seems I'm instantiating this new view controller, but never getting rid of it. So when I go back and forth, I imagine I might be leaving these View Controllers instantiated as new every time?
So my question is:
If there is a better way to switch between these windows, how can it be done?
If this is correct, why the error message?
The most easy way is unsing the Storyboard.
Add a button and link it to the second view.
You can use a Segue to parse data:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if([[segue identifier] isEqualToString:#"SEGUENAME"]) {
SecondViewController *secondViewController = [segue destinationViewController];
secondViewController.parameter = parameter; // Parse a value
}
}