Dynamically calculate application load time - iphone

How can I run a clock that allows me to measure the time to load until appDidFinishLaunching ?
I want to set a sleep call that extends the Defaul.png show time to 3 seconds regardless the speed of the underlying hardware.

First off, you should know that Springboard in iPhone OS is kinda picky about load times. You should never make a sleep call somewhere in the loading process of you application. If Springboard detects that your application is taking too long to launch, your application will be terminated with "failed to launch in time" in the crash log.
Secondly, there is no, as far as I know, way of measuring the time your application took to launch. There are several thing happening when the user taps the Application icon on the springboard, and the iPhone OS provides no good information to your application.
One solution could be to make sure your applicationDidFinishLaunching: is very lightweight, and creating a "fake" Default.png overlay. By trimming down your applicationDidFinishLaunching: method to do only the most essential stuff, and the performing any time consuming tasks in the background, you can ensure that your Default.png overlay is displayed roughly the same time on different hardware.
- (void)applicationDidFinishLaunching:(UIApplication *)application {
// Create the image view posing with default.png on top of the application
UIImageView *defaultPNG = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Default.png"]];
// Add the image view top-most in the window
[window addSubview:defaultPNG];
[window makeKeyAndVisible];
// Begin doing the time consuming stuff in the background
[self performSelectorInBackground:#selector(loadStuff) withObject:nil];
// Remove the default.png after 3 seconds
[self performSelector:#selector(removeDefaultPNG:) withObject:defaultPNG afterDelay:3.0f];
}
- (void)removeDefaultPNG:(UIImageView *)defaultPNG {
// We're now assuming that the application is loaded underneath the defaultPNG overlay
// This might not be the case, so you can also check here to see if it's ok to remove the overlay
[defaultPNG removeFromSuperview];
[defaultPNG release];
}
If you add more views (your view controllers etc) in the loadStuff method, you should insert them below the defaultPNG overlay. You should also be aware of problems that could occur by doing these things from another thread. You could use performSelectorOnMainThread:withObject:waitUntilDone: if you encounter problems.

Related

How to handle a system alert message for iOS?

I have an app where i am using UIImagePickerController to use the native camer inorder to click pictures but the when the photo gallery on the device is full. I get a alert message which says "Cannot Take Photo - There is not enough available storage to take a photo.You can manage your storage in Settings". I am given two options to click the "Done" button or "Settings" button. Clicking either of them does nothing and the app freezes completely.
This is what i get from the console logs
Not enough space to take a picture. Available space is 0
The code for the picker
UIImagePickerController *mediaPicker = [[UIImagePickerController alloc] init];
mediaPicker.sourceType = UIImagePickerControllerSourceTypeCamera;
mediaPicker.delegate=self;
mediaPicker.sourceType=UIImagePickerControllerSourceTypeCamera;
[self presentModalViewController:mediaPicker animated:YES];
I have implemented and tried all the delegates already and its not calling any delegate.
Is there any way i can implement something where i can use a listener to detect when this error occurs and take back the user to the previous screen ?
Sounds like your device run out of memory, system sent lots of "Out of Memory" notifications and your app got one, too. As result your app released the UIViewController, which originally launched UIImagePickerController.
Now when you dismiss imagePicker with Done/Settings button, control returns back to your app. The old UIViewController doesn't exist any more and you haven't implemented code to recreate it from scratch in this kind of situations. The device looks like it frozen, but only because UI wasn't redrawn by your app. Otherwise app works just fine.
You can check this case by implementing didReceiveMemoryWarning method into every UIViewController and logging, if it's called:
- (void)didReceiveMemoryWarning
{
NSLog(#"%#", [self description]);
[super didReceiveMemoryWarning];
}
One of my favourite bugs. Easy to miss :)
This sounds like a bug in iOS.
You should file a feedback at https://feedbackassistant.apple.com/.

Iphone launch image disappear very fast

The launch image appear and disappear very fast in the iPhone.
How can I control this time? How much seconds is the default?
Thanks
You can use a sleep(time in seconds) function in the application:didFinishLaunchingWithOptions: to explicitly increase some time by yourself.
Eg :
sleep(3);
Will extend the time to 3 more seconds.
Note : As rmaddy said, make user stare at splash screen for a long time is not a good practice. But you can use this in customer's demand.
Happy coding. :)
There's no default — it stays up until your program has been loaded and returned from application:didFinishLaunchingWithOptions:.
If you want to keep the image up under programmatic control then you'll need to place it on screen manually as the first thing the program displays, then dismiss it through the usual channels. This would be relatively easy on a pre-5 iPhone (just put up a big UIImageView with Default.png in it) but as of the iPhone 5 and with the iPad you're going to have to make some sort of decisions about which default screen to show.
You can also try to add a sleep time in your didFinishLaunchingWithOptions method as below:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[NSThread sleepForTimeInterval:3.0f]; //add 3 seconds longer.
//other code....
}

Received memory warning. Level=1 when showing a UIImagePickerController

This is driving me crazy!!!
I'm getting a "Received memory warning. Level=1" whenever I attempt to show a UIImagePickerController with a sourceType = UIImagePickerControllerSourceTypeCamera.
Here is the code from my viewDidLoad where I set things up:
- (void)viewDidLoad {
[super viewDidLoad];
// Set card table green felt background
self.view.backgroundColor = [UIColor colorWithPatternImage: [UIImage imageNamed:#"green_felt_bg.jpg"]];
// Init UIImagePickerController
// Instantiate a UIImagePickerController for use throughout app and set delegate
self.playerImagePicker = [[UIImagePickerController alloc] init];
self.playerImagePicker.delegate = self;
self.playerImagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
}
And here is how I present it modally ..
- (IBAction) addPlayers: (id)sender{
[self presentModalViewController:self.playerImagePicker animated:YES];
}
The result ... UIImagePicker starts to show and then boom ... I get the memory warning ... EVERY TIME! Interestingly enough, if I switch to sourceType = UIImagePickerControllerSourceTypePhotoLibrary ... everything works fine.
What in the heck am I missing or doing wrong? All I want to do is show the camera, take and save a picture.
FYI - I'm testing on my 3GS device.
Thanks to anyone who can help :)
This is very common. As long as you handle the memory warning without crashing and have enough space to keep going, don't let it drive you crazy.
It is not about how much memory your app has used, because it will probably happen even when you write a very simple app which have only one view with one button, clicking the button and then open camera.
I have tested on iPhone 3GS, iPad 2 and iPod touch 3G. It only happened in iPhone 3GS.
I found it will not happen anymore if you restart you device before you execute you app.
Another real solution is to comment the code, [super didReceiveMemoryWarning], in your viewController.
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
After lots of test on iPhone 3GS with iOS 4.3.2, I found the logic might like that:
-> Open as much as app running on background
-> Presenting a imagePicker of UIImagePickerController, clicking "Back" or "Save" from imagePicker
-> ApplicationDelegate's method, applicationDidReceiveMemoryWarning:(UIApplication *)application, will be invoked
-> Then ViewController's method, didReceiveMemoryWarning:, will be invoked
-> Then viewDidUnload
-> Then viewDidLoad
Then you could find some views have been released and the current view has been pointed to a unexpected one.
By default, [super didReceiveMemoryWarning] will run when ViewController's didReceiveMemoryWarning method is invoked. Commenting it, and viewDidUnload: and viewDidLoad: methods will not be invoked. It means the mem warning has been totally ignored. That's what we expected.
Now after I upgraded to 4.0 it happens to my app too - before in 3.1 there were no warnings.
Actually as you said before, there should be no issue. However, this causes the view that comes after it to load again and viewDidLoad is being called. This messes up my app, since I initialize the view in viewDidLoad - now it gets initialized all over again - even though it shouldn't.
Just as a comment, this might also happen to many other apps that rely on loading the view only once!
It did happen in my app Did I Do That on iOS 4.0 too. It was not consistent, but the most common cause was creating a UIImagePickerController instance and navigating to some large photo stored in one of the albums.
Fixed by persisting state in the didReceiveMemoryWarning method, and loading from state in the viewDidLoad method. One caveat is to remember to clear the state-persisted file in the correct point for your application. For me it was leaving the relevant UIViewController under normal circumstances.
I'm getting the memory warning when opening a UIImagePickerController as well. I'm on 4.01 as well.
But in addition, the UIImagePickerController is running the close shutter animation and stalling there, with the closed shutter on screen.
It seems like the UIImagePickerController's behavior on memory warnings is to close itself.
I could dismiss the UIImagePickerController from the parent ViewController in the didReceiveMemoryWarning method, but that would make for a terrible user experience.
Has anyone seen this problem?
Is there a way to handle the memory warning so that the UIImagePickerController doesn't shut itself down?
I have been struggling with the same problem for some days now. However, resetting my iPhone 4 (clearing out memory) solves the problem so it's not really an app problem.
It appears that a level 1 or 2 memory warning triggers the UIimgPickerController delegate to offload itself. The same happens in my app with the delegate of the delegate (yes it can). After the memory warning however, it will load the delegate (and it's delegate) again causing the viewDidLoad to execute any code that's in there.
I am not sure this happens only while using the UIimgPickerController because testing all that is very time consuming.
I could write some extra code to prevent the code in viewDidLoad en viewWillAppear from execuring while showing the UIimgPickerController but that's not classy, right?
Here's food for thought: it could be
that you are running out of memory
because you are testing your app. With
some memoryleaks it is very well
possible that you are working towards
this problem every time you debug.
The UIImagePickerControllerDelegate is a memory hog because you are capturing high memory assets, be that an image or video. So from the start be sure to specify the medium capture settings, as a start point, reduce this if you don't need the quality:
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
picker.videoQuality=UIImagePickerControllerQualityTypeMedium;
Then after capturing and using these assets. Remove any temp files from the applications temp folder. Could be an extra obsessive step but its a good habit:
NSFileManager *fileManager = [NSFileManager defaultManager];
if ([fileManager fileExistsAtPath:[lastCapturedFile substringFromIndex:7] ]) {
NSError *error;
// Attempt to delete the folder containing globalDel.videoPath
if ([fileManager removeItemAtPath:[lastCapturedFile substringFromIndex:7] error:&error] != YES) {
NSLog(#"Unable to delete recorded file: %#", [error localizedDescription]);
} else {
NSLog(#"deleted file");
}
}
With above it is clearing the file that was created by the delegate. In some instances if you are transcoding or creating you own assets delete the folder with that file. Note above I am removing the 'file://' part of the url string as the file manager doesn't like it:
[lastCapturedFile substringFromIndex:7]
Other things to consider are covered in the various documentation for what you are doing with that asset - transcoding, image size reduction and more. Beware that any transcoding using the AVFoundation will crash if the UIImagePickerViewController is displaying.

Pattern for iPhone background loading during init?

I'm currently kicking off a background thread to do some REST queries in my app delegate's didFinishLaunchingWithOptions. This thread creates some objects and populates the model as the rest of the app continues to load (because I don't block, and didFinishLaunchingWithOptions returns YES). I also put up a loading UIViewController 'on top' of the main view that I tear down after the background initialization is complete.
My problem is that I need to notify the first view (call it the Home view) that the model is ready, and that it should populate itself. The trick is that the background download could have finished before Home.viewDidAppear is called, or any of the other Home.initX methods.
I'm having difficulty synchronizing all of this and I've thought about it long enough that it feels like I'm barking up the wrong tree.
Are there any patterns here for this sort of thing? I'm sure other apps start by performing lengthy operations with loading screens :)
Thanks!
I usually have a Factory class that’s responsible for wiring all the objects together. The Factory is created by the application delegate in the applicationDidFinishLaunching:
- (void) applicationDidFinishLaunching: (UIApplication*) app {
// Creates all the objects that are needed to wire
// the application controllers. Can take long. We are
// currently displaying the splash screen, so that we
// can afford to block for a moment.
factory = [[Factory alloc] init];
// Now that we have the building blocks, we can wire
// the home screen and start the application.
home = [[factory wireHomeScreen] retain];
[window addSubview:home.view];
[window makeKeyAndVisible];
}
Now if the Factory creation takes long, I simply wait under the splash screen or put up another view that displays spinner until everything is ready. I guess you could use this very scheme if you can perform the initialization synchronously:
#implementation Factory
- (id) init {
[super init];
// Takes long, performs the network I/O.
someDataSource = [[DataSource alloc] init…];
return self;
}
- (id) wireHomeScreen {
// Data source already loaded or failed to load.
HomeScreen *home = [[HomeScreen alloc] init…];
[home setDataSource:someDataSource];
return [home autorelease];
}
#end
With a bit of luck there’s just a single long operation in your startup routine, so that you won’t lose anything by serializing the init.
If you want to perform the data source init in background, you can display some introductory screen that will cue the home screen once the data has been loaded:
- (void) applicationDidFinishLaunching: (UIApplication*) app
{
// Create the basic building blocks to wire controllers.
// Will not load the data from network, not yet.
factory = [[Factory alloc] init];
// Display something while the data are being loaded.
IntroScreen *intro = [[IntroScreen alloc] init];
// Main screen, will get displayed once the data are loaded.
home = [[factory wireHomeScreen] retain];
// The intro screen has to know what do display next.
[intro setNextScreen:home];
// Start loading data and then notify the intro screen
// that we are done loading and the show can begin.
[factory.someDataSource startLoadingAndNotify:intro];
[window addSubview:intro.view];
[window makeKeyAndVisible];
}
Now when the data source has finished loading the data, it will tell the intro screen to cue the real content (home screen, in this case). This is just a rough sketch (for example the memory management might be different in the real case), but in principle it should work fine.
I ran into a similar issue a while back writing a REST application. It wasn't at the home screen but the general idea was the same. Issues with synchronizing call backs with NSURLRequests and so on. I found an example code from Apple that doesn't really solve this problem but illustrates how Apple solved it. Here's the link...
http://developer.apple.com/iphone/library/samplecode/XMLPerformance/Introduction/Intro.html
They do block the thread, so maybe it's not the solution you are looking for. In short, they use...
-(void) get {
finished = NO;
... do threading stuff ...
do {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
} while (!finished);
}
Just make sure your thread calls set finished to YES at some point.
It's not a pattern by any means, but I found it very helpful if you are using multiple threads in your application.

How to delay Default.png?

How can I delay the app loading to show the splash screen for longer?
You should let the app start as usual then make the first view that appears have the identical image on it as the splash screen. Start a timer and then replace that view with your real application root view after a few seconds.
Deliberately delaying the actual application launch is a big no-no.
UPDATE: No seriously, DON'T do this!
Or us the C function
sleep(9);
Putting this in applicationDidFinishLaunching: will cause you program to pause for 9 seconds, any other integer may be entered as well.
EDIT: I've learned a lot in the past year. Don't do this. The reason being that the springboard will automatically stop the app launching if it takes too long. That timing is poorly documented so even one second can result in the app failing.
This question is similar: splash screen like tap tap revenge 3
Basically, in your applicationDidFinishLaunching:, add an image view on top of other views containing your Default.png.
See the above discussion of why you probably should not delay your app load in this way. But if you happen to have a scenario where sleeping for short duration would be preferable to the overhead of switching out a view, use NSThread's sleepForTimeIntervale instead of sleep(). It's more framework friendly and you have more granular control over the sleep time:
[NSThread sleepForTimeInterval:0.75]
I had a situation where the client had to demo the launch image. So, this was my solution..
- (void)applicationDidBecomeActive:(UIApplication *)application
{
UIImageView *defaultImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Default#2x.png"]];
[self.window addSubview:defaultImageView];
sleep(2);
[defaultImageView removeFromSuperview];
[defaultImageView release];
/*
Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
*/
}
You can use it sleep method to get this result "
sleepForTimeInterval
", If you want to get it launch time, do like :
- (void) applicationDidFinishLaunching:(UIApplication*)application
{
[NSThread sleepForTimeInterval:8.0];
}
It will delay the launch by 8 seconds
Warning : But it is not recommended by apple, as it will the watchdod about long time for your app loading, It can kill your app.
But incase if you need it to get some specific screenshot or for some in-house use, you can use to solve for purpose but never in app submission.