I have a UINavigationController with two UITableViewControllers (A and B).
A is displayed first and when the user taps a row on the display, A loads UITableViewController B and pushes it onto the stack.
The user can then update some data in B's UITableView which may result in the tapped row on A's UITableView needing to be updated.
The problem I'm trying to nut out is the best way for UITableViewController B to let UITableViewController A know that it needs to update the row.
I've thought of a number of different ways of doing this including:
Having A store the IndexPath and a reference to B so that when ViewWillAppear is called, it can check properties of B and then reload the cell at the IndexPath.
Have A monitor the core data NSMangedObjectContext through the notification system. Both controllers feed their data from core data. A would still need to store the IndexPath.
Having B somehow (through the UINavigationController?) look up the previous controller (A) and tell it that it needs to update the row.
None of these seem that eligant.
Is there a better way to do this?
The second one is the most elegant to me (and you could tweak it with KVO instead of notifications).
And it is since it does not load B with more responsibilities that he needs (B cannot even know about A) whereas the third option makes B notify A. Plus it will be more independent from changes than the first one (because you are obliged to check the situation before A is loaded, and you use ViewWillApperar:, but this situation can change in the future)
why not use NSNotificationCenter?
Related
I have 4 seperate tableViews which, when selected do a modal segue to a tabBarController containing four tabs. Of those four tabs they all have a common tab which performs an XML parse.
Ive done some reading and it seems I have three ways of doing it.Either I can
A) Use a class to define where the data is coming from but I don't want to instantiate all the options
B) Find out what the current TabBarController is and use that as a condition
c) Find out where we segued from and use that data
Which would be the best way to perform this action, and how would I do it(the segue is working with data being passed). Please note that I am not using the UINavigationController.
I basically want to end up with a switch performing the functions based on where its coming from.
Well, you could use a singleton.
You could also create a data model and pass pointers to it to your various classes, as needed.
As for using a switch, just setup your data with an index of some sort, such as an array, and pull it based on the current tab bar object. If you plan to use UITabBarController then call its selectedIndex property to know which tab bar item is selected.
I'll try to explain this as best as i can, but i appologize if it gets too confusing - I've been stuck on this problem for many hours now.
In my application i have a search screen where the user will be able to select a bunch of criterias to perform the search by. Some of these criterias consists of fairly long lists of values to choose from and therefor i want a tableview on my searchscreen which have 4 rows - Each row representing a criteria that the user can set.
Once the user clicks on a row i want to push a new window in my navigationcontroller which consists of a new table containing the selectable values for that criteria - Once the user clicks on one of these rows on the new window, i want the selected value to be sent back to my main searchscreen and pop back to my search screen.
What would be the best way to do this?
Elaboration:
My searchscreen is called SearchViewController and is contained in a navigationController.
SearchViewController contains two sliders and a tableView with 4 rows called "Searchtype", "Property type", "Salestype", "Area" and a searchbutton. If the user clicks on "Searchtype" then i want a new view to be pushed in the navigationController which should contain a new tableView with a bunch of rows representing different possible values for the "Searchtype" criteria - The same goes for all 4 rows in SearchViewController.
When the user clicks on one of the value rows in the newly pushed tableView i want that tableView to be popped away and the selected value sent back to the SearchViewController allowing the user to either select more criterias or push the search button to actually perform a search based on the selected criterias.
But i can't figure out the best way to do this?
I really appreciate any help i can get - I'm going nuts trying to figure this out :)
Btw. i don't use Interface Builder - All UI elements are coded manually.
5 ways to do it here:
1) Let the Search View Controller be the delegate of action in the Search Type View Controller, so that when the user selects a search type, it will be informed. Use protocol for proper check at compile time if you want, and remember to use assign instead of retain for the delegate, to avoid circular reference.
2) Set the UINavigationController delegate to Search View Controller (or whatever class you want to control it), and listen to the event when the Search Type View Controller is popped out.
3) Implement a "refresh" function in viewWillAppear: as suggested above, but this is not recommended, because the implementation of viewWillAppear: sucks and not reliable at all. Maybe good for simple app, but when the structure of your app gets complicated, forget it.
4) Use NSNotificationCenter. Your Search View Controller will observe all changes to search criteria, and in each child view controller, when the user changes it, post a notification. This is more complicated, but much more powerful and flexible than all the methods above.
5) Similarly, you can use Core Data to store all search criteria in an object, and listen to changes in that object using KVO. This is a bit more advanced and may be overkill, but if you know KVO, it makes life much easier in Objective C, so probably worth taking a look anyway.
Btw: It's good to do all the UI by hand coding to understand the concepts at first, but try to move to Interface Builder whenever you can. It is a much recommended way to work (there are countless threads on this in Stackoverflow or on the web, with more elaborated discussions on why IB is better).
I have a fairly simple setup: RootViewController (which is a UITableViewController). Each cell in it shows some stats for a different person. You can tap on any of these cells to push on a DetailViewController (UIViewController), and modify the stats (which are stored in a model object). After the user is done modifying the stats for that person, they click the Back button, causing popViewControllerAnimated to get called.
My question is: What's the best way to know in the RootViewController that the stats for this player have been changed, and updated the cell accordingly? Do I have to record in the RootViewController which cell was tapped, and then call the appropriate setNeedsDisplay after the DetailViewController completes? And if so, which method should I do this from? viewWillAppear?
Or is there a nicer way? This seems like it'd be a fairly common task, and that I'm missing something obvious.
This depends on how your model is designed and whether or not you're using Core Data.
The basic principle is to observe the properties of your model objects that might change in the detail views. When something changes in the detail controller, somehow mark its table cell as dirty. Then, when the table view becomes visible again, get the changed cell with [tableView cellForRowAtIndexPath:] and reconfigure the cell. The cellForRowAtIndexPath: method will handily return nil if the cell is not visible which will keep you from spending time updating cells that don't need it.
If you're using Core Data (and you probably should be), NSFetchedResultsController does almost all of this work for you. It will observe your model objects and send the controller:didChangeObject:atIndexPath:forChangeType:newIndexPath: message to its delegate for each changed cell. Then, you can make the proper changes to the table view.
I recommend creating a new Xcode project using the Navigation-based Application template with the Use Core Data for Storage checkbox ticked. The template has a good default implementation of the aforementioned pattern.
I've Created a UITableViewController subclass. Do I only need one controller? Do I just instantiate multiple instances of that one subclass?
The iPhone App I'm building will start with a Table of a list of people. If the user taps a person, a new table will be pushed in with a list of Companies they've worked for. If the user then taps a company, they'll see a list of Job Positions. And if they tap a position they'll see a list of people holding those positions.
This could go on forever, and the user could always back up the list.
The App Delegate instantiates the Navigation Controller and the Table View Controller and then pushes it onto the Navigation Controller. But when a user taps a row, now the TVC is creating another TVC.
Is that right or should the
AppDelegate be instantiating all
TVC's? Or does it work out since
they all get pushed onto the Nav
Controller anyway?
Does each Table View instance
need to have a different name or can
they all be called 'mainTVC' or
something like that?
tableViewController *mainTVC = [[tableViewController alloc] init];
Won't I run out of memory? Do i
need to start dropping Table Views
when they're 2 or 3 levels away from
current, and then re-create it if
the user backs up to it?
No need to create multiple TableView's, what I've done in the past is simply re-bind to a different datasource. So keep one TableView and have a datasource for people, then companies, etc...
I'd create a view controller for each type. Presumably you'll want to have special display characteristics like a custom tableview cell to display job positions slightly differently then you would people names.
Other then that, #Ben Gottlieb's answer should work quite well. Use lots of view controllers and handle the didReceiveMemoryWarning: method.
One more thing, if the user drills down so far that you want to say they'll never go all the way back (sort of like having an undo stack) you can use the setViewControllers:animated: UINavigationController method to reset the stack to a certain size (say 15 to implement an 'undo buffer' of 15). With this method you can make sure that the first view controller is always your root view controller and the rest are all drilldown instances.
Option number (2) looks good. You can push quite a lot of view controllers onto the stack before memory becomes an issue. The system will clean up most of the heavyweight memory hogs (ie, the views) in the didReceiveMemoryWarning: method. If you're creating a lot of in-memory structures, you may want to clean them up in that method (be sure to call the inherited method).
To answer your third question, as long as you don't have huge data stores in memory, memory shouldn't be an issue. You SHOULD NOT under any circumstances "drop" tableviews - this would lead to crashes(and there's no way to do non-FILO additions/removals to the navigation stack anyway). Under memory pressure, you should only free "nonessential" items like caches. However, this shouldn't be an issue.
Also, if you have more than 3 or so levels, chances are you need to rethink your UI. If users are drilling down 10 levels, it will be tedious to navigate the stack back.
I'm starting out in iPhone development, and I'm trying to do a Contacts-style controller to add items to a table. I've got the two controllers designed, but I can't seem to figure out how to pass data between them. How can I get data from the modal controller to its parent?
Just trying to call methods on parentViewController won't work (and results in compiler warnings and crashes). I've considered moving the data out of the controller itself (which is going to happen anyway, I'm just trying to keep things as simple as possible for now), but even then I still have to somehow tell the parent view to refresh its data. Again, how can I do this?
I've considered moving the data out of the controller itself (which is going to happen anyway
I think now may be the time to follow that consideration and create a separate "ContactList" model object to store your data.
Your modal view controller just adds new "Contacts" into the "ContactList".
Your TableViewController should observe the same "ContactList". As items are added/removed to/from the "ContactList" your TableViewController will simply add and remove rows from its tableView.
In this way you will keep each ViewController independent, your code will be more flexible and adding/removing single rows will be much more efficient than reloading an entire tableView.
You either keep a link to the sub view you create and ask it for data that has changed on return, or else ad yourself as a delegate of a subview and have it call you back directly (which does work if you have a valid reference).
I had the same question and found this sample code: http://developer.apple.com/iphone/library/samplecode/LocateMe/Introduction/Intro.html
Helped me a ton and was pretty easy to figure out from the code.
In short, use delegate.
I would suggest you have a look at Lecture 11: Text input, Presenting content modally (May 6) - iPhone App Programming course offered by Stanford. Search for it on iTunes U.
Download this sample app if you want to know how to implement delegate: http://www.stanford.edu/class/cs193p/downloads/11-Pickers.zip