I'm stuck with a problem which I'm not sure how to solve. I have several view controllers which follows each other as the user populates them with data.
Before changing views I use an alert controller for the user to confirm correctness of data before pushing to the next view controller. However, here I need to capture the data but I'm only writing the data to Realm once all the data is gathered.
My question is this; how do I temporarily keep this data (and use some of them forward) until it's time to write to the database?
The easiest way is to create a property in each of the view controllers.
in the .h file, under interface
#property (strong, nonatomic) MyRealmObject *realmObject;
in the .m file, under implementation
#synthesize realmObject
Then, in your prepareForSegue method, you populate the copy local to your view controller, instantiate the destination view controller, and then pass the local Realm object into the property of the destination view controller.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if([segue.identifier isEqualToString:#"SegueName"]) {
DestinationViewController *destViewController = segue.destinationViewController;
destViewController.realmObject = self.realmObject;
}
}
This will pass a copy of your existing realm object to the next view controller
Related
I'm trying to make a form that one of the filed takes value from a two level selections' result.
The main progress will something like:
EditViewController ===> CategoryViewController (which embedded inside a NavigationController by storyboard and popped up as a modal view) ===> SubCategoryViewController (Which will be pushed to NavigationController).
Now I have a problem. After user tap to select a value in SubCategoryViewController, I'm supposed to dismiss SubCategoryViewController and return the value to EditViewController. But I don't know exactly how.
Please suggest any solution.
Thank you.
EDIT:
Every one of those view controllers should have a public property for a weak reference to a model object that represents whatever is being edited.
So every ____ViewController.h file would have:
#property (weak, nonatomic) CustomItem *item.
in its interface (assuming a strong reference is somewhere in some data store or array of all the items).
When EditViewController is preparing for the segue to show CategoryViewController modally, it should assign that same reference to CategoryViewController's item property after assigning any data entered in EditViewController's form to item:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
//TODO: assign data from controls to item, for example:
//self.item.title = self.titleField.text;
CategoryViewController *vc = (CategoryViewController *)segue.destinationViewController
vc.item = self.item; //pass the data model to the next view controller
}
Likewise for the segue from CategoryViewController to SubCategoryViewController. This ensures that every ViewController is editing the same object in memory. When you dismiss SubCategoryViewController (assuming somewhere in all of this CategoryViewController was already dismissed), viewWillAppear: will be called on EditViewController- there you can refresh any changes made in the modal views to the item property, just like you would when first displaying the view (it's actually the same method that's called):
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.titleField.text = self.item.title;
self.categoryLabel.text = self.item.category;
self.subcategoryLabel.text = self.item.subcategory;
//etc....
}
This question already has answers here:
Passing data between two controllers using storyboards
(4 answers)
Closed 9 years ago.
I am new to storyboard and I am not able to send a data from "Add Filter View Controller" to "Add Filter tableView Controller". Problem is prepareForSegue is not getting called because "Add Filter View Controller" is a root view controller. I don't know what I am doing wrong.
Try something like this:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
AdFilterViewController *destination = segue.destinationViewController;
destination.dataINeed = self.dataToGive
}
where destination.dataINeed is a property you need to declare in AdFilterViewController.h so this class can interact with it.
Hope it helps
Answer from #Kamaros worked.
" In your prepareForSegue:, you can do something like AddFilterTableViewController *ftvController = [addFilterVC viewControllers][0] and then pass your data manually that way"
Here's what you do.
In your Add Filter Table View Controller.h file, add a property (whatever is the data you want to pass) :
#property (nonatomic, strong) NSMutableArray *filterList;
Then, when you segue to that from your Add Filter View Controller, in the Add Filter View Controller.m file, add :
#import "AddFilterViewController.h" //Don't forget to import the destination view controller's header file
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
AddFilterTableViewController *aFTVC = segue.destinationViewController;
[aFTVC setFilterList : YOUR_NSMUTABLEARRAY_HERE];
}
I passed an NSMutableArray here, but it can be any data type.
I feel ignorant for asking this because I know it's simple. Goal: Retain a variable on a view after leave then returning to it.
For instance: Let's say we have MainView, CategoryView and (drumroll) ProjectView
Application opens to MainView it displays a table - user selects they want to pick a category. This segue's them to CategoryView. Once a selection is made I send the chosen category back to MainView. via
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
No problem here. MainView receives variable and displays the chosen category as subtext in the 'Category' section. Next the user wants to pick a project name (this is also a predefined list) They select the item and I send the variable back the MainView.
-- Now can somebody explain to me (gently) why when I return to the main view the NSString variable that was previously holding the 'chosen' category is now null?
So my NSString selectedProject is not being retained correct? What is the correct implementation I should be doing here? Or what am I missing? I'm really trying to understand whats going on so anything would be a great help.
MainView Interface
#interface MainViewController : UIViewController {
NSString *selectedProjectName;
NSString *selectedCategory;
}
#property (nonatomic, retain) NSString *selectedProjectName;
#property (nonatomic, retain) NSString *selectedCategory;
#end
MainView Implementation
#implementation MainViewController
#synthesize selectedCategory, selectedProjectName;
and if you need it..
ProjectView Implementation
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"masterSegue"]) {
MainViewController *vc = (MainViewController *)[segue destinationViewController];
LogValues *lv = [LogValues alloc];
lv.project = #"Test Project Name";
vc.selectedProjectName = lv.project;
}
}
Ok, your problem is that you're not returning to the same instance. You've missed one very very important thing about segues -- they ALWAYS instantiate new view controllers. So, when you use a modal segue to go "back" to the main view controller, you're just creating a new instance of that controller. You should never go backwards (to earlier controllers) in a storyboard using anything other than an unwind segue. Unwinds are the exception to the rule about segues always creating new instances.
So, you have 2 choices. You can either use an unwind segue, which is nice, because you can still implement prepareForSegue to send data back to the destination controller, or you can not use a segue at all, and use dismissViewControllerAnimated:completion: to go back, and use a delegate to send back the data.
So of course immediately after posting I see a thread in the side that I believe helps. The solution was to store the values in the AppDelegate which is working fine.
I feel however there are other ways to achieve the same result without having to rely on the AppDelegate and would love to hear other solutions.
I have view controller embed in navigation controller with one property (nonatomic strong NSMutableArray *myData), when I am pushing second view I am also passing my array data to this view using this method:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"secondView"]) {
SecondViewController *svc = [segue destinationViewController];
svc.myDataInSecondView = self.myData;
}
My question is: Why if I change any values in my myDataInSecondView array and than I will come back to first view my values in myData array are changed as well? I always thought that I have to use custom protocols and delegates to pass any data back to the previous view.
The way you're doing it is a very common way of sharing data between view controllers. The second view controller has a property that can be set by the first view controller. The property is a pointer, the same as in the first view controller. Both point at the same place in memory, so either view controller can change that same data.
If you don't want the second view controller to alter the data, set the property as copy.
#property (nonatomic, copy) MyData *myData;
In my app, I use a storyboard and segues, and I often pass data to the destination view controller before doing the segue, as follows:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.destinationViewController respondsToSelector:#selector(setMyData:)]) {
[segue.destinationViewController performSelector:#selector(setMyData:)
withObject:myData];
}
}
It works everywhere except in one place. The selector gets called, the data gets set, but when the segue completes and the destination controller appears, it doesn't have the data I just set. After printing the view controller's id in both the source and destination view controllers, I found that the segue.destinationViewController in the code above is a DIFFERENT instance of the view controller than the one that gets displayed. What's going on here?
[UPDATE 1]
I looked into the lifecycle of the destination view controller, and it first gets loaded during the segue execution, but AFTER I set the property on it! This means, that when I call performSelector on it, the view controller object is not initialized! This is why the data I set doesn't stick. t don't understand why is this the case, and why this same approach works in the other parts of my app.
[UPDATE 2]
Posting the code of setMyData by request. At first I didn't have this method at all, because locationToOpen is a public property. I only added it to ensure it gets called and to print the debug info.
- (void)setMyData:(MyData *)myData
{
DLog(#"self: %#", (id)self);
_myData = myData;
}
I would do it as follows -
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"NextSegue"])
{
DestinationViewController *dest = [segue destinationViewController];
dest.myData = self.myData;
}
}
And in the DestinationViewController.h, you should create a property -
#import <UIKit/UIKit.h>
#interface DestinationViewController : UIViewController
#property (nonatomic, strong) NSObject *myData;
#end
And also, make sure to synthesize the myData property in DestinationViewController.m -
#interface DestinationViewController ()
#end
#implementation DestinationViewController
#synthesize myData = _myData;
// other methods here
#end
I had this same issue. It turned out for me that the target ViewController property I was setting in my prepareForSegue: code was declared as weak because I had copied and pasted the property from one that InterfaceBuilder auto-created, but mine was not a Storyboard object. So my property was being released and zeroed by ARC on exit from prepareForSegue:. Making it a non-weak property fixed it.
I had a similar problem where the ViewController I was doing the segue to changed at some odd point,
after a looking around a bit it seems that the segue created a new ViewController.
To solve the data passing problem I used notifications.
I know this thread is old and solution should be found. But since the final solution is not posted here, I would like to list one of the possible root cause (which is the one in my case). I had the same issue, trying to set the variable in the destination view controller of the segue. The root cause is that I forgot to instantiated ([[Class alloc]init]) the object variable. I need it in my case because I am setting the properties of the object instead of pointing to other object. Hope this help.