2012-04-30 25 views
15

Làm cách nào để tìm đường dẫn đến hình ảnh bằng cách sử dụng phương pháp NSBundlepathForResource khi tạo UIImage bằng cách sử dụng imageNamed? Tôi thấy mã hướng dẫn chỉ cần chỉ định tên của hình ảnh trực tiếp, và sau đó mã đi thêm dặm để tìm đường dẫn đầu tiên.Hình ảnh UIImageNamed yêu cầu pathForResource?

Theo kinh nghiệm của tôi, tôi đã luôn chỉ sử dụng tên trực tiếp và nó luôn hoạt động tốt. Tôi cho rằng nó tự động biết cách tìm hình ảnh. Làm thế nào quan trọng hoặc trong những trường hợp nào nó sẽ là cần thiết để làm nhiều hơn thế này?

+0

[Ở đây] (http://stackoverflow.com/questions/924740/dispelling-the-uiimage-imagenamed-fud) là bài đăng SO về cách sử dụng imageNamed trong mã của bạn mà bạn có thể muốn đọc. Không liên quan trực tiếp đến câu hỏi của bạn, nhưng tôi thấy nó rất hữu ích. – zero0cool

Trả lời

5

Tài liệu nói rằng "phương pháp tìm kiếm hình ảnh có tên được chỉ định trong gói chính của ứng dụng", vì vậy tôi cho rằng bạn luôn có thể chỉ sử dụng tên. Ngoại lệ duy nhất có thể là hình ảnh được lưu trữ bên trong thư mục con, đặc biệt là khi bạn có foo/image.pngbar/image.png. Tôi không biết liệu [UIImage imageNamed:@"foo/image"] có hoạt động hay không, nhưng nó không đáng để thử.

(Có gì hơi rắc rối trong những trường hợp này là các nhóm trong cây Xcode không tương ứng với các thư mục trong gói ứng dụng kết quả. Nội dung của chúng được đập vào nhau trong thư mục gốc, trừ khi bạn sử dụng tham chiếu thư mục màu xanh thay vì một nhóm thông thường.)

+2

Trên thực tế bạn đã chính xác, nó hoạt động, nhưng (và nó là một lớn nhưng) _only_ nếu "foo" là một thư mục trong gói của bạn, do đó một thư mục "màu xanh" trong Xcode. Trong trường hợp phổ biến nhất bạn không cần "foo" cả. (Điểm đặt hàng: bạn không nên trả lời nếu bạn chỉ có tài liệu và dự đoán tiếp tục, bạn cũng không nên chấp nhận câu trả lời nếu nó không giải quyết được vấn đề của bạn - nếu bạn có thư mục màu xanh, thì tất cả đều tốt , nếu không, thì điều này không thể có hiệu quả với bạn.) Xem bài luận dài về chủ đề dưới đây – Rhubarb

-1

Hãy thử điều này.

[UIImage imageNamed:@"your directory path of image"] 

[UIImage imageNamed: @ "dir1/folder1/folder2/imagename.jpeg"]

57

Không hề ... là câu trả lời cho câu hỏi ban đầu:

Làm cách nào để tìm kiếm đường dẫn đến hình ảnh bằng cách sử dụng phương thức NSBundle pathForResource khi tạo UIImage bằng imageNamed?

Không có nhiều .. là cách đúng câu trả lời chấp nhận từ Zoul và một trong những khác từ Ranga đang có. Để công bằng: chúng là chính xác nếu bạn đang nói về cấu trúc thư mục gói ứng dụng hoặc cho trường hợp (hiếm) trong đó hình ảnh nằm trong thư mục "xanh dương" trong Xcode (nhiều hơn về sau), nhưng không phải cho nhiều nhất các trường hợp phổ biến

Dù sao, vào một câu trả lời đúng.

Như thường lệ, tôi đã tìm thấy câu hỏi này trong khi tự mình tìm câu trả lời. Tôi chưa bao giờ tìm thấy tài liệu hoặc các câu trả lời khác cho câu hỏi này đạt yêu cầu, vì vậy tôi quyết định thử nghiệm.

Chi tiết kiểm tra của tôi là tất cả bên dưới, nhưng hãy để tôi tóm tắt kết quả tại đây. Nói tóm lại, khi sử dụng imageNamed: để tải hình ảnh của bạn, nó phụ thuộc vào nơi bạn đặt chúng:

  1. nếu hình ảnh của bạn trong thư mục gốc của dự án của bạn, ngay cả khi tổ chức trong một nhóm Xcode hoàn toàn hợp lý, sau đó không , bạn không cần cần phải suy nghĩ về đường dẫn: chỉ cần tên hình ảnh.

  2. nếu ảnh của bạn nằm trong nhóm được đính kèm vào thư mục trong hệ thống tệp của bạn, thông qua "tạo nhóm cho thư mục được thêm" thì bạn vẫn không cần phải lo lắng về tên.

  3. nếu hình ảnh của bạn nằm trong nhóm "xanh", được đính kèm vào thư mục trong hệ thống tệp của bạn qua "tạo thư mục tham chiếu cho thư mục được thêm", sau đó bạn có thể tải nó bằng imageNamed: được đề xuất (trùng hợp?) bởi câu trả lời được chấp nhận ở trên.

  4. nếu bạn sử dụng thay thế chính cho imageNamed :, imageWithContentsOfFile :, bạn thực sự cần đường dẫn đầy đủ đến tệp bao gồm đường dẫn gói, có nghĩa là bạn cần biết cấu trúc điều hướng Xcode chuyển thành đường dẫn trong gói của bạn như thế nào Cấu trúc thư mục.

Sự khác biệt quan trọng khác giữa hai phương pháp:

  • imageNamed không yêu cầu bạn chỉ định phần mở rộng filetype, nên chỉ đơn thuần là "biểu tượng" không phải là "icon.png", trong khi imageWithContentsOfFile làm yêu cầu tên tệp đầy đủ
  • điểm đầu tiên này sẽ giúp với tính năng thứ hai: imageNamed sẽ tự động tải phiên bản võng mạc của hình ảnh nếu có, bằng cách thêm @ 2 x vào tên tệp của bạn. Vì vậy, nếu bạn yêu cầu "biểu tượng", trên màn hình hiển thị võng mạc , nó sẽ cố tải "[email protected]". imageWithContentsOfFile không
  • imageNamed lưu trữ hình ảnh: và trong đó có rất nhiều tranh cãi xung quanh nó: Nếu bạn tìm kiếm SO hoặc web lớn bạn sẽ tìm thấy nhiều bài viết đề xuất bạn tránh nó vì nó không ' t xóa bộ nhớ cache đúng cách. Điều này, tuy nhiên, đã được cố định năm trước, vì vậy bạn không cần phải lo lắng về nó không xóa bộ nhớ cache của nó. Bạn làm vẫn còn cần phải lo lắng về thực tế là nó lưu trữ ở tất cả, mặc dù. Nếu hình ảnh của bạn là lớn và không được tải rất thường xuyên, bạn sẽ bảo tồn bộ nhớ bằng cách tải chúng từ tệp và không lưu vào bộ nhớ cache. Đây là không có gì để làm với rò rỉ: ngay cả khi bạn không bị rò rỉ, bạn vẫn còn có bộ nhớ giới hạn trên thiết bị và bạn không muốn cache không cần thiết. Đó là sự cân bằng bộ nhớ đệm cổ điển: điều gì là quan trọng hơn trong trường hợp của bạn là ? Hiệu suất bộ nhớ hoặc hiệu suất CPU (thời gian).

Vì vậy, với các thử nghiệm của tôi.

Điều tôi đã làm là tạo một ứng dụng UITableView đơn giản với 3 tệp biểu tượng đơn giản, được hiển thị trong các hàng của bảng bằng các phương pháp khác nhau. Các biểu tượng khác nhau ở vị trí của chúng trong cấu trúc dự án Xcode. Lưu ý sự nhấn mạnh trên Xcode. Chìa khóa để hiểu câu trả lời cho câu hỏi ban đầu là có ba cấu trúc thư mục dự án hoàn toàn khác nhau trong ứng dụng iOS: Có một cấu trúc bạn thấy trong trình điều hướng Xcode, một trong hệ thống tệp cho cùng một dự án mà bạn thấy trong Trình tìm kiếm (nhấp chuột phải vào bất kỳ mục nào trong trình điều hướng Xcode và chọn "hiển thị trong Trình tìm kiếm") và, bạn hiếm khi thấy, cấu trúc thư mục "bó" của ứng dụng được triển khai. Bạn có thể thấy cái cuối cùng này trong Finder - bằng cách tìm ứng dụng của bạn trong ~/Library/Application Support/iPhone Simulator, và đi sâu vào thư mục .app. Tôi sẽ cho bạn xem một bức ảnh của tôi trong một phút.

Vì vậy, trong ứng dụng của tôi, tôi kéo cả ba biểu tượng png tập tin hình ảnh vào Xcode theo những cách khác nhau:

  1. icon1.png (đồng hồ), tôi lôi vào cuộc như một tập tin vào thư mục gốc của Xcode dự án, thì I sau này đã tạo một nhóm mới trong Xcode và kéo nó vào . Nhóm này không được đại diện bởi bất kỳ thư mục nào trong tệp hệ thống: đó là một nhóm Xcode thuần túy. Do đó tên của nó: "JustGroup"

  2. icon2.png (một mắt), tôi ban đầu đặt hệ thống tập tin của tôi trong thư mục gọi là "RealDir", và tôi kéo toàn bộ thư mục này vào Xcode, và khi hỏi, tôi đã chọn tùy chọn "Tạo nhóm cho bất kỳ thư mục được thêm nào". Điều này có nghĩa là nhóm RealDir trong Xcode được đính kèm vào thư mục thực được gọi là RealDir trong hệ thống tệp (trong thư mục dự án của tôi) và biểu tượng đó2.png nằm trong đó.

  3. icon3.png (mục tiêu), tôi cũng có trong một thư mục riêng biệt, mà tôi cũng đã kéo vào Xcode. Chỉ có thời gian này tôi đã chọn tùy chọn radio thứ hai "Tạo tài liệu tham khảo thư mục cho bất kỳ thư mục nào được thêm". Điều này tạo ra một nhóm gọi là "xanh" trong Xcode. Thông tin thêm về điều này là về sau. Tôi gọi nhóm này (và thư mục) "FolderReference"

Dưới đây là một shot của sự lựa chọn đó Xcode mang đến cho bạn: Xcode's dialog when dragging a directory in

Và đây là những gì cấu trúc dự án của tôi trông như thế nào trong Xcode: Xcode navigator project structure

Bây giờ, trong ứng dụng của tôi, tôi đã sử dụng hai phương pháp để tải từng biểu tượng: UIImage imageNamed: và UIImage imageWithContentsOfFile. Tôi tạo ra một loạt các hàng trong bảng của tôi với tiêu đề của mỗi ô là tên của nhóm chứa biểu tượng: JustGroup, RealDir hoặc FolderReference, cộng với tên của phương thức được sử dụng: imageNamed vs fromFile (mà tôi sử dụng như viết tắt của imageWithContentsOfFile)

Nhãn chi tiết của ô (văn bản mờ hơn bên dưới tiêu đề) hiển thị tên tệp hoặc tên đường dẫn mà tôi đã cung cấp cho phương thức.

Để rõ ràng, trong trường hợp "fromFile", tôi đang thêm đường dẫn gói vào tên "tương đối" mà bạn nhìn thấy. Vì vậy cho "fromFile", tôi thực sự sử dụng mã này:

NSString *bundlePath = [[NSBundle mainBundle] bundlePath]; 
NSString *imagePath = [NSString stringWithFormat:@"%@/%@", bundlePath, filePath]; 
UIImage *image = [UIImage imageWithContentsOfFile:imagePath]; 

nơi "filepath" là con đường mà bạn nhìn thấy trong nhãn bảng chi tiết tế bào. Đối với imageNamed :, mặt khác, tệp tệpPath trong chi tiết ô được thông qua nguyên văn.

Và hàng image là, một cách tự nhiên, hình ảnh được tải. Vì vậy, đối với các hàng trong bảng không có hình ảnh, tải hình ảnh không thành công.

Ở đây, tóm lại, là kết quả. Nếu bạn không đọc gì về bài đăng này, ít nhất là lướt qua hình ảnh này sẽ cho bạn biết tất cả những gì bạn cần biết.

app shows which icons were loaded

Dưới đây là lời giải thích cơ bản tại các điểm dễ dàng tiêu hóa:

  • vì nó khẳng định trong các tài liệu chính thức, imageNamed: Phương pháp tải hình ảnh từ các gói ứng dụng. Điều này có nghĩa là bạn không cần chỉ định vị trí gói, chỉ tên tệp. Và thậm chí sau đó, chỉ là tên cơ sở của tệp. Tài liệu này hơi mỏng ở đây, nó thực sự sẽ làm cho nó rõ ràng rằng nó tải hình ảnh từ đường dẫn tệp nhất định tương đối vào thư mục gốc của gói ứng dụng.

  • (đây là kicker, chú ý đến điều này) quy tắc đó về thư mục bó, tham chiếu đến thư mục gốc trong gói ứng dụng được triển khai của bạn. Nếu bạn đi khám phá, điều đó có nghĩa là trong thư mục ".app". Đó là không giống nhau như thư mục gốc của dự án Xcode trong navigator Xcode, cũng không phải là giống như các thư mục gốc của dự án Xcode trong công cụ tìm

  • này là bởi vì, khi triển khai ứng dụng của bạn để thiết bị (hoặc trình mô phỏng) tất cả các thư mục dự án được đại diện bởi "nhóm cho thư mục được thêm" là được làm phẳng. Đó là, thư mục bị bỏ qua, và tất cả các nội dung của nó được bỏ qua một cách vô thức trong thư mục gốc của gói. (Tôi nói "unceremoniously" bởi vì nếu có các tập tin có cùng tên trong các thư mục khác nhau, họ sẽ va chạm ở đây và bạn sẽ không nhận được sự trợ giúp trong việc giải quyết các vấn đề gây ra.) Đây là trường hợp của RealDir trong ví dụ của tôi: trong ứng dụng được triển khai, RealDir không còn tồn tại nữa và biểu tượng2.png còn lại để kết hợp với dân số chung (đáng sợ). Nó gần như không nói rằng "JustGroup", nhóm Xcode thuần túy hợp lý, cũng bị bỏ qua - nó chưa bao giờ là thư mục thực, chỉ là một trợ giúp trực quan cho người dùng Xcode - và icon1.png cũng nằm trong thư mục gốc.

    • Đây là lý do imageNamed: có thể tải biểu tượng2.

    • Và cũng tại sao imageWithContentsOfFile đã không thể tìm thấy nó trong "RealDir/image2.png": vì có không có thư mục RealDir trong ứng dụng triển khai.

  • "thư mục màu xanh", mặt khác, có nghĩa là, các thư mục đại diện bởi "tài liệu tham khảo thư mục cho các thư mục bổ sung", là trên thực tế vẫn giữ trong gói ứng dụng cấu trúc thư mục. Điều này, rõ ràng là điểm của các thư mục màu xanh: chúng cung cấp cho bạn một cách để tạo cấu trúc thư mục trong ứng dụng được triển khai của bạn. Tôi không chắc chắn về bản gốc này, nhưng một trường hợp sử dụng tốt là nơi bạn có một số thư mục chứa các phiên bản thay thế của các tệp tài nguyên có cùng tên và bạn muốn ứng dụng của mình có thể chuyển đổi giữa chúng khi chạy bằng cách thay đổi thư mục. Dù sao, icon3.png trong FolderReference của tôi, vẫn nằm trong thư mục FolderReference của tôi trong ứng dụng được triển khai.

    • Đây là lý do tại sao imageNamed: không thể tìm thấy nó với "Icon3", nhưng thể thấy nó với "FolderReference/Icon3"
    • imageWithContentsOfFile đã có thể tìm thấy nó cũng sử dụng FolderReference, nhưng chỉ khi được đính kèm, hãy nhớ đến đường dẫn gói đầy đủ bằng cách sử dụng mã ở trên. (Sự khác biệt chính ở đây: imageNamed làm việc với một đường dẫn tương đối trong trường hợp này, imageWithContentsOfFile luôn làm việc với một đường dẫn tuyệt đối).

Để làm rõ, đây là một cấu trúc thư mục của tôi:

Bạn thấy Xcode cấu trúc hoa tiêu dự án của tôi ở trên, đây là thư mục hệ thống tập tin bên dưới: Finder Xcode project directory structure

Và cuối cùng, có lẽ quan trọng nhất, cấu trúc thư mục hệ thống tệp bó được triển khai: deployed bundle directory structure

Lưu ý: Tôi tìm thấy t tại vị trí này trên máy Mac của tôi: bạn sẽ tìm thấy vị trí của bạn ở một vị trí tương tự - bạn có thể phải tìm kiếm một chút để tìm thư mục con có tên xấu xí-GUID nào chứa ứng dụng của bạn.

~/Library/Application Support/iPhone Simulator/5.1/Applications/4EB386B2-CD7E-4590-9757-18DDDEE6AF4F/ImageLoadingTest.app 

Tôi hy vọng điều này sẽ hữu ích. Thử nghiệm, khám phá và cuối cùng, mô tả nó chắc chắn đã giúp tôi.

+0

Điều này đáng lẽ phải là câu trả lời, cảm ơn bạn đã gửi bài. – dashesy

+0

Đây là câu trả lời hữu ích và đã giải quyết vấn đề này cho tôi. Phải là câu trả lời được chấp nhận. Upvoted và cảm ơn. – scottburton11

+1

Tại sao câu trả lời này không được chấp nhận? Nó là tuyệt vời! –

0

Tôi đã tạo một dự án Xcode mới (xem đơn, AppDelelgate, lớp ViewController, bảng phân cảnh, v.v.). Đã tạo một nhóm Hình ảnh. Được sử dụng Paintbrush để tạo tệp 16ng16 png Wall1.png và thả nó vào nhóm Hình ảnh trong Xcode (để Xcode sao chép các tệp).

Trong phương pháp ViewController viewDidLoad thêm mã:

UIImageView* imageView=[[UIImageView alloc] initWithFrame:CGRectMake(50, 100, 16, 16)]; 
UIImage *image = [UIImage imageWithContentsOfFile: [[NSBundle mainBundle] pathForResource:@"Images/Wall1" ofType:@"png"]]; 
imageView.image = image; 
    UIImageView* imageView=[[UIImageView alloc] initWithFrame:CGRectMake(50, 100, 16, 16)]; 
UIImage *image = [UIImage imageWithContentsOfFile: [[NSBundle mainBundle] pathForResource:@"Wall1" ofType:@"png"]]; 
imageView.image = image; 
[self.view addSubview:imageView]; 

Ran ứng dụng trên điện thoại của tôi, hình ảnh sẽ không xuất hiện

gia tăng một điểm break ở [self.view addSubview: IMAGExem];

hình ảnh là null

Thiết bị đầu cuối đã mở và thư mục thay đổi cho dự án của tôi, Wall1.png không phải là thư mục nhóm Hình ảnh. Đã xóa png khỏi dự án, đã tạo thư mục Hình ảnh, đã di chuyển Wall1.png vào thư mục. Đã thêm tập tin hiện có Wall1.png vào nhóm Hình ảnh.

Chạy ứng dụng, hình ảnh vẫn không xuất hiện.

hình ảnh là vô

hình ảnh Thay đổi/Wall1 để Wall1

Ran ứng dụng, hình ảnh bùng nổ là displayed1

Nếu bạn tạo một nhóm cho hình ảnh của bạn, Xcode không tạo ra một thư mục tương ứng. Tạo một thủ công nếu bạn muốn (tôi thích giữ hình ảnh của tôi trong một thư mục riêng biệt). Không chỉ định đường dẫn đầy đủ đến tệp hình ảnh của bạn khi sử dụng hình ảnh UIImageWithContentsOfFile.

Các vấn đề liên quan