簡體   English   中英

保存使用相機拍攝的圖像或從相機膠卷中選擇時的長時間延遲 - iPhone

[英]Long delay when saving image taken with camera or chosen from camera roll - iPhone

我使用以下代碼允許我的應用程序的用戶拍攝/選擇照片,然后將其保存到文檔目錄並設置為UIImageView的圖像:

    -(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {

        if (actionSheet.tag == 0){
            if (buttonIndex == 0) {
                NSLog(@"Take Picture Button Clicked");
                // Create image picker controller
                UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];

                // Set source to the camera
                imagePicker.sourceType =  UIImagePickerControllerSourceTypeCamera;

                // Delegate is self
                imagePicker.delegate = self;

                // Show image picker
                [self presentModalViewController:imagePicker animated:YES];
            } 
            else if (buttonIndex == 1) {
                NSLog(@"Choose From Library Button Clicked");
                // Create image picker controller
                UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];

                // Set source to the camera
                imagePicker.sourceType =  UIImagePickerControllerSourceTypePhotoLibrary;

                // Delegate is self
                imagePicker.delegate = self;

                // Show image picker
                [self presentModalViewController:imagePicker animated:YES];
            } 
            else if (buttonIndex == 2) {
                NSLog(@"Cancel Button Clicked");
            } 
        }
......

- (void)saveImage:(UIImage*)image:(NSString*)imageName 
{ 
    NSData *imageData = UIImagePNGRepresentation(image); //convert image into .png format.

    NSFileManager *fileManager = [NSFileManager defaultManager];//create instance of NSFileManager

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); //create an array and store result of our search for the documents directory in it

    NSString *documentsDirectory = [paths objectAtIndex:0]; //create NSString object, that holds our exact path to the documents directory

    NSString *fullPath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.png", imageName]]; //add our image to the path 

    [fileManager createFileAtPath:fullPath contents:imageData attributes:nil]; //finally save the path (image)

    receiptImageView1.image = [UIImage imageWithContentsOfFile:fullPath];
    self.receiptImage1 = fullPath;

    NSLog(@"image saved");
}

//Receive the image the user picks from the image picker controller
-(void)imagePickerController:(UIImagePickerController*)picker
didFinishPickingMediaWithInfo:(NSDictionary*)info {
    UIImage* image = [info objectForKey: UIImagePickerControllerOriginalImage];
    NSString* imageName = @"Receipt1Image1";
    [self saveImage:image :imageName];
}

基本上我的問題是這個代碼似乎執行得非常慢,例如當我從相機膠卷中選擇一個圖像時它最終會保存並將我帶回調用視圖,但只是經過很長時間的延遲。

任何人都可以對此有所了解嗎?

保存大圖像(如iPhone 4 / 4S中相機拍攝的圖像)需要很長時間。 如果您對該過程進行概要分析,您會發現UIImagePNGRepresentation()需要一段時間來生成您的PNG圖像,但根據我的經驗,主要的瓶頸是寫入1+ MB圖像的磁盤。

除了使用JPEG壓縮之外,你幾乎無法加速這個過程,我發現在我的基准測試中,或者使用更快的第三方圖像壓縮程序會更快。 因此,如果您不希望在發生這種情況時阻止用戶界面,請在后台線程或隊列上調度此保存過程。 您可以執行以下操作:

-(void)imagePickerController:(UIImagePickerController*)picker
didFinishPickingMediaWithInfo:(NSDictionary*)info {

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        UIImage* image = [info objectForKey: UIImagePickerControllerOriginalImage];
        NSString* imageName = @"Receipt1Image1";
        [self saveImage:image :imageName];
    });
}

但是,請注意這些UIImages中的每一個都會占用相當多的內存來保留,因此您可能希望使用調度信號量來防止同時發生多個此類圖像保存操作。

另外,作為一個風格筆記,定義一個Objective-C方法

- (void)saveImage:(UIImage*)image:(NSString*)imageName 

雖然允許,但非常沮喪。 為每個參數指定一個名稱,如下所示:

- (void)saveImage:(UIImage*)image fileName:(NSString*)imageName 

它將使您的代碼更具描述性。

我回答了類似的問題 為清楚起見,我將在此復制:

根據圖像分辨率, UIImagePNGRepresentation確實可能非常慢,對文件系統的任何寫入也是如此。

您應該始終在異步隊列中執行這些類型的操作。 即使測試時性能看起來足夠適合您的應用程序, 您仍然應該使用異步隊列 - 您永遠不會知道設備可能進行的其他進程,一旦您的應用程序在用戶手中,這可能會減慢保存速度。

較新版本的iOS使用Grand Central Dispatch(GCD)可以非常簡單地異步保存。 步驟是:

  1. 創建一個保存圖像的NSBlockOperation
  2. 在塊操作的完成塊中,從磁盤讀取圖像並顯示它。 這里唯一需要注意的是,您必須使用主隊列來顯示圖像: 所有UI操作必須在主線程上進行
  3. 將塊操作添加到操作隊列並觀察它!

而已。 這是代碼:

// Create a block operation with our saves
NSBlockOperation* saveOp = [NSBlockOperation blockOperationWithBlock: ^{

   [UIImagePNGRepresentation(image) writeToFile:file atomically:YES];
   [UIImagePNGRepresentation(thumbImage) writeToFile:thumbfile atomically:YES];

}];

// Use the completion block to update our UI from the main queue
[saveOp setCompletionBlock:^{

   [[NSOperationQueue mainQueue] addOperationWithBlock:^{ 

      UIImage *image = [UIImage imageWithContentsOfFile:thumbfile];
      // TODO: Assign image to imageview

   }];
}];

// Kick off the operation, sit back, and relax. Go answer some stackoverflow
// questions or something.
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperation:saveOp];

一旦你熟悉這個代碼模式,你會發現自己經常使用它。 它在生成大型數據集,加載時的長操作等方面非常有用。實際上,任何使UI偏差最小的操作都是此代碼的良好候選者。 請記住,當你不在主隊列中時,你不能對UI做任何事情,其他一切都是蛋糕。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM