UIImage imageNamed wymaga pathForResource?

Jak konieczne jest wyszukiwanie ścieżki do obrazu przy użyciu metody NSBundle pathForResource Podczas tworzenia UIImage przy użyciu imageNamed? Widzę kody samouczka, które po prostu określa nazwę obrazu bezpośrednio, a następnie kod, który idzie o krok, aby znaleźć ścieżkę jako pierwszy.

Z mojego doświadczenia wynika, że zawsze używałem nazwy bezpośrednio i zawsze działało dobrze. Założyłem, że automatycznie wie, jak znaleźć obraz. Jak ważne lub w jakich okolicznościach byłoby konieczne, aby zrobić więcej niż to?
Author: The iOSDev, 2012-04-30

4 answers

Dokumenty mówią, że "metoda szuka obrazu o określonej nazwie w głównym pakiecie aplikacji", więc powiedziałbym, że zawsze możesz użyć tylko nazwy. Jedynym wyjątkiem mogą być obrazy przechowywane w podfolderach, zwłaszcza jeśli masz foo/image.png i bar/image.png. Nie wiem, czy [UIImage imageNamed:@"foo/image"] zadziała, ale trywialne jest próbować.

(co jest nieco mylące w tych przypadkach jest to, że grupy w drzewie Xcode nie odpowiadają folderów w otrzymanym pakiecie aplikacji. Ich zawartość jest rozbita razem do katalogu głównego pakietu, chyba że zamiast zwykłej grupy użyjesz niebieskiego odniesienia do folderu.)

 5
Author: zoul,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-30 08:54:20

Ani trochę ... jest odpowiedzią na pierwotne pytanie:

Jak konieczne jest wyszukiwanie ścieżki do obrazu przy użyciu metody nsbundle pathForResource podczas tworzenia interfejsu Użytkownika za pomocą ImageName?

Niewiele .. czy jest poprawna zaakceptowana odpowiedź od Zoula i drugiej od Ranga są. Aby być uczciwym: są poprawne, jeśli mówimy o strukturze katalogów pakietu aplikacji lub (rzadkim) przypadku, w którym obraz jest w" niebieskim " folderze w Xcode (więcej o tym później), ale nie w najczęstszych przypadkach

W każdym razie, przejdźmy do jednej prawdziwej odpowiedzi.

Jak zwykle znalazłem to pytanie, próbując znaleźć odpowiedź. Nigdy nie znalazłem zadowalającej dokumentacji ani innych odpowiedzi na to pytanie, więc postanowiłem przetestować.

Moje szczegóły testu są poniżej, ale pozwól mi podsumować wyniki tutaj. Krótko mówiąc, Gdy używasz imageNamed: aby załadować obrazy, zależy, gdzie umieścisz oni:

  1. Jeśli obrazy znajdują się w katalogu głównym projektu, nawet jeśli są zorganizowane w czysto logiczną grupę Xcode, to Nie, Nie trzeba myśleć o ścieżce: tylko nazwa obrazu.

  2. Jeśli Twoje obrazy znajdują się w grupie, która jest dołączona do katalogu w Twoim systemie plików, poprzez "utwórz grupy dla dodanych folderów", to nadal nie musisz się martwić o nazwę.

  3. Jeśli obrazy znajdują się w grupie" niebieskiej", która jest dołączona do katalogu w systemie plików poprzez "create folder references for added folders", następnie możesz załadować go z imageNamed: podając ścieżkę względną zgodnie z sugestią (przypadkowo?) przez zaakceptowaną powyżej odpowiedź.

  4. Jeśli używasz głównej alternatywy dla imageNamed:, imageWithContentsOfFile:, rzeczywiście potrzebujesz pełnej ścieżki do pliku, w tym ścieżki pakietu, co oznacza, że musisz wiedzieć, jak struktura Xcode navigator przekłada się na ścieżki w katalogu pakietu struktura.

