内存不足时的iOS应用程序行为

时间:2013-12-18 10:12:10

标签: ios iphone objective-c memory-management

我有iPhone应用程序。在某些情况下,当设备的可用内存不足时,某些操作(例如,打开相机)可能会导致应用程序崩溃。

我的问题是:

  1. 我想防止这些崩溃,应用程序的常用方法是什么 做这样的事情(阻止特定的行动,通知用户,其他 思想)?我问,因为我没有在iOS中遇到过这样的行为 我碰到的应用程序。
  2. 有没有办法防止此类崩溃并保持完整的应用程序功能,例如iOS系统调用以释放更多内存等?如果有人有最好的练习或良好的启发式,我很乐意听到它。
  3. 编辑:我问这个问题,假设我已经实现了'didReceiveMemoryWarning'功能,并释放了所有的内存。

    编辑2:我的应用程序是关于图片。很像相机扫描仪应用程序,这个应用程序允许拍照,图像处理和在内存中保存有关它们的数据。当我扫描很多照片时,我的崩溃通常会发生。

4 个答案:

答案 0 :(得分:4)

我遵循一些拇指规则:

  1. 使用Arc

  2. 对iboutlet使用weak(顶级示例:UIwindow除外)和委托

  3. 对类属性使用Strong并为NSString复制。

  4. 不要直接访问变量,请使用self ....方式。

  5. 不要使用autorelease方式创建新对象,例如NSArray * array = [NSArray arrayWithObjects .......,而不是使用NSArray * array = [NSArray alloc] initWit ....

    NSString类的方法相同。尝试使用[NSString alloc] initWithFormat .....而不是[NSString stringWithFormat。

  6. 当您添加NSNotification(addObserver ...)时,必须在dealloc中删除(removeObserver ..)它们。

  7. 实现didReceiveMemoryWarning(视图控制器级别)或applicationDidReceiveMemoryWarning(应用程序级别,它首先被调用,而不是视图控制器级别),有时候你只是希望从崩溃中保存。你可以显示一个警告告诉用户可用的内存较少,您可以弹出/显示..user到主屏幕。(不好的做法)。

  8. 在后台线程中不要对主线程执行任何操作。总是使用@autorelease块作为后台线程。

  9. 对长时间运行的进程使用GCD / NSOperation队列。

  10. 密切关注您正在使用的图像资源,仅使用所需尺寸的图像,而不是根据需要将大图像缩放到小图像尺寸。

  11. USE自动释放池用于长时间运行的循环,它会创建大量自动释放的对象。

  12. 我有一些ypu可以遵循的代码片段:

        //way 1 all on main thread bad approach, basically we are just doing some image manipulation on main thread(should not do on main thread :)) 
    -(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{
    
        YourApplicationDelegate *appDelegate = (YourApplicationDelegate *)[[UIApplication sharedApplication]delegate];
        [appDelegate showLandscapeLoading];//think it as progress view/loader
    
        UIImage *pickedImage = [info objectForKey:UIImagePickerControllerOriginalImage];
        NSData *imageData = UIImagePNGRepresentation(pickedImage);
    
        NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
        NSString *path = [documentsDirectory stringByAppendingPathComponent:@"category_imagename.jpeg"];
    
        NSError * error = nil;
    //from here
        [imageData writeToFile:path options:NSDataWritingAtomic error:&error];
    
        **//the important part for discussion UI manipulation on main thread bad bad bad**
        CGSize size1;//A
        size1.width = 400;
        size1.height = 400;
        UIGraphicsBeginImageContext(size1);
        [pickedImage drawInRect:CGRectMake(0, 0, size1.width, size1.height)];
        UIImage *bigImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
    
        NSString *bigThumb = [documentsDirectory stringByAppendingPathComponent:@"category_thumb_imagename.jpeg"];
    
        NSData *data1=UIImageJPEGRepresentation(bigImage, 0.5);
        BOOL status1=[data1 writeToFile:bigThumb atomically:YES];
        **//up to here should be in non ui thread/seperate thread**
    **//below code should go in main thread**
        NSLog(@"status1 -> %d",status1);
        [self setCategoryImageName:bigImage];
        [self.imgCategory setImage:pickedImage];
    
        if (status1) {
            isAddingCategoryImage = YES;
        }
    
        [appDelegate stopLandscapeLoading];
    
        if (error != nil) {
            NSLog(@"Error: %@", error);
            return;
        }
    
        if ([self.popoverController isPopoverVisible]) {
            [self.popoverController dismissPopoverAnimated:true];
    
        }
    
        [picker.view removeFromSuperview];
    
    }
    

    正确的方法:

    使用NSOperation:

    -(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{
    
    YourApplicationDelegate *appDelegate = (YourApplicationDelegate *)[[UIApplication sharedApplication]delegate];
    [appDelegate showLandscapeLoading];
    
    UIImage *pickedImage = [info objectForKey:UIImagePickerControllerOriginalImage];
    
    NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    
    NSError * error = nil;
    
    
    
    NSOperationQueue *opQueue = [[NSOperationQueue alloc] init];
    [opQueue addOperationWithBlock:^
     {
         // Create a graphics image context very slow stuff
         CGSize newSize = CGSizeMake(400, 400);
         UIGraphicsBeginImageContext(newSize);
         // Tell the old image to draw in this new context, with the desired
         // new size
         [pickedImage drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
         // Get the new image from the context
         UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
         // End the context
         UIGraphicsEndImageContext();
    
         NSString *bigThumb = [documentsDirectory stringByAppendingPathComponent:@"category_thumb_imagename.jpeg"];
    
         NSData *data1=UIImageJPEGRepresentation(newImage, 0.5);
         BOOL status1=[data1 writeToFile:bigThumb atomically:YES];
         // ok, now do UI stuff in the main queue
    
         [[NSOperationQueue mainQueue] addOperationWithBlock:^
          {
              [self setCategoryImageName:bigThumb];
              [self.imgCategory setImage:pickedImage];
    
              if (status1) {
                  isAddingCategoryImage = YES;
              }
    
              [appDelegate stopLandscapeLoading];
    
              if (error != nil) {
                  NSLog(@"Error: %@", error);
                  return;
              }
    
              if ([self.popoverController isPopoverVisible]) {
                  [self.popoverController dismissPopoverAnimated:true];
    
              }
    
              [picker.view removeFromSuperview];
          }];
     }];
    

    }

    感谢和问候, ALOK

答案 1 :(得分:1)

  1. 如果您使用非弧并且您已经分配了许多对象,并且您没有释放这些对象,那么它会显示内存问题。你在dealloc方法中重新关注所有对象。在上面的产品选项中选择Analyze。您将看到应用程序内存泄漏的位置

  2. 如果你使用旧的xcode并且使用了新的iphone模拟器而不是显示内存泄漏

  3. 如果您使用arc,请注释autorelease或[obj release] close。

  4. 此外,如果您要检查其应用程序而不是侧角按钮来保持并选择配置文件。它将显示仪器工具。你可以启用Nszombies。你可以检查对象值的确定方法,你可以看到应用程序中的内存泄漏位置。

答案 2 :(得分:0)

在iOS中没有直接调用空闲RAM内存。如果在项目中使用ARC,请将属性正确定义为弱/强等,并检查应用程序是否存在内存泄漏或僵尸进程,不会出现RAM问题。

iOS从其他应用程序中释放内存,以便在需要时将其分配给前台应用程序,您不应该尝试处理它。如果应用程序因内存问题而崩溃,则可能是应用程序中存在内存泄漏。使用工具来分析您的应用。

答案 3 :(得分:0)

自从我开始为iOS开发以来,内存警告系统有了很多改进,ARC也很有助于开发人员管理内存。
您应该使用泄漏和分配来分析您的应用,以了解您的应用为何占用了大量内存 您正在开发哪种应用程序?应该是一个高内存使用应用程序,如游戏,或照片应用程序?
崩溃可能是由于对内存警告或大量内存占用的管理不善而导致应用程序没有留下任何最后一口气。 最常见的原因是图片。如果您不以正确的方式管理这些情况,这些设备无法处理大量的招聘资源,您的应用程序的内存占用量会增长,直到它无法释放足够的内存。

但是你需要提供更多细节。