I'm working on an app which allows users to send messages to people which can be selected from a variety of sections. One of these sections happens to be the contacts stored on the phone book (other contacts are selected from an online DB).
As such, I have a 'master list' of recipients. If the user, for example, chooses to select a contact from their online account, this will push a new view that will allow the user to select which contacts to add to the recipient list. When they go back to the master list, they should see the chosen participants selected there. If they were to return to add another person, the selected contacts should all be checked (each contact is displayed as a UITableViewCell).
This is working fine for all the online contacts however I'm having some issue implementing this functionality for local contacts using the ABPeoplePickerNavigationViewController. To check the selected contacts when the user returns to this screen, I need to have some way to now when the view has loaded.
Are any of the view delegates (i.e. ViewDidAppear) guaranteed to be called after the table has been loaded (I'm pretty doubtful on this one)?
If not, I had thought of counting the total number of rows in the datasource (using numberOfRowsInSection:) in a timer. If half a second or so has passed without the count incrementing, it should be a safe bet that all the records have been loaded. Somehow, however, I'm not so sure if this is going to work. It might be that all the records will be loaded in a single hit.
Any ideas on how to achieve this? Are my suggested methods workable? Is there a different workaround?
If you make view transition by standard methods, like presentModelView: or pushViewController:, then the methods about viewWillAppear:, viewDidAppear, viewWillDisappear:, and viewDidDisappear will be called. But if you make view transition by UIView's instance methods, like +transitionFromView:toView:duration:options:completion etc, then you have to call those viewWillAppears methods manually.
All UI related method will run in main thread, and ABPeoplePickerNavigationController is a sub-class of UIViewController. When it's view has been loaded, it will call -viewDidLoad. At this moment, it means the view has been loaded, maybe this view doesn't appear. So, the -viewWillAppear: should be executed after -viewDidLoad. But, the -viewDidLoad maybe executed before return from -init in practice. In my experiment, I set view's backgroundColor inside the -init, then when I use self.view.backgroundColor = [UIColor black], at this moment the view has been loaded. It means the -viewDidLoad will be executed when I set background color of view.
Related
I get used to put either of viewWillAppear and viewDidLoad, it's OK until know. However I'm thinking there should be some rules that guide when to put into viewWillAppear and when to put into viewDidLoad?
Simple rule I use is this. viewDidLoad is when the view's resources are loaded. The view is not drawn onscreen yet. So calculations and code dealing with the geometry and visuals of the view should not be put here. They should be in the viewWillAppear or viewDidAppear method.
Also viewWillAppear can be called multiple times
When a popover/modal view is displayed and remove
When an alert view/actionsheet/uiactivityController's view is displayed and removed.
For these reason, viewWillAppear should not contain codes that takes longer to finish. (at least the code running on the main thread). Neither should codes that only needs to be run once per view display.
There are more I am sure but these are simple to remember and I hope it helps.
viewDidLoad: Alerts you that a view has finished loading
viewWillAppear: Runs just before the view loads
viewDidLoad is things you have to do once. viewWillAppear gets called every time the view appears. You should do things that you only have to do once in viewDidLoad - like setting your UILabel texts. However, you may want to modify a specific part of the view every time the user gets to view it, e.g. the iPod application scrolls the lyrics back to the top every time you go to the "Now Playing" view.
However, when you are loading things from a server, you also have to think about latency. If you pack all of your network communication into viewDidLoad or viewWillAppear, they will be executed before the user gets to see the view - possibly resulting a short freeze of your app. It may be good idea to first show the user an unpopulated view with an activity indicator of some sort. When you are done with your networking, which may take a second or two (or may even fail - who knows?), you can populate the view with your data. Good examples on how this could be done can be seen in various twitter clients. For example, when you view the author detail page in Twitterrific, the view only says "Loading..." until the network queries have completed.
I'm working on my first app and I've issues on how to layout some of its logics.
Basically, what the app is supposed to do is to show a first screen when launched where user can fill in some values and press a button that opens a tableview which shows results. The first screen (view), outlets and connections are all working fine. The issue I'm having is how to leave this "home" search view and show the results to the end user on a table view. Right now, I've only 1 view with its related View Controler and this controller handles the tasks of taking user inputs and get results throughout a HTTP post request.
I need your guidance...Thx in advance
Stephane
Is there a reason that this all has to happen on one screen? iOS is set up to allow for this to happen very easily and (I think) attractively by using a UINavigationController and pushing in a new view controller (could be a UITableViewController or simply a UIViewController that contains a UITableView).
If you MUST have all of this take place in one view, Swastik is correct that it will require some view acrobatics. One way to do it attractively is to use the UIView animations introduced with iOS 4.
Here's Apple's UIView documentation: UIView Class Reference
Specifically, check out the CLASS methods of:
1. animateWithDuration:animations: (with or without completion:)
2. transitionWithView:duration:options:animations:completion:
Note that these methods will require you to learn a little bit about blocks, but it's worth it and I think blocks give tremendous power!
With the methods mentioned above, you could fade out your form and fade in your tableview, or maybe just move the form off-screen while the table view flies in. The possibilities are limited only by your imagination.
u can add a table in ur xib.Initially make it hidden, & when u need to show it unhide it & also if u want to update table's data , you can reload the data of the table.
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.
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'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.