I am working on a project in which I have a ViewController with MapView in it.
Now this page is loaded and dismissed several times.
What I first implemented was, I added MapView in xib and and then every time this page loaded then live bites used to increase by 10mb.
Solution1
Then after doing research for this issue what I found was to use single object for MKMapView and define it in AppDelegate and use it all the time.
I tried this and it decreased the memory usage to some extent but again after sometime the app got crashed due to Received Memory Warning.
Now if I again launch the app after crash, then it used to crash on the very first time on opening the MapView page, the live bites at this time were around 11mb only.
This is the code to add mapview in AppDelegate
mapView=[[MKMapView alloc]initWithFrame:CGRectMake(0, 0, 300, 450)];
[self.window addSubview:mapView];
mapView.delegate=self;
mapView.hidden=YES;
This was the code which I used to load Mapview.
- (void)viewDidLoad
{
[super viewDidLoad];
latittude=[[[NSUserDefaults standardUserDefaults]valueForKey:#"LATITUDE"] floatValue];
longitude=[[[NSUserDefaults standardUserDefaults] valueForKey:#"LONGITUDE"] floatValue];
APPDELEGATE.mapView.frame=CGRectMake(0, 140, 320, 290);
}
-(void)viewDidAppear:(BOOL)animated
{
APPDELEGATE.mapView.hidden=NO;
CLLocationCoordinate2D location;
location.latitude = latittude;
location.longitude = longitude;
Annotation *a;
a=[[Annotation alloc]initWithCoordinate:location];
[APPDELEGATE.mapView addAnnotation:a ];
}
-(void)viewWillDisappear:(BOOL)animated
{
APPDELEGATE.mapView.hidden=YES;
}
Solution2
Second solution I found was to change MapView type when view disappears.
So I changed its type, changed its delegate to nil and removed from superview on ViewWillDisappear.
Even this didn't made any difference.
Any idea how can I overcome this problem?
Thanks
Storing a MapView in the app delegate seems like a bit of a strange solution. I'd go back to having it contained in a single controller as you did originally.
What I first implemented was, I added MapView in xib and and then
every time this page loaded then live bites used to increase by 10mb.
This is your problem and it looks like a memory leak. The app size shouldn't increase if you are handling your objects / memory correctly. Make sure you are using arc and check you are setting any required objects (e.g NSTimers, NSNotifications) to nil in the viewWillDisappear method.
Related
I've been reading everything I can find on here about this topic but am still not sure the best way to proceed. I have a heavy UIImageView that uses an array of fat UIImages acting as an animated loop. This UIImageView is serving as the background for every screen in the app. (Client's request, not mine, so don't hate.) We've optimized the png files as small as they can go but it's still a pretty heavy load.
I've read several posts about how UIImage searches the cache for an existing image of that name (Ex. Shared UIImageView for background image throughout app - Singleton Property) but this doesn't seem to be happening. I've also been reading here about singletons and instantiating in the appdelegate but I'm not sure if either of these are the right way to proceed.
What's the best way to load the UIImageView once over the life of the app and use it in the background of every viewcontroller? Btw, because it takes several seconds to load, I'm going to be adding a "loading" page at app start that uses a single static image and an activity indicator.
Also, I'm not as familiar with testing and performance tools. Which one should I be using to test performance and make sure this is what is causing the hesitations throughout the app?
Apologies in advance for the noob questions - I generally avoid asking questions at all but sometimes, as in this case, I don't even know where to begin the research.
I'm rather pleased with myself. I went with the AppDelegate technique and it's working beautifully. I declared a UIImageView property in the AppDelegate, then add the image code to its getter:
- (UIImageView *)backgroundImageView {
if (!_backgroundImageView) {
NSMutableArray *tempArray = [NSMutableArray arrayWithCapacity:150];
for (int imageNum = 0; imageNum < 150; imageNum++) {
[tempArray addObject:[UIImage imageNamed:[NSString stringWithFormat:#"image_00%03i.png",imageNum]]];
}
_backgroundImageView = [[UIImageView alloc] initWithImage:[UIImage animatedImageWithImages:tempArray duration:4.0]];
}
return _backgroundImageView;
}
This also allowed me to kill the object in applicationDidReceiveMemoryWarning.
Then I created a helper class that I can pop into all of my UIViewController classes:
+ (void)placeBackgroundImageUnderView:(UIView *)masterView {
myAppDelegate *appDelegate = (myAppDelegate *)[[UIApplication sharedApplication] delegate];
//Correct for shrinkage
appDelegate.backgroundImageView.frame = masterView.frame;
[masterView addSubview:appDelegate.backgroundImageView];
[masterView sendSubviewToBack:appDelegate.backgroundImageView];
}
This allowed me to add a single line in each viewDidLoad method:
[HelperClass placeBackgroundImageUnderView:self.view];
The thing is, just using UIImage alone should cache the whole thing and speed up load time. But it seems that every now and then the images would have to reload - memory issues? So this allows me more control over it by instantiating the object once and using that same object, while also being to set that object to nil to free up memory if needed.
Since adding it, the whole app has been loading much faster. I added an additional load screen with an activity indicator for that initial load (also works beautifully) and everything after that is instant happy.
I am having problem finding a memory leak with Instruments. Usually it helps me a lot and I am able to find the leak, but in this case I'm lost.
I am creating a view controller that controls a views loaded from NIB file. The view has Map View with "Show user location" on true. Once user location is found I use MKReverseGeocoder to get the location data. The leak is always present when I load this view controller and MapKit finds user location. I figured out that MKReverseGeocoder isn't problem here, since I get the same leak with or without the MKReverseGeocoder.
When I load this view Instruments "leaks" report a memory leak. See the screenshot on the image:
This is how I initialize my controller:
AddPlaceViewController *addPlaceVC = [[AddPlaceViewController alloc] initWithNibName:#"AddPlaceViewController" bundle:[NSBundle mainBundle]];
addPlaceVC.delegate = self;
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:addPlaceVC];
self.placeController = navigationController;
[self presentModalViewController:self.placeController animated:YES];
[addPlaceVC release];
[navigationController release];
This is all on the iPhone Simulator 4 and targeted OS 3.2.
Is this actually leak or what I am facing here?
Since the responsible library is "Foundation" and not your code, there is nothing you can do about it (except report it to Apple).
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.
I started to learn using Instrument, but I cannot figure it out.
After I start my application, the UI shows up, I do nothing and after few seconds I can see memory leak detected:
When I have a look at the second leak I can see the following stack:
When I double click on the cell related to my code I can see that it is pointing to the following line of code:
[window addSubview:newPostUIViewController.view];
from the method:
- (void)applicationDidFinishLaunching:(UIApplication *)application {
//creating view controller
newPostUIViewController = [[NewPostUIViewController alloc] initWithNibName:#"NewPostView" bundle:nil];
newPostUIViewController.title = #"Post it!";
[window addSubview:newPostUIViewController.view];
// Override point for customization after application launch
[window makeKeyAndVisible];
}
I wonder, how this can be a reason of a leak? I release newPostUIViewController in the dealloc method of PostItAppDelegate class.
Any ideas how this could be explained?
You did not provide an autorelease or release to balance your init. Just in case you haven't read through it already, have a look at the memory management guide is a great help.
Looking at link text allows to say that this is Simulator problem, not the code problem.
uiimagepickerview controller creating memory leaks in iphone - why?
Try to implement ui image picker view controller in your application & debug it.
You will find memory leaks in your application.
Why ui image picker view controller creates memory leaks.
-(void)addPhotos:(id)sender
{
if(imagePickerController==nil){
imagePickerController=[[UIImagePickerController alloc]init];
imagePickerController.delegate=self;
imagePickerController.sourceType=UIImagePickerControllerSourceTypeSavedPhotosAlbum;
imagePickerController.allowsImageEditing=YES;
imagePickerController.navigationBar.barStyle=UIBarStyleBlackOpaque;
}
[self.navigationController presentModalViewController:imagePickerController animated:YES];
}
dealloc of my view controller.
- (void)dealloc {
if(PhotoDateArray!=nil)[PhotoDateArray release];
if(imagePickerController!=nil) [imagePickerController release];
if(objDetail!=nil) [objDetail release];
if(Picimage!=nil) [Picimage release];
if(mySavePhotoController!=nil) [mySavePhotoController release];
if(LoadingAlert!=nil);
[super dealloc];
}
Video link explaining how I am getting the memory leak in it..
http://www.yourfilelink.com/get.php?fid=508534
Even though you have the nil check, it's still possible to leak memory. I think what is happening here is that you are calling alloc / init multiple times, but only releasing once. My guess it that addPhoto: is wired up to some button click, dealloc would only be called once when the delegate is trying to destroy. This creates a situation like this:
button click
alloc / init
button click
alloc / init (memory leak on first alloc'd picker)
close window
dealloc (free second alloc'd picker)
A better way might be the way Apple does it in the PhotoLocations and iPhoneCoreDataRecipes examples:
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
imagePicker.delegate = self;
[self presentModalViewController:imagePicker animated:YES];
[imagePicker release];
Then listen for the didFinishPickingImage and imagePickerControllerDidCancel messages to your delegate and a call to [self dismissModalViewControllerAnimated:YES]; in both places should suffice.
I dont know about the rest of the code, but do you ever have a release?
[imagePickerController release]
UIImagePickerController loads and initializes PhotoLibrary.framework the first time it is shown. This memory won't be reclaimed until your application is closed.
(the code you posted doesn't appear to have leaks as-is, but that doesn't mean it won't interact with the rest of your application in a way that causes them)
I can explain this because I was having the same problem.
Don't test memory on the simulator!
If you test the apple code on a device the memory problem disappears.
I was having a memory alloc leak which I found in Instruments. All I was doing was opening and closing the image picker (open/cancel) and using Apple code, my code and other people's code, just like yours above.
All were showing the allocation going up and up each time, as if the picker was not being released. If you tried to release it, it would crash (over released).
Then I found a really helpful web page which basically stated:
"This doesn't happen when testing on the device"
So I switched from the simulator and ran the tests on the device. Lo & behold there was no allocation increase and it behaved normally.
This however is totally evil and now we can place no trust in the simulator to do a reliable job.
I want to add this to save people, the time, pain and bewilderment of wondering wtf is going on!