gpt4 book ai didi

iOS 应用程序在内存不足的情况下的行为

转载 作者:行者123 更新时间:2023-12-01 17:54:28 25 4
gpt4 key购买 nike

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

我的问题是:

  • 我想防止这些崩溃,应用程序的常用方式是什么
    做这样的事情(阻止特定的 Action ,通知用户,其他
    想法)?我问是因为我在 iOS 中没有遇到过这样的行为
    我遇到的应用程序。
  • 是否有任何方法可以防止此类崩溃并保持完整的应用程序功能,例如 iOS 系统调用以释放更多内存等?如果有人有最佳实践或良好的启发式方法,我很想听听。

  • 编辑:我问这个问题假设我已经实现了'didReceiveMemoryWarning'功能并释放了我能释放的所有内存。

    编辑 2:我的应用程序是关于图片的。很像相机扫描仪应用程序,此应用程序允许拍照、图像处理并将有关它们的数据保存在内存中。我的崩溃通常发生在我扫描大量图片时。

    最佳答案

    我遵循的一些经验法则:

  • 使用弧线
  • 对 iboutlets(除了顶级示例:UIwindow)和委托(delegate)使用 weak
  • 对类属性使用 Strong,对 NSString 使用副本。
  • 不要直接访问变量,使用 self....方式。
  • 不要使用自动释放方式创建新对象,例如 NSArray *array = [NSArray arrayWithObjects.......,而是使用 NSArray *array = [NSArray alloc] initWit....

    NSString 类的方法相同。尝试使用 [NSString alloc] initWithFormat..... 而不是 [NSString stringWithFormat.
  • 当您添加 NSNotification(addObserver...) 中心时,必须在 dealloc 中删除(removeObserver..)它们。
  • 正确实现didReceiveMemoryWarning( View Controller 级别)或applicationDidReceiveMemoryWarning(应用程序级别,它比 View Controller 级别首先调用),但有时您只希望从崩溃中保存。您可以显示警报告诉用户可用内存不足,您可以将 ..user 弹出/呈现到主屏幕。(不好的做法)。
  • 在后台线程中时不要对主线程执行任何操作。始终将@autorelease block 用于后台线程。
  • 对长时间运行的进程使用 GCD/NSOperation 队列。
  • 密切关注您正在使用的图像资源,仅使用所需大小的图像,而不是根据需要将大图像缩放为小图像大小。
  • 使用自动释放池进行长时间运行的循环,这会创建很多自动释放的对象。

  • 我为您准备了一些代码片段,您可以遵循这些代码片段:
        //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];
    }];
    }];

    }

    谢谢并恭祝安康,
    阿洛克

    关于iOS 应用程序在内存不足的情况下的行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20655204/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com