[英]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)可以非常簡單地異步保存。 步驟是:
NSBlockOperation
而已。 這是代碼:
// 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.