2011-11-04 31 views
8

Trong ứng dụng iPhone của tôi, tôi đang sử dụng máy ảnh của iPhone để chụp ảnh và lưu nó làm đĩa (thư mục tài liệu của ứng dụng). Đây là cách tôi lưu nó:tải hình ảnh từ đĩa trong ứng dụng iPhone chậm

[UIImageJPEGRepresentation(photoTaken, 0.0) writeToFile:jpegPath atomically:YES]; 

Sử dụng nén nhiều nhất, tôi đã đọc hình ảnh từ đĩa sẽ nhanh chóng. Nhưng không phải của nó! Tôi sử dụng hình ảnh làm hình nền cho một nút ở một trong các chế độ xem của tôi. Tôi tải nó như thế này:

[self.frontButton setBackgroundImage:[UIImage imageWithContentsOfFile:frontPath] forState:UIControlStateNormal]; 

Khi tôi điều hướng đến chế độ xem với nút này, nó sẽ bị chậm và bị thay đổi. Làm thế nào để sửa lỗi này?

Trả lời

37

+imageWithContentsOfFile: là đồng bộ, do đó giao diện người dùng trên chuỗi chính của bạn đang bị chặn bởi tải hình ảnh từ hoạt động của ổ đĩa và gây ra sự xáo trộn. Giải pháp là sử dụng một phương thức tải tệp không đồng bộ từ đĩa. Bạn cũng có thể làm điều này trong một chủ đề nền. Điều này có thể được thực hiện dễ dàng bằng cách gói +imageWithContentsOfFile: trong dispatch_async(), sau đó lồng nhau dispatch_async() trên hàng đợi chính bao bọc -setBackgroundImage: vì các phương thức UIKit cần được chạy trên chuỗi chính. Nếu bạn muốn hình ảnh xuất hiện ngay lập tức sau khi lượt xem tải, bạn sẽ cần phải lưu trước hình ảnh từ đĩa sao cho nó trong bộ nhớ ngay lập tức khi khung nhìn xuất hiện.

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{ 

    UIImage *image = [UIImage imageWithContentsOfFile:frontPath]; 

    dispatch_async(dispatch_get_main_queue(), ^{ 
     [self.frontButton setBackgroundImage:image forState:UIControlStateNormal]; 
    }); 

}); 

Là một sang một bên, nếu hình ảnh nút xảy ra một gradient, xem xét sử dụng các tính chất sau đây để đảm bảo các tập tin hình ảnh được nạp từ đĩa nhỏ:

- (UIImage *)resizableImageWithCapInsets:(UIEdgeInsets)capInsets 

hoặc (bị phản đối, chỉ sử dụng nếu bạn cần hỗ trợ iOS 4.x):

- (UIImage *)stretchableImageWithLeftCapWidth:(NSInteger)leftCapWidth topCapHeight:(NSInteger)topCapHeight 
+0

giúp bạn tiết kiệm cuộc sống của tôi! cảm ơn bạn! –

+0

@Andrew làm cách nào để bạn lưu trước bộ nhớ cache? lại: "bạn sẽ cần phải lưu trước hình ảnh từ đĩa" –

+0

@Van Du Tran, trước khi lưu vào bộ nhớ cache trong trường hợp này có nghĩa là chỉ cần tải hình ảnh vào UIImage trước khi bạn cần (ví dụ: trước khi chế độ xem xuất hiện). Bằng cách này, khi bạn tải chế độ xem, hình ảnh đã được lưu trữ trong bộ nhớ để không có đĩa I/O được yêu cầu hiển thị trên màn hình. – Andrew

2

Đây là cách nhanh hơn tôi biết. Bạn sẽ cần nhập #import <ImageIO/ImageIO.h>

Tôi sử dụng mã này để tải xuống và nén hình ảnh trong khi cuộn, bên trong một chế độ xem cuộn và bạn hầu như không nhận thấy sự chậm trễ.

CGImageSourceRef src = CGImageSourceCreateWithData((CFDataRef)mutableData, NULL); 
CFDictionaryRef options = (CFDictionaryRef)[[NSDictionary alloc] initWithObjectsAndKeys:(id)kCFBooleanTrue, (id)kCGImageSourceCreateThumbnailWithTransform, (id)kCFBooleanTrue, (id)kCGImageSourceCreateThumbnailFromImageIfAbsent, (id)[NSNumber numberWithDouble:200.0], (id)kCGImageSourceThumbnailMaxPixelSize, nil]; 
CGImageRef thumbnail = CGImageSourceCreateThumbnailAtIndex(src, 0, options); 

UIImage *image = [[UIImage alloc] initWithCGImage:thumbnail]; 
// Cache 
NSString *fileName = @"fileName.jpg"; 
NSString *path = [NSTemporaryDirectory() stringByAppendingPathComponent:@"thumbnail"]; 
path = [path stringByAppendingPathComponent:fileName]; 
if ([UIImagePNGRepresentation(image) writeToFile:path atomically:YES]) { 
    // Success 
} 
+0

Nếu mã này vẫn còn chậm cho bạn, bạn chỉ cần đặt nó vào trong một chuỗi. Xin lưu ý rằng "200.0 "là kích thước tối đa bạn muốn bằng pixel. –

0

Tôi gặp phải vấn đề rất tương tự khi tôi phải tải hàng trăm hình ảnh từ thư mục. Hiệu năng của tôi khá chậm nếu tôi sử dụng phương thức UIImage (contentsOfFile :). Phương pháp dưới đây đã tăng hiệu suất của tôi lên 70%.

lớp ImageThumbnailGenerator: ThumbnailGenerator { tin let url: URL

init(url: URL) { 
     self.url = url 
    } 

func generate(size: CGSize) -> UIImage? { 
    guard let imageSource = CGImageSourceCreateWithURL(url as NSURL, nil) else { 
     return nil 
    } 

    let options: [NSString: Any] = [ 
     kCGImageSourceThumbnailMaxPixelSize: Double(max(size.width, size.height) * UIScreen.main.scale), 
     kCGImageSourceCreateThumbnailFromImageIfAbsent: true 
    ] 

    return CGImageSourceCreateThumbnailAtIndex(imageSource, 0, options as NSDictionary).flatMap { UIImage(cgImage: $0) } 
} 
} 
Các vấn đề liên quan