Received memory warning. Level=1 when showing a UI

2019-01-21 14:11发布

问题:

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 :)

回答1:

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.



回答2:

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.



回答3:

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!



回答4:

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.



回答5:

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?



回答6:

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.



回答7:

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.