How to Handle an Indefinite Amount of TableViews in an iPhone drill-down app - iphone

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.

Related

How to speed up slow loading of segue to table view in iphone app

I have a welcome screen which leads to a table view.
When users tap on a row they are taken via a push segue to a detail view. This loads quickly.
There is also another push segue possible to another table view but this is slow loading.
I think this is because it contains a search bar and data which have to be loaded.
Is there any way I can instantiate this table view when the program loads rather than wait for the segue? The class for the slow loading table view is called BSGlossaryController.
I was thinking something along the lines of myGlossaryController = [[BSGlossaryController alloc]init] but am not sure.
If you want the BSGlossaryController to instantiate at startup, you should delete the segue to it, instantiate it at startup, and push to it manually. You don't want to use alloc init to instantiate it though, that will create a different one than the one in your storyboard. You want to use the UIStoryboard method instantiateViewControllerWithIdentifier: to instantiate it (and make sure you give it an identifier in IB). When it comes time to push to it, you'll want to hook your button (or whatever you're using to trigger the push) to a method that uses pushViewController:animated: to do the push.
If you do this at startup (in the app delegate), then you'll have to assign the newly created BSGlossaryController to a property, and access that in which ever controller you're going to push from. If you can wait to instantiate it until that controller (the one you're pushing from) is on screen, then you can create it in that controller's viewDidLoad method.
Typically, you don't want to load one giant chunk of data at a time. If the chunk is large enough to significantly slow down your view loading, it's a good bet that you need to rethink your approach. Memory issues aside, loading large amounts of data at one time will block the UI of your app as it's loading. This will leave the app unresponsive and the user will wonder what is going on.
You can handle loading large data sets in a few different ways -- presented in order of preference:
Use an NSFetchedResultsController to load your data. This will automatically take care of caching and chunking the data so responsiveness and performance are maintained.
Break your data into smaller subsets. The screen can only display so much data at a time, so it's pointless to load data into memory that isn't currently being presented. Bring in new data as the view requires it.
First present the view (without data), display an activity indicator with a message informing the user that the data load is happening, then bring in the data asynchronously on a background thread. This approach will at least not leave the user wondering what is going on.
Once you post some code and I have a better idea about what you are trying to do and why, I can give more specific answers.

Reloading subviews of UINavigationController

I'm kind of new to iPhone development so bear with me.
I have an application wherein I display a lot of data in a tableviews, edit it in a detailview etc. However, I also have a login-system.
The problem I have is that I can't figure out how to reload the subviews of the NavigationController when I've logged out, or how to dealloc it completely and reinitialize it upon a succesful login.
This means that data from the last user who logged out is still present in my tableview when I log in as another user, as the data is set to reload only when the view loads for the first time.
Thankful for any and all contributions.
There are probably several ways you could go about this; it's up to you (and without more information about your app, I can't suggest a particular solution). You might consider:
-viewWillAppear: — this method is called on any UIViewController subclass when it's about to (re)appear as part of a UINavigationController stack (or tab bar controller, etc.). You can clear out fields, etc. This is mostly useful when a view controller reappears (being uncovered or switched to), because you usually create a new view controller instance each time you display one.
Notifications and delegates — your view controllers (and other objects) can communicate with each other about when a logout occurs, and reconfigure themselves as necessary.

ViewController design question for complex layout

I'm building my second app, and I'm trying to learn from the places I stubbed my toes on the first one.
Just as in the last app, I have sections of my app that feature a view with buttons along the bottom (basically a custom tab bar) that trigger the switching of the contents of the main, big area of the screen. One is a map view, one is a table view, one is a grid view, looking at the same objects in three different ways.
In my last app, I had each of the content options be a separate view, managed by separate ViewControllers. That worked, but there were places it was awkward. Passing data among those VCs was a little tricky (especially passing back upstream), and I was totally confused by my nested view controllers not having access to self.navigationController, for instance. It could be argued that I now know how to work with that scheme (and I do), but I'm interested in a Better Way.
I'm now thinking, maybe that whole thing should be ONE view controller, and it should have separate top-level UIView objects that it swaps in and out when the tabs at the bottom are clicked.
Problem is, two of my nested views have tables on them. So I'd need to either write REALLY complex UITableViewDelegate methods to figure out which table I'm talking about, or create separate UITableViewController subclasses to manage my table data. Either way, this just eliminated most of the simplicity I was hoping to achieve by keeping it all in one View Controller.
The other thing is, having those content views be UIViews inside the same view controller has some ramifications. There's no load time to swap views, but I'm burning memory I don't need to, if the user never visits one or more of those view alternatives.
Thoughts?
Problem is, two of my nested views have tables on them. So I'd need to either write REALLY complex UITableViewDelegate methods to figure out which table I'm talking about, or create separate UITableViewController subclasses to manage my table data.
A table view datasource/delegate does not need to be a view controller, it can be any object. So you could write two custom classes that acts as datasource/delegate for the table views.
The other thing is, having those content views be UIViews inside the same view controller has some ramifications. There's no load time to swap views, but I'm burning memory I don't need to, if the user never visits one or more of those view alternatives.
You should load the views lazily in that case, i.e. do not load anything before is is needed. And release stuff that is not needed at the moment when you receive a memory warning.

Is it bad practice to create unique view controllers for different tabs that do essentially the same thing?

Ok so basically I have a UITabBarController as my root view controller. I have three tabs that will all have UINavigationController objects nested in them, controlling three table views each.
Each mode will access the same database in the same way, but just sort by different variables. Very similar to the way the iPod app works - whether you narrow down your search by Artist or Genre, you end up at the same "detail view" (the song playing).
My question is, should I link all three tabs in Interface Builder to the same UINavigationController, but just populate the table depending on the selected tab? Or should I create completely independent objects for each tab, and copy and paste code?
The first way seems more efficient and flexible, but the second seems like it will be a little more explicit and easy to read!
Thanks for any help :)
I think clearing the navigation controller stack on every tab switch (assuming it is not hidden when the non-uppermost navigation child is shown) would be much more resource-consuming than having all three/four UINavigationControllers available all the time (mostly for quick tab-switching).
Further, if the owning UINavigationController is the only object that retained (owns) the UIViewControllers on the stack, then you will also deallocate your UIViewControllers should you decide to reset the navigation stack (1-Nav scenario). Assuming of course they are not "statically" present inside a NIB.
TL;DR version
I'd use a separate UINavigationController for each tab, in a low memory-footprint app it will increase the visual performance of your tabs.

Passing data from modal navigation controller to parent controller?

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