Loading background data and launch image - iphone

I have read the apple guidelines and I know it says you shouldn't do that but hear me out as I would like to know if what I am doing is bad practice.
When my application loads up, in the app delegate, a web call is made which sets up the order of the tabs, as well the content within it. Web call is like this
WebCalls *wc = [[WebCalls alloc] init];
[wc setWebCallDidFinish:^(NSString * json) {
// set up tab order here, as well as stores the JSON in a file on the phone
// Also code here to download images and cache them on phone
self.window.rootViewController = self.tabBarController;
[self.window makeKeyAndVisible];
}
[wc getData:phoneNumber];
Now this code works great but the problem is what will happen when app starts is
Launch image shows for a second (which is not very long, sometimes it's half a second or less so just annoying)
Screen goes black for about 2 seconds while json is parsed and images downloaded etc
Then first tab controller is shown
What I want is a seamless transition between the splash screen and the first screen so the user never sees black screen.
What I was thinking of doing is something like this
Change iPhone splash screen time
In the answer given, the guy pushes a view forward to be the splash screen. Would it be bad practice to push that view forward, and then in that screen do the web calls which gets json data, and downloads images, then dismiss the view and have the tabcontroller view become main view?
Or how else would I prevent this delay? Is it bad practice to have a large enough web call like this in AppDelegate?
If this is bad practice to push a view forward while doing background loading, what else would you recommend? Would it be better if I just make the tabController the main rootViewController first and do the webCall in the first tab shown instead, then update the tabs when this web call finished? I was considering this one, but the tab order could be in any order after the web call is made, so not sure what tab will be shown first.
Would be grateful for your input

In the answer given, the guy pushes a view forward to be the splash screen. Would it be bad practice to push that view forward, and then in that screen do the web calls which gets json data, and downloads images, then dismiss the view and have the tabcontroller view become main view?
This is the way to do it. It's generally bad practice to download stuff from applicationDidFinishLaunching, what happens if the phone is not connected to the internet?
Present a simple view controller (using presentModalViewController:controller animated:NO with a UIActivityIndicator and a label describing what's going on, and then dismiss it when loading finishes (or it it fails, just display an error and deny access to the app). Remember to also check for airplane mode and notify the user.

Related

Presenting Modal View Controller login screen

In my app there is authentication required, so when you launch one of the tabs on tab bar, "class A" checks are there credentials saved if not, "class B" modal view controller with fields to login launches.
So my question is : in which method in class A (loadView, viewWillAppear or maybe in another one) should be implemented checking if there are credentials saved and other stuff described above.
And my additional second question is:
is pushing modalviewcontroller correct way to show login screen, or i should do that differently?
Thank you for reply guys.
OH ! One More Thinh
And one more thing. I've done implementing LoginView by adding delegate and presenting ModalVC (Harkonian the Piquant's method). But in my tab bar app i have got very confusing problem. I mean when user taps login button (assume that everything was correct and he's able to secured data) how PROPERLY switch to tab where is secured info. I mean previously selected tab.
i did it by adding in
-(IBAction) login {
//some code
self.tabBarController.selectedIndex =1;
And it seem to work good but is it correct ?
I have a very similar use case in my app -- it requires a passcode to authenticate. After a lot of testing and tweaking I found the following design to be the best approach:
Don't use class A to launch your credentials VC -- use the app delegate instead.
For security purposes, typically you'll want the credentials VC to show before the user can view the underlying view. It's much easier to handle this in the app delegate than in a VC. In addition, you need to consider what happens when your app is backgrounded -- a screen shot is taken of the current state of the app. If you are using viewController A to show the credentials view, when the app relaunches the user will be able to see whatever sensitive information was visible on app close until the app finishes launching and VC A presents the credentials VC.
Don't insert your credentials view into an existing ViewController -- use a new UIWindow instead.
You don't ever want any other view to be able to sit on top of your credentials view. Ever. Even views that would normally always be on top, like UIAlertView. The easiest way to achieve this is to have a special UIWindow just for your credentials view. Show this window and hide the primary app window whenever you need to display the credentials view.
How does this approach look in practice?
If you are at all interested in how well this design works, you can check out the passcode feature in Audiotorium Notes for iPad. I spent a lot of time with this design to make sure it was as secure as possible.
If you have any specific implementation quests feel free to ask and I'll try to answer them.

NavigationViewController with WebView-containing View Controller

I have a problem with a navigation controller.
First of all, there is a navigationviewcontroller.
Also, there is A webviewcontroller-containing view controller, meaning that webview controller is loaded inside WEBcontroller.m
I made that when the WEBcontroller is loaded, it automatically loads google.com. The function is in the -viewDidLoad()
First, when the app is launched, navigationview loads WEBcontroller.m, then WEBcontroller loads google.com as intended.
Then, when I click any link in the google.com, navigationview pushes a new view with
[self.navController pushViewController:newWebController animated:YES];
[newWebController gotoUrl:[request.URL absoluteString]];
It, of course, works. The newly loaded(and alloc) WEBController.m loads gmail.com by calling "gotoUrl" function.
And, I click another links to go "gmail.com/help"
So,
google.com -> gmail.com -> gmail.com/help
Then, I close the app, and play some games... it makes iPhone free memory.
Launching the app again, the "gmail.com/help" webpage is shown. Then, I click the [Back] button which is at the navigationBar which calls [popViewController].
Then, the navigation controller properly go back to preceding WEBController.m which was showing "gmail.com" page.
BUT!! there is a problem. Because the memory was 'dealloc' by iPhone, the WEBController is loaded AGAIN with "google.com" page, not "gmail.com" page.
I've searched this problem but I couldn't get any.
Really thank you for reading and giving some interests to my problem.
I'm confused. You are using a UIWebView? If so, why don't you just let it handle the links/navigation? Why are you creating (and pushing) a new UIWebView for every link click? Technically speaking, a view controller needs to be able to handle being freed and restored from memory by IOS. This is done in viewDidLoad and viewDidUnload. But I don't think that's what you want/need here.

How do I implement an automatic jump to a detailed page if the user was on this previously (or fix my code for doing this which has a design flaw)

Any advice on how to fix this issue I have, or a better implementation design perhaps?
Requirement
Needed a way for the application at start up to take the user to the previous details page, if this was what they were on prior to quiting the application in their last session
If they were on the main screen of the app, then at restart they can stay here
The assumption is I'm working with UINavigationController and the main screen and details screen are built on a UITableViewController
My Implementation Concept
Put a check in "viewdidLoad" to see whether they were on a detailed screen, and then if so jump to this (refer to code below)
Issue
Works fine normally, however when I trigger a memory warning things screw up and I get nav bar weird behavior. For example I see the main page nav buttons, when it looks like I'm on the detail page content (UITableView)
My Analysis
From what I see when I am on the details page (appointmentsListController) and cause a memory warning in the simulator I see:
(a) the main page "viewDidLoad" actually gets called, which my concept didn't expect, so whilst I had hit the BACK button from the detailed view (UINavigationController) to go to the main view (RootViewController), in fact my code is run and it try's to throw the user back to the details page again
(b) I note in my logs after this point that [AppointmentListController viewDidLoad] seems to get called before the previous AppointmentListController dealloc method is called (i.e. like I was in controller A, went back to controller B, but got thrown back to A - and the initial dealloc for the first part didn't kick in until late...)
So I guess it's obvious my idea isn't too great
Question
Any suggestions on how to better implement my requirement? (how to check, which method to put them in)
Code
- (void)viewDidLoad {
[super viewDidLoad];
// My Implementation of the Requirements which seems flawed in the case there is memory warning triggered
if ( previousSelectedScreen >= 0 ) {
// Setup New Controller
AppointmentListController *appointmentListController = [[AppointmentListController alloc] initWithNibName:#"AppointmentListController" bundle:nil];
appointmentListController.screenToShow = previousSelectedScreen;
// Push new view onto stack
[[self navigationController] pushViewController:appointmentListController animated:NO];
[appointmentListController release];
}
}
Here's what I'd suggest: rather than having this logic in your view controller, but it in your application delegate. By constructing your navigation stack before displaying it you will hopefully avoid some of the weird things that can happen with nav bars, etc. To get rid of the memory warnings you may need to look at how your app allocates memory: it may not necessarily be to do with this.
Anyway - in your application delegate you can perform your check to see if the user was on a detail page when they exited. If they are, you can create an array containing the navigation stack (ie, Main Screen -> Details Page). You can then pass this into a navigation controller using its setViewControllers method. Once this is done, you can display your window and finish launching the app.

Preload UIView To Minimize Delay While Running Iphone App

I have an iphone app that has one view that needs to fetch a lot of data off of a variety of internet sites. Therefore, the amount of time required for it to load is unacceptable. I was wondering if there is any way to load the view during the 'applicationDidFinishLaunching' method so the delay is at the startup of the app instead of midway through navigation.
Thank you very much!
You want to load the view as quickly as possible, and then launch a background thread or asynch request to pull the data down.
Making your application sleep during initial load isn't advisable. I believe SpringBoard will terminate any application which takes longer than 30 seconds to finish loading.
It's a bad user experience to have the app do something without visible feedback to the user (animated UIActivityView for example)
Have you already considered loading the data asynchronously? While it's loading, the UI doesn't get blocked. For example you can show a nice loading-wheel when your app is loading the data. This is how all good apps do this.
If the initial view has a separate viewController than your 'data' view, you could add a reference to the dataView to the appDelegate and then do something like:
if (self.curAccountManager == nil) {
self.curAccountManager = [[accountManagerController alloc] initWithNibName:#"accountManager" bundle:[NSBundle mainBundle]];
if (![self.curAccountManager isViewLoaded]) {
UIView *tmpView = self.curAccountManager.view;
tmpView = nil;
}
}
This will load the view. But if it's doing a lot of loading, when the user switches to it, it might not respond well. I would suggest you follow the suggestion above and in your data view load the data asynchronously so you can at least show the user status or partial results.

modal view while importing data

I'll start with a confession here... I'm a real newbie to Objective-C & iPhone programming (started studying in February & coding in March), I have a project that's very ambitious for that level of experience & a very tight deadline to catch an opportunity to give my app a field trial.
My app is Core Data driven & downloads all of it's data on first run which is a choice made because it will be used on sites where 3G network access may not be reliable. I'd like to present a modal view while this happens, nothing fancy just a bit of text to explain, a progress bar or activity indicator, a graphic to pretty it up & button becoming visible when the job is done. I've tried a couple of approaches & failed dismally so no code for that as all but the XIB has been trashed.
At the moment I'm running this code in applicationDidFinishLaunching ...
[self checkDataAndLoadIfNeeded];
[window addSubview:rootController.view];
[window makeKeyAndVisible];
rootController is a TabBarController with nested NavigationControllers. checkDataAndLoadIfNeeded is a method that checks a default for the data being loaded & if it is not YES presents an alert. The delegate method for dismissing the alert then a custom class, DataLoader, which goes about downloading & importing the data.
What's happening is that the rootController view becomes visible before the alert does & the table on the first tab doesn't load any data until the next run of the app. I'm wondering if that data not loading is because I'm doing that in viewDidLoad & whether I'd do better to have it in viewWillAppear or viewDidAppear. When I tried loading the modal view I've built my rootController view still became visible first & my modal view didn't become visible until the data had finished (or almost finished) downloading (the Done button became visible immediately).
Can anyone offer suggestions as to how I can make this work?
Cheers & TIA, Pedro :)
Sounds like your rootController is not watching for changes in the data. It should not matter if the element is displayed already or if the data loads first. If the data loads later then the UI element should notice that the data is updated and then refresh itself.
Depending on your app design, you should look at the NSFetchedResultsController class and implement it along with its delegate methods. This class is designed to watch the NSManagedObjectContext for changes and when data is saved out to disk, update its delegate with what has changed.