2008-11-25 37 views
64

Tôi muốn tải một số hình ảnh vào ứng dụng của mình từ hệ thống tệp. Có 2 cách dễ dàng để làm điều này:Sự khác nhau giữa [UIImage imageNamed ...] và [UIImage imageWithData ...]?

[UIImage imageNamed:fullFileName] 

hay:

NSString *fileLocation = [[NSBundle mainBundle] pathForResource:fileName ofType:extension]; 
NSData *imageData = [NSData dataWithContentsOfFile:fileLocation]; 

[UIImage imageWithData:imageData]; 

Tôi thích là người đầu tiên vì nó là ít hơn rất nhiều mã, nhưng tôi đã thấy một số người nói rằng hình ảnh được lưu trữ và phương pháp này sử dụng nhiều bộ nhớ hơn? Vì tôi không tin tưởng mọi người trên hầu hết các diễn đàn khác, tôi nghĩ tôi sẽ đặt câu hỏi ở đây, có sự khác biệt thực tế nào không, và nếu như vậy cái nào là 'tốt hơn'?

Tôi đã thử lược tả ứng dụng của mình bằng công cụ Phân bổ đối tượng và tôi không thể thấy bất kỳ khác biệt thực tế nào, mặc dù tôi chỉ thử trong trình mô phỏng chứ không phải trên iPhone.

+2

Hoặc, bạn có thể sử dụng [hình ảnh UIImageWithContentsOfFile: đường dẫn], không lưu hình ảnh. – bentford

Trả lời

90

Tùy thuộc vào những gì bạn đang làm với hình ảnh. Phương thức imageNamed: lưu bộ nhớ cache hình ảnh, nhưng trong nhiều trường hợp sẽ giúp sử dụng bộ nhớ. Ví dụ: nếu bạn tải một hình ảnh 10 lần để hiển thị cùng với một số văn bản trong chế độ xem bảng, UIImage sẽ chỉ giữ một biểu diễn duy nhất của hình ảnh đó trong bộ nhớ thay vì phân bổ 10 đối tượng riêng biệt. Mặt khác, nếu bạn có một hình ảnh rất lớn và bạn không sử dụng lại nó, bạn có thể muốn tải hình ảnh từ một đối tượng dữ liệu để đảm bảo nó bị xóa khỏi bộ nhớ khi bạn hoàn tất.

Nếu bạn không có bất kỳ hình ảnh lớn nào, tôi sẽ không lo lắng về điều đó. Trừ khi bạn thấy một vấn đề (và kudo để kiểm tra Phân bổ đối tượng thay vì tối ưu hóa trước), tôi sẽ chọn ít dòng mã hơn những cải tiến bộ nhớ không đáng kể.

+0

Tôi có câu hỏi, sau khi tôi sử dụng 'imageNamed', nó lưu trữ hình ảnh, ok, sau đó, tôi nên làm gì để giải phóng hình ảnh được lưu trong bộ nhớ đó khỏi bộ nhớ? Nó sẽ tự động phát hành? Thx –

+0

Nó sẽ được phát hành tự động nếu có cảnh báo bộ nhớ thấp. –

5

Tôi cũng được thông báo rằng [UIImage imageNamed:] có quá nhiều bộ nhớ đệm và hình ảnh không được phát hành thường xuyên. Tôi được yêu cầu phải cẩn thận khi sử dụng nó.

+0

Tôi gặp sự cố với bộ nhớ đệm. Ứng dụng của tôi đang tải hình ảnh, sau đó ghi đè lên tệp hình ảnh và điều đó đã gây ra những hình ảnh và các thông báo gỡ rối đáng sợ thực sự kỳ lạ từ thư viện JPEG. –

+5

Tôi nghĩ rằng điều này đã lỗi thời. –

10

Trong kinh nghiệm của tôi [UIImage imageNamed:] có hiệu suất tốt hơn đáng kể, đặc biệt khi được sử dụng trong UITableViews.

Nó không chỉ là bộ nhớ mà còn giải mã image. Có nó được lưu trữ nhanh hơn nhiều.

+1

Thậm chí quan trọng hơn là reuseIdentifier trên các ô - nếu bạn không sử dụng lại hiệu suất của ô bảng sẽ bị ảnh hưởng. –

3

imageWithData rất hữu ích khi bạn lưu trữ nhị phân hình ảnh trong cơ sở dữ liệu hoặc tải xuống hình ảnh lớn từ web.

0

Tôi sẽ không sử dụng trí tưởng tượng nếu ứng dụng của bạn có vô số hình ảnh lớn không giống nhau. Tôi đã gặp phải sự cố ứng dụng do sử dụng quá nhiều.

+0

ditto, ứng dụng của tôi đã bị lỗi do imageNamed trên một số hình ảnh lớn hơn. Tôi nghĩ rằng đó là một rò rỉ bộ nhớ, nhưng không có bằng chứng về điều đó cả. Mất một lúc để nhận ra bởi vì nó đã xảy ra liên tục, nhưng imageWithData đã giải quyết vấn đề. – yeahdixon

+0

Roger: Bạn có một liên kết với thông tin, để sao lưu nó? Tôi đã gặp vấn đề tương tự với imageNamed và tắt (chủ yếu là với nhiều hình ảnh lớn) và luôn sử dụng các trình khởi tạo khác để giải quyết vấn đề. – Jonny

-11

Tôi không tin rằng hình ảnh được lưu vào bộ nhớ cache và tôi không biết tại sao tất cả các bạn đều nói điều đó. UIImage là lớp con của NSObject sử dụng bộ đếm tham chiếu để theo dõi những thứ liên quan đến nó. Vì vậy, khi bạn tải một hình ảnh nó làm điều tương tự. Nếu bạn tải cùng một hình ảnh nhiều lần nó sẽ (hoặc nên) chỉ có một bản sao của hình ảnh trong bộ nhớ và chỉ tăng bộ đếm tham chiếu mỗi lần bạn phải sử dụng một cái gì đó với hình ảnh đó. Bởi bộ đếm tham chiếu Tôi có nghĩa là khi đếm được đến 0 nó xóa chính nó. do đó, "phân bổ", "giữ lại" là mỗi +1 cho số lượng và "phát hành" là -1. Nó không chỉ là cách tốt hơn để quản lý bộ nhớ mà còn giúp lập trình dọn dẹp bộ nhớ.

+1

Bạn có thể vui lòng cho chúng tôi biết bất kỳ tài liệu nào về việc này không? – Plumenator

+2

Xin lỗi - nhưng tôi nghĩ * nó được lưu trữ * và nó khá nổi tiếng. Để có một bài đăng trên blog tốt (không phải blog của tôi), hãy đọc tại đây: http://www.alexcurylo.com/blog/2009/01/13/imagenamed-is-evil/ – Magnus

+0

Đây là một nguồn tôi tìm thấy, cuộn xuống bộ nhớ phần quản lý. – andrew

7

Nếu bạn không muốn hình ảnh của bạn làm được cached bạn cũng có thể sử dụng trực tiếp initWithContentsOfFile:

NSString *fileLocation = [[NSBundle mainBundle] pathForResource:fileName ofType:extension]; 
UIImage* yourImage = [[[UIImage alloc] initWithContentsOfFile:imagePath] autorelease]; 
9

Khi tham khảo API của UIImage nói:

+ (UIImage *) imageNamed: (NSString *) name

Phương pháp này tìm trong bộ nhớ cache của hệ thống đối tượng hình ảnh với mẫu d tên và trả về đối tượng đó nếu nó tồn tại. Nếu một đối tượng hình ảnh phù hợp chưa có trong bộ đệm ẩn, phương thức này sẽ tải dữ liệu hình ảnh từ tệp được chỉ định, lưu trữ nó và sau đó trả về đối tượng kết quả.

+ (UIImage *) imageWithContentsOfFile: (NSString *) đường dẫn

Phương pháp này không cache đối tượng hình ảnh.

như vậy, chúng ta có thể thấy rằng nếu bạn có rất nhiều cùng phần UI (như UITableViewCell) có thể sử dụng cùng một hình ảnh (thường là một biểu tượng), và do hiệu suất, tất nhiên chúng tôi muốn sử dụng lại cùng một hình ảnh, để chúng tôi sẽ tiết kiệm bộ nhớ cho việc sử dụng khác. Hình ảnh tái sử dụng thường được sử dụng trong phần tử ui mà người dùng của chúng tôi có thể hoạt động trên đó nhiều lần. Vì vậy, nó có giá trị cho chúng tôi để tái sử dụng nó. Vì vậy, bạn có thể chọn sử dụng phương thức imageNamed.

Mặt khác, trong một ứng dụng sẽ có một số yếu tố giao diện UI sẽ có trong vòng đời của ứng dụng, chẳng hạn như Nút, chế độ xem biểu trưng. cũng ở đó trong vòng đời của ứng dụng, bạn sẽ không cân nhắc xem những hình ảnh này có phải là bộ nhớ cache hay không. Do đó, bạn có thể chọn sử dụng phương thức imageNamed.


Ngược lại, trong một ứng dụng, thường có một số UI Elements đã tạo ra động. Ví dụ, ứng dụng của chúng tôi hỗ trợ động nền, để người dùng có thể chọn nền họ thích. Và nền có thể là hình ảnh. Do đó, chúng tôi có thể có giao diện liệt kê rất nhiều khác nhau nền (thường hiển thị bằng cách sử dụng UIImageView) cho người dùng lựa chọn, chúng ta có thể đặt tên cho xem danh sách MyBackgroundListView vì vậy, khi người dùng chọn một hình nền , các MyBackgroundListView nên bị hủy diệt, bởi vì nó có chức năng finishs .Công thời gian tiếp theo của nó cho người sử dụng muốn thay đổi nền của họ, chúng tôi có thể tạo MyBackgroundListView lần nữa Vì vậy, các hình ảnh sử dụng bởi MyBackgroundListView nên không được lưu trữ, hoặc bộ nhớ ứng dụng của chúng ta sẽ cạn kiệt Vì vậy, thời gian này bạn nên sử dụng imageWithContentsOfFile phương pháp.

Khi Apple doc Supporting High-Resolution Screens In Views nói

Trên các thiết bị với màn hình độ phân giải cao, các imageNamed:, imageWithContentsOfFile:initWithContentsOfFile: phương pháp tự động tìm kiếm một phiên bản của hình ảnh theo yêu cầu với @ 2x modifier trong tên của nó. Nếu nó tìm thấy một, nó tải hình ảnh đó để thay thế. Nếu bạn không cung cấp phiên bản có độ phân giải cao của một hình ảnh nhất định, đối tượng hình ảnh vẫn tải hình ảnh có độ phân giải tiêu chuẩn (nếu có) và chia tỷ lệ trong khi vẽ.

vì vậy bạn sẽ lo lắng về đường dẫn tìm kiếm của hình ảnh cho vấn đề màn hình võng mạc. IOS sẽ giúp bạn đối phó với nó.

Xin lỗi vì tiếng Anh kém của tôi. Có thể nó hữu ích.