Inne istotne różnice między tymi dwiema metodami:

  • imageNamed nie wymaga podania rozszerzenia typu pliku, więc po prostu" ikona "nie" ikona.png", natomiast imageWithContentsOfFile robi wymagaj pełnej nazwy pliku
  • ten pierwszy punkt pomaga w drugiej funkcji: imageNamed will automatycznie załaduj wersję retina obrazu, jeśli taka istnieje, dodając @2x do nazwy pliku. Więc jeśli poprosisz o "ikonę", na a wyświetlacz retina spróbuje załadować "[email protected]". imageWithContentsOfFile Nie
  • imageNamed buforuje obraz: i w nim leży wiele kontrowersje wokół niego: jeśli szukasz tak lub w Internecie na ogół będziesz znajdź dużo postów polecających unikaj tego, bo nie Wyczyść pamięć podręczną. To jednak zostało naprawione lata temu, więc ty nie musisz się martwić, że nie wyczyści swojej pamięci podręcznej. You do still musisz się jednak martwić o to, że w ogóle się buforuje. Jeśli obrazy są Duże i nie są ładowane zbyt często, zachowasz pamięci poprzez wczytywanie ich z pliku i nie buforowanie ich. To jest nie ma to nic wspólnego z przeciekami: nawet jeśli nie masz przecieków, nadal masz ograniczoną pamięć na urządzeniu i nie chcesz buforować niepotrzebnie. To klasyczny kompromis buforowania: co więcej ważne w twojej sytuacji? Wydajność pamięci lub procesora (czas).
Tak dalej z moimi testami.

To, co zrobiłem, to stworzenie prostego Aplikacja UITableView z 3 prostymi plikami ikon, pokazanymi w wierszach tabeli przy użyciu różnych metod. Ikony różnią się w swojej lokalizacji w strukturze projektu Xcode. Zwróć uwagę na nacisk na Xcode. Kluczem do zrozumienia odpowiedzi na oryginalne pytanie jest to, że istnieją trzy zupełnie różne struktury katalogów projektów w aplikacji na iOS: jest jeden, który widzisz w Xcode navigator, jeden w systemie plików dla tego samego projektu, który widzisz w Finderze (kliknij prawym przyciskiem myszy dowolny projekt). pozycja w Xcode navigator i wybierz "Pokaż w Finderze") i, jeden rzadko widać," pakiet " struktura katalogów wdrożonej aplikacji. Ten ostatni możesz zobaczyć również w Finderze-znajdując swoją aplikację w ~/Library/Application Support / iPhone Simulator, i wiercąc w dół do .katalog aplikacji. Pokażę Ci moje zdjęcie za chwilę.

Więc w mojej aplikacji przeciągnąłem wszystkie trzy pliki obrazów icon png do Xcode na różne sposoby:

  1. Icon1png (zegar), zaciągnąłem się jako plik do katalogu głównego projektu Xcode, następnie później utworzyłem nową grupę w Xcode i przeciągnąłem ją do to. Ta grupa nie jest reprezentowana przez żaden katalog w pliku system: to czysta Grupa Xcode. Stąd nazwa: "JustGroup"

  2. Icon2.png (oko), pierwotnie umieściłem mój system plików w katalogu o nazwie "RealDir", i przeciągnąłem cały katalog do Xcode, a kiedy zapytany, wybrałem opcję "Utwórz grupy dla dowolnych dodanych folderów". Oznacza to, że RealDir grupa w Xcode jest dołączona do prawdziwego katalog o nazwie RealDir w systemie plików (w katalogu mojego projektu) i ten icon2.png jest tam.

  3. Icon3.png (cel), miałem też w osobnym katalogu, który też przeciągnąłem do Xcode. Tylko tym razem wybrałem II opcję radia " Utwórz odniesienia do folderów dla dodanych folderów". Tworzy to tzw. Grupa "niebieska" w Xcode. Więcej na ten temat później. I nazywa tę grupę (i katalog) "FolderReference"

Oto strzał z wyboru, że Xcode daje Ci: Okno dialogowe Xcode podczas przeciągania katalogu w

A oto jak wygląda moja struktura projektu w Xcode: Struktura projektu Xcode navigator

Teraz, w mojej aplikacji, użyłem dwóch metod ładowania każdej z ikon: UIImage imageNamed: i UIImage imageWithContentsOfFile. Utworzyłem kilka wierszy w mojej tabeli z tytułem każdej komórki jest nazwa grupy zawierającej ikonę: JustGroup, realdir lub FolderReference, plus nazwa metody używane: imageNamed vs fromFile (którego używam jako skrótu imageWithContentsOfFile)

Etykieta szczegółów komórki (słabszy tekst pod tytułem) pokazuje nazwę pliku lub ścieżki, którą podałem metodzie.

Aby było jasne, w przypadku "fromFile" dodaję ścieżkę pakietu do" względnej " nazwy, którą widzisz. Więc dla "fromFile", faktycznie używam tego kodu:

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

Gdzie "filePath" jest ścieżką widoczną na etykiecie szczegółów komórki tabeli. Dla zapytania:, na z drugiej strony, ścieżka pliku w szczegółach komórki jest przekazywana werbalnie.

I wiersz obraz jest oczywiście obrazem, który jest ładowany. Tak więc dla wierszy w tabeli, które nie mają obrazu, ładowanie obrazu nie powiodło się.

Tutaj, w skrócie, są wyniki. Jeśli nie czytasz nic z tego postu, przynajmniej rzut oka na ten obraz powie Ci wszystko, co musisz wiedzieć.

aplikacja pokazuje, które ikony zostały załadowane

Oto podstawowe wyjaśnienie w łatwo przyswajalnych punktach:

  • Jako w oficjalnej dokumentacji stwierdza, że metoda imageNamed: ładuje obrazy z pakietu aplikacji. Oznacza to, że nie musisz podawać lokalizacji pakietu, tylko nazwę pliku. A nawet wtedy, tylko podstawowa nazwa pliku. Dokumentacja jest tutaj trochę cienka, powinno to wyraźnie zaznaczyć, że ładuje obraz z podanej ścieżki pliku relative do katalogu głównego pakietu aplikacji.

  • (Oto kicker, zwróć uwagę na ten), że zasada o katalogu pakietu, odnosi się do katalogu głównego w pakiecie wdrożonej aplikacji. Jeśli idziesz zwiedzać, oznacza to w ".app " katalog. To nie to samo co katalog główny projektu Xcode w Xcode navigator, ani nie jest to ten sam katalog główny projektu Xcode w Finderze

  • Dzieje się tak dlatego, że podczas wdrażania aplikacji do urządzenia (lub symulatora) wszystkie katalogi projektu reprezentowane przez " grupy do dodania foldery" są spłaszczone. Oznacza to, że katalog jest ignorowany, a cała jego zawartość wrzucana bezceremonialnie do katalogu głównego pakietu. (Mówię "bezceremonialnie", bo jeśli są pliki o tej samej nazwie w różnych folderach, to zderzą się tutaj i nie otrzymasz pomocy w rozwiązaniu problemów, które powodują.) Tak jest w przypadku RealDir w moim przykładzie: w wdrożonej aplikacji RealDir już nie istnieje, a icon2.png jest pozostawiony do mieszania się z populacją ogólną (przerażające). To idzie prawie bez powiedzenia, że "JustGroup", czysto logiczna Grupa Xcode, jest również ignorowane - to nigdy nie był prawdziwy katalog tak, tylko wizualna pomoc dla użytkownika Xcode - i icon1.png jest również w katalogu głównym pakietu.

    • To dlatego imageNamed: był w stanie załadować icon2.

    • A także dlaczego imageWithContentsOfFile nie mógł go znaleźć w "RealDir / image2.png": ponieważ nie ma katalogu RealDir w aplikacja.

  • "niebieskie foldery", z drugiej strony, czyli katalogi reprezentowane przez " odniesienia do folderów dla dodanych folderów", w rzeczywistości są przechowywane w strukturze katalogów pakietu aplikacji . Widocznie o to chodzi w niebieskich folderach: dają one sposób na stworzenie struktury katalogów w wdrożonej aplikacji. Nie jestem pewien oryginalnego raison d ' etre dla tego, ale jeden dobry przypadek użycia jest, gdy masz kilka katalogów zawierających alternatywne wersje plików zasobów o tej samej nazwie i chcesz, aby Twoja aplikacja mogła przełączać się między nimi w czasie wykonywania, zmieniając katalog. W każdym razie, icon3.png w moim FolderReference, pozostał w moim FolderReference katalogu w wdrożonej aplikacji.

    • to dlatego imageNamed: nie można go znaleźć za pomocą "icon3", ale można znaleźć za pomocą "FolderReference / icon3"
    • imageWithContentsOfFile był w stanie znaleźć go również za pomocą FolderReference, ale tylko po dołączeniu pamiętaj o ścieżce pełnego pakietu, używając powyższego kodu. (Kluczowa różnica: imageNamed działa ze ścieżką względną w tym przypadku imageWithContentsOfFile zawsze działa ze ścieżką bezwzględną).

Dla wyjaśnienia, oto moje struktury folderów:

Widziałeś moją strukturę Xcode project navigator powyżej, tutaj jest katalog systemu plików pod nim: Struktura katalogu projektu Finder Xcode

I wreszcie, być może najważniejsze, katalog wdrożonego systemu plików bundle struktura: wdrożona struktura katalogów pakietów

Uwaga: znalazłem to w tej lokalizacji na moim komputerze Mac: znajdziesz swój w podobnej lokalizacji - być może będziesz musiał trochę przeszukać, aby znaleźć podkatalog o nazwie ugly-GUID zawiera Twoją aplikację.

 ~/Library/Application Support/iPhone Simulator/5.1/Applications/4EB386B2-CD7E-4590-9757-18DDDEE6AF4F/ImageLoadingTest.app 
Mam nadzieję, że to pomoże. Testowanie, eksplorowanie i wreszcie, opisanie z pewnością mi pomogło.
 58
Author: Rhubarb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-08 14:42:59

Stworzyłem nowy projekt Xcode(single view, AppDelelgate, ViewController class, storyboard itp.). Utworzono grupę obrazów. Użyto pędzla do stworzenia pliku png Wall1 o wymiarach 16x16.png i wrzucił go do grupy obrazów w Xcode (niech Xcode skopiuje pliki).

W metodzie ViewController viewDidLoad dodano kod:

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];

Uruchomiłem aplikację na moim telefonie, obraz nie pojawi się

Dodano punkt przerwania na [self.view addSubview: imageView];

Obraz był null

Otworzyłem terminal i zmieniłem katalog na mój projekt, Wall1.png nie był folderem grupowym obrazów. Usunięto png z projektu, utworzono folder obrazów, przeniesiono Wall1.png do folderu. Dodano istniejący plik Wall1.png do zdjęć grupowych.

Uruchomił aplikację, obraz nadal się nie pojawia.

Obraz był null

Zmieniono obrazy / Wall1 na Wall1

Uruchomił aplikację, obraz wysięgnika jest wyświetlony1

Jeśli utworzysz grupę dla swoich obrazów, Xcode nie utwórz odpowiedni katalog. Utwórz je ręcznie, jeśli chcesz (wolę trzymać moje obrazy w oddzielnym folderze). Nie określaj pełnej ścieżki do pliku obrazu podczas korzystania z UIImage imageWithContentsOfFile.

 0
Author: Gary Davies,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-30 14:49:15

Spróbuj tego.

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

[UIImage ImageName:@ " Dir1 / folder1/folder2 / imagename.jpeg"]

 -1
Author: Ranga,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-30 09:13:54