Access textField.text variables from different view controllers - ios

I'm creating a login page with multiple view controllers and at the end of all the view controllers there will be a create account button. I want to be able to access all of the textField.text variables from every view controller. I tried to use core data and structs. However, xCode wouldn't compile it and would spit errors. Here is a ScreenShot of all the view controllers I need to pull data from: http://prntscr.com/lqt9b4

"I want to be able to access all of the textField.text"
Do not do that. You should treat a view controller's views as private. You should create a model object (a class) and have each view controller change the relevant field(s) of the model object.
Alternately you can use a struct and pass a new copy each time it changes (since structs are value types.)

Maybe reconsider how to do this. A sequence of VCs like this would require passing each part of the puzzle onto the next. If you want four VCs to work together, it maybe better to use a UIPageViewController-style arrangement, with the overall view controller then pulling data from each sub-VC.

Related

Swift Container control from parent view

I have two views, one is a main view, and another is a container view. What I wish to do is send a variable to the child and for it to execute my function. How do I tell the child view these two things from the parent view?
A few problems I have had is, ViewDidLoad does not work in container view. and when I tried to segue the information it also said that a periotical programming or container has been implemented indicating to me that the container can not be segued.
What I am trying to do is have two tables, the first table has a list, and the second table changes depending what you select in the first table. So I decided to seperate the two tables using a container view which is working for the most part.
First of all, you should note that any containers you create will be available through the childViewControllers property on your main controller. This gives you a link between the main controller and the child controller.
Now what you are trying to do is to change something in the child's table if the parent's table changes. There are many ways to do that, but in this case there is a pretty simple technique: you always know when the parent's table cell selection changes, in didSelectRowAtIndexPath. So what you need to do is simply within didSelectRowAtIndexPath, when the row changes you call a method in the child controller that passes in whatever information about the currently selected row you want to use. That method will change the table and do whatever else you want to do within the child view, since it's part of the child controller.
Using delegates or KVO or any other technique is overkill and bound to make the code much less readable.
You can use delegates to do that. Delegates are just protocols you can implement to pass data to another view:
protocol nameOfProtocol {
func someFunc
}
You can search for a tutorial or examples easily, that way you can visualize it much better than just looking at some code here.
If you want viewDidLoad to work you can create a view in storyboard, give it an identifier name (and also setting it to the correct view controller) and you can declare it like:
let viewController = storyboard?.instantiateViewControllerWithIdentifier("viewControllerName") as! ViewControllerName

What is the proper way of passing data from master to detail view controller?

I'm studying developing for iOS and while building a simple app which loads data from database and shows it as a tableview, I've got some issues which I fail to understand so far.
The master - detail controllers' classes were created by me, not by the XCode template, if this matters.
I try to pass data from master tableview controller to detail
controller. The data is as simple as a couple of strings. I use
segue for this purpose. In prepareForSegue method I do the
following:
if ([segue.identifier isEqualToString: #"DetailsSegue"]) {
DetailsViewController* dvc = (DetailsViewController*)segue.destinationViewController;
NSInteger selectedRow =[self.tableView indexPathForSelectedRow].row;
dvc.nameLabel.text = [NSString stringWithFormat:#"%#",
[[self.entitiesArray objectAtIndex:selectedRow name]];
...
}
The problem here is that dvc.nameLabel is nil. And I guess, that
is possibly because the controller has not been fully created yet.
Well, the dvc pointer is not nil, but I don't see the log in my
init method, so my idea that it was not initialized.
I decided to create an instance variable of DetailsViewController
and in prepareForSegue set it:
dvc->name = [NSString stringWithFormat:#"%#",
[[self.entitiesArray objectAtIndex: selectedRow] name]];
and then I set nameLabel property in viewDidLoad method
And it actually worked! So I guess I wouldn't be able to set instance variable of an unitialized instance. But I did. So what was wrong? And I feel this is not the way people do it,
as to have one more variable that holds the same thing seems
redundant.
So what is the proper way of passing a variable (in my case NSString) using a segue to another controller?
Thank you guys for help
The problem in your code is that you're trying to manipulate the other VCs views. Don't do that. Instead, you should create properties in the destination view controller to hold the data you want to display.
As the other poster said, it makes sense to create a class that contains the data for a record, and pass that. You might have your master view controller's model be an array of these objects. The master would use the data objects to populate a table view. When the user clicked on a row to open a detail view, you'd pass a copy of that data object to the detail view controller in prepareForSegue.
The detail view controller could then edit it if desired, and pass the edited object back to the master view controller if the user saved changes, or simply discard the edited object if the user cancels.
Yes, you could use a singleton to save your data model.
If you want to pass data, you're doing it reasonably. UI elements are not guaranteed to be initialized until the main view of the view controller has finished loading, so a non-UI variable is fairly common.
For a more complex app or one that you expect to grow and maintain, the better approach would be to create a class (or classes) that make up the application's data model. Anything that modifies shared data sends updates to the model and anything that needs to use shared data reads from the model. Among many positive results from that strategy, one is less crosstalk between view controller.

Best way to simplify/refactor tableView code setup in objective-c

Every single time I need to create a simply tableview that is populated by a simple data set retrieved from my web server which has its code executed like this: SELECT * FROM table I find myself spending two blady whole hours trying to get the new view controller up and running as I try to update some variable names, copy and paste the required code from my previous view controllers. etc its ridiculous.
This is the end result for all my view controller pages where each will contain different data sets depending on the web service urlĀ being called:
Here is a link:
Link to downloading staple code .h .m and .xib files
This view controller contains a few simple elements seen throughout all data viewing pages:
UITableView
Titled header views
table indices.
refresh table control feature
data connection retrieval code
data connection succeeded
data connection failed
setting up all my bloody delegate and data source methods.
I find myself having to copy and paste all the staple code, functions, variables, properties, and IBOutlets; and to be frank, its getting ridiculously paintaking to have to repeat the same procedure over and over again but changing variable names between the different view controllers.
This is why I believe people create simple component like structures that make it easy for users to get tables setup and up and running.
How can I reduce this big chunk of code:
to something that will allow me at most do this:
Create a new view controller
Setup xib file
create appropriate IBOutlets, and hook them up to the xib.
Here's where it needs to change
I need to now simply able to write something like this the next time I am goin to create another data viewing View Controller:
[self setupTableForDataSetType:]; //This will make sure the tableView knows which data set its dealing with and so therefor know which DataModel classes to use
[self retrieveDataWithWebServerURL:]; //of course so that the connection code can make the right server connection with the URL given for the data set required.
Thats it. So that it is super easy for me to create the tableView pages desired and show the results quickly! Atm I have the same code everywhere in different view controllers.
Whats the best way to go about doing this?
Create a viewcontroller with all your customizable values as properties and reuse changing its values.
Well, subclassing is probably the best (maybe only) way. I've done something like this for tables with an index, since they're a bit of a pain to set up. I created a IndexedTableViewController that handles almost all the load. I make my app table view controller a subclass of that controller, and then I only need to feed a simple array of custom objects to the method, convertArray:usingSectionKey:secondarySortKey:(implemented in the IndexedTableViewController) which creates the sections and the index. The only other method I have to implement in my app table view controller is cellForRowAtIndexPath:(though I would have to implement more, especially didSelectRowAtIndexPath:, if I were doing more things with this table).
Your needs sound a bit more ambitious than this, so it would take quite a bit of work to make a superclass that would be general enough to work with most of your apps. A method like setupTableForDataSetType: could be quite complicated if it needs to handle many different data types.

The correct way to communicate between several different view controllers in Objective C

I have an app that was extremely simple until today. It had a tab bar view controller with 3 tabs. The middle tab was a camera, and the other 2 were table views. The tab bar view controller was the central hub for all the data in the app. So from there, I would set a table's data array as:
(PLEListViewController*)[self.viewControllers objectAtIndex:0] setList:newList];
Obviously, PLEListViewController is my UITableView subclass.
So now, I want to wrap the table views in a UINavigationController, which is fairly simple. But now, that line of code turns into:
[(PLEListViewController*)((UINavigationController*)[self.viewControllers objectAtIndex:0]).topViewController setList:newList];
There are 15 lines in the code that do this, which is not pleasant.
So my question: what is a more elegant way of doing this that I'm missing?
It's good that you're asking this and seeing the issue now. Your problem is can be found in your question. The answer to "the correct way to communicate between several different view controllers in Objective C" is "don't." Specifically, your mistake is here:
The tab bar view controller was the central hub for all the data in the app.
A view controller should never hold any of the data in the app. Your data should live in your model classes. All the view controllers should talk to the model classes. They should very seldom talk to each other. That's the heart of MVC.
So, you move your "list" (whatever that is, doesn't matter) into some model object that all the view controllers know about. That model object can be a singleton, or often better, it can be passed to the view controllers when they are created. When things change, you change the model. And in viewWillAppear: you update your view controller to match the current state of the model.
Never assume that a view controller exists when it is not currently on screen. If your design requires that a non-active view controller exist, then your design needs fixing.
You need to work with your architecture. Make the appropriate datasource and delegation protocols to ensure your classes can communicate anonymously. What you currently have is very inflexible and it will get worse as your app grows/changes.
You want to make things more loosely-coupled, instead of coding explicit traversal of links between your objects in your code.
Assuming you have one data model that is displayed in various places in your application, I think there are 2 approaches that could help...
One is to use your view controller hierarchy.. For example, use [ self enclosingTabBarController ] to find your closest parent tab bar controller and get it's data model property. Substitute -enclosingTabBarController with what works better for your application.
The other approach would be a "data model as a singleton" approach. For this you can either
move the data to your application delegate and access it via ((MyApplicationDelegateClass*)[ UIApplication sharedApplication ].delegate).dataModel
or
have a singleton data model object for your app, and access it via [ MyDataModelClass sharedModel ]
In any case you are moving to a looser coupling, which requires less explicit traversal of links between objects in your app. Less is more!

UITableViewController data source from coredata

I have found two ways of populating UITableView with data from coredata. One way is to use NSFetchedResultsController and implement the delegates for update controller:didChangeSection. Other way is to copy data from coredata to local array of Managed objects. Handle the updates on local array and saves the changes to managedcontex.
Both could be found on developer.apple.com.
I would like to hear pros and cons for each metod?
Thanks.
It is better to use NSFetchedResults controller, because your current view controller may not be the only one changing the data. It may happen in the background, or through some other view controller (for example, if you have a split view controller, you may be changing data related to a record in the master view controller, in the detail view controller). In those cases, you want your table to automatically reflect the changes. In extremely simple cases, where you are the only view controller in town, it may be easier the other way, but do it the right way and you will be happy.

Resources