16

usingを作成するときに、NSBundleメソッドを使用して画像へのパスを検索する必要がありますか?画像の名前を直接指定するチュートリアルコードと、最初にパスを見つけるためにさらに一歩進んだコードが表示されます。pathForResourceUIImageimageNamed

私の経験では、私はいつも名前を直接使用してきましたが、それは常にうまく機能しています。画像の見つけ方は自動的にわかると思いました。これ以上のことをする必要があるのはどれほど重要ですか、それともどのような状況ですか?

4

4 に答える 4

65

まったくそうではありません...元の質問への答えです:

imageNamedを使用してUIImageを作成する場合、NSBundleメソッドpathForResourceを使用して画像へのパスを検索する必要はありますか?

それほど多くはありません..Zoulからの受け入れられた答えとRangaからの他の答えがどれほど正しいかです。公平を期すために:アプリケーションバンドルのディレクトリ構造について話している場合、または画像がXcodeの「青」フォルダにある(まれな)場合(これについては後で詳しく説明します)は正しいですが、ほとんどの場合は正しくありません一般的なケース

とにかく、1つの本当の答えに。

いつものように、私は自分で答えを見つけようとしているときにこの質問を見つけました。この質問に対するドキュメントやその他の回答が満足のいくものであるとは思わなかったので、テストすることにしました。

私のテストの詳細はすべて以下にありますが、ここで結果を要約します。つまり、imageNamed:を使用して画像を読み込む場合、画像を配置する場所によって異なります。

  1. 画像がプロジェクトのルートにある場合、純粋に論理的なXcodeグループで編成されている場合でも、いいえ、パスについて考える必要はありません。画像名だけです。

  2. 「追加されたフォルダのグループを作成する」を介して、ファイルシステムのディレクトリに接続されているグループに画像が含まれている場合でも、名前を気にする必要はありません。

  3. 画像が「追加されたフォルダのフォルダ参照の作成」を介してファイルシステムのディレクトリに接続されている「青」グループにある場合は、提案された相対パスを指定することで、imageNamed:で画像を読み込むことができます(偶然ですか?)上記の受け入れられた答えによって。

  4. imageNamed:、imageWithContentsOfFile:の主な代替手段を使用する場合、バンドルパスを含むファイルへのフルパスが実際に必要です。つまり、Xcodeナビゲーター構造がバンドルディレクトリ構造内のパスにどのように変換されるかを知る必要があります。

これら2つの方法のその他の重要な違いは次のとおりです。

  • imageNamedではファイルタイプ拡張子を指定する必要がないため、「icon.png」ではなく「icon」のみが必要ですが、imageWithContentsOfFileでは完全なファイル名が必要です。
  • この最初のポイントは、2番目の機能に役立ちます。imageNamedは 、ファイル名に@ 2xを追加することにより、画像の網膜バージョンがあれば自動的にロードします。したがって、「アイコン」を要求すると、Retinaディスプレイで「icon@2x.png」を読み込もうとします。imageWithContentsOfFileはしません
  • imageNamedは画像をキャッシュします:そしてその中には多くの論争があります:SOまたはWeb全体を検索すると、キャッシュが適切にクリアされないため、回避することを推奨する投稿がたくさん見つかります。ただし、これは数年前に修正されたため、キャッシュのクリアに失敗することを心配する必要はありません。ただし、それでもキャッシュされるという事実について心配する必要はありません。画像が大きく、あまり頻繁に読み込まれない場合は、画像をキャッシュせずにファイルから読み込むことでメモリを節約できます。これはリークとは関係ありません。リークがなくても、デバイスのメモリは限られており、不必要にキャッシュしたくない場合があります。これは、古典的なキャッシングのトレードオフです。あなたの状況でもっと重要ですか?メモリパフォーマンスまたはCPUパフォーマンス(時間)。

私のテストもそうです。

私が行ったのは、さまざまな方法を使用してテーブルの行に表示される3つの単純なアイコンファイルを使用して単純なUITableViewアプリを作成することでした。Xcode内のアイコンの位置が異なりますプロジェクト構造。Xcodeに重点を置いていることに注意してください。元の質問に対する答えを理解するための鍵は、iOSアプリには3つのまったく異なるプロジェクトディレクトリ構造があることです。Xcodeナビゲーターに表示されるものと、Finderに表示される同じプロジェクトのファイルシステムに表示されるものがあります。 (Xcodeナビゲーターの任意の項目を右クリックし、[Finderに表示]を選択します)そして、めったに表示されないものとして、デプロイされたアプリの「バンドル」ディレクトリ構造。Finderでもこの最後のものを見ることができます-〜/ Library / Application Support / iPhone Simulatorでアプリを見つけ、.appディレクトリにドリルダウンします。すぐに私の写真をお見せします。

そのため、私のアプリでは、3つのアイコンpng画像ファイルすべてをさまざまな方法でXcodeにドラッグしました。

  1. icon1.png(時計)、ファイルとしてXcodeプロジェクトのルートにドラッグし、後でXcodeで新しいグループを作成し、そこにドラッグしました。このグループは、ファイルシステム内のどのディレクトリでも表されません。純粋なXcodeグループです。したがって、その名前は「JustGroup」です。

  2. icon2.png(目)、私はもともとファイルシステムを「RealDir」というディレクトリに置き、このディレクトリ全体をXcodeにドラッグし、求められたら「追加されたフォルダのグループを作成する」オプションを選択しました。これは、XcodeのRealDirグループがファイルシステム(私のプロジェクトディレクトリ内)のRealDirという実ディレクトリに接続されており、icon2.pngがそこにあることを意味します。

  3. icon3.png(ターゲット)も別のディレクトリにあり、Xcodeにドラッグしました。今回だけ、2番目のラジオオプション「追加されたフォルダのフォルダ参照を作成する」を選択しました。これにより、Xcodeにいわゆる「青」グループが作成されます。これについては後で詳しく説明します。このグループ(およびディレクトリ)を「FolderReference」と呼びました

Xcodeが提供する選択肢のショットを次に示します。 ディレクトリをドラッグするときのXcodeのダイアログ

Xcodeでの私のプロジェクト構造は次のようになります。 Xcodeナビゲータープロジェクトの構造

ここで、私のアプリでは、各アイコンをロードするために、UIImage imageNamed:とUIImageimageWithContentsOfFileの2つのメソッドを使用しました。テーブルに一連の行を作成しました。各セルのタイトルは、アイコンを含むグループの名前(JustGroup、RealDir、FolderReference)と、使用するメソッドの名前( imageNamed vs fromFile )です。 imageWithContentsOfFileの略語)

セルの詳細ラベル(タイトルの下の薄いテキスト)には、メソッドに付けたファイルまたはパスの名前が表示されます。

明確にするために、「fromFile」の場合、表示されている「相対」名にバンドルパスを追加しています。したがって、「fromFile」の場合、実際には次のコードを使用しています。

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

ここで、「filePath」は、テーブルセルの詳細ラベルに表示されるパスです。一方、imageNamed:の場合、セル詳細のfilePathは逐語的に渡されます。

そして、行の画像は、当然、ロードされる画像です。したがって、画像がないテーブルの行の場合、画像の読み込みに失敗しました。

ここに、一言で言えば、結果があります。この投稿を何も読んでいない場合は、少なくともこの画像を一目見れば、知る必要のあるすべてのことがわかります。

アプリはどのアイコンがロードされたかを示します

簡単に消化できるポイントの基本的な説明は次のとおりです。

  • 公式ドキュメントに記載されているように、imageNamed:メソッドはアプリケーションバンドルから画像をロードします。つまり、バンドルの場所を指定する必要はなく、ファイル名のみを指定する必要があります。それでも、ファイルのベース名だけです。ここでのドキュメントは少し薄いです。アプリケーションバンドルのルートディレクトリを基準にして、指定されたファイルパスからイメージをロードすることを明確にする必要があります。

  • (これがキッカーです。これに注意してください)バンドルディレクトリに関するルールは、デプロイされたアプリのバンドル内のルートディレクトリを参照します。探索に行く場合、それは「.app」ディレクトリ自体にあることを意味します。これは、XcodeナビゲーターのXcodeプロジェクトのルートディレクトリと同じではありません。また、ファインダーのXcodeプロジェクトのルートディレクトリと同じでありません。

  • これは、アプリをデバイス(またはシミュレーター)にデプロイするときに、「追加されたフォルダーのグループ」で表されるすべてのプロジェクトディレクトリがフラット化されるためです。。つまり、ディレクトリは無視され、そのすべての内容がバンドルのルートディレクトリに不用意にダンプされます。(異なるフォルダーに同じ名前のファイルがある場合、それらはここで衝突し、原因となる問題を解決する助けが得られないため、「不意に」と言います。)これは私の例のRealDirの場合です。デプロイされたアプリ、RealDirはもう存在せず、icon2.pngは一般の人々と混ざり合うために残されています(怖い)。言うまでもなく、純粋に論理的なXcodeグループである「JustGroup」も無視されます。これは実際のディレクトリではなく、Xcodeユーザーの視覚的な補助にすぎません。icon1.pngもバンドルルートにあります。

    • これが、imageNamed:がicon2をロードできた理由です。

    • また、imageWithContentsOfFileが「RealDir / image2.png」でそれを見つけることができなかった理由:デプロイされたアプリにRealDirディレクトリがないため。

  • 一方、「青いフォルダー」、つまり「追加されたフォルダーのフォルダー参照」で表されるディレクトリは実際にはアプリバンドルのディレクトリ構造に保持されます。これは、明らかに青いフォルダのポイントです。これらは、デプロイされたアプリでディレクトリ構造を作成する方法を提供します。これの元の存在理由はわかりませんが、1つの良いユースケースは、同じ名前のリソースファイルの代替バージョンを含む複数のディレクトリがあり、アプリが実行時にそれらを切り替えることができるようにする場合です。ディレクトリを変更する。とにかく、FolderReferenceのicon3.pngは、デプロイされたアプリのFolderReferenceディレクトリに残りました。

    • これが、imageNamed:が「icon3」では検出できなかったが、「FolderReference/icon3」では検出できた理由です。
    • imageWithContentsOfFileは、FolderReferenceを使用してそれを見つけることができましたが、アタッチされている場合にのみ、上記のコードを使用して完全なバンドルパスを覚えておいてください。(ここでの主な違い:この場合、imageNamedは相対パスで機能し、imageWithContentsOfFileは常に絶対パスで機能します)。

明確にするために、ここに私のフォルダ構造があります:

上記のXcodeプロジェクトナビゲーター構造を見ましたが、その下のファイルシステムディレクトリは次のとおりです。 FinderXcodeプロジェクトのディレクトリ構造

そして最後に、おそらく最も重要なのは、デプロイされたバンドルファイルシステムのディレクトリ構造です。 デプロイされたバンドルディレクトリ構造

注:これはMacのこの場所で見つかりました。同様の場所にあります。少し検索して、アプリが含まれている醜いGUID名のサブディレクトリを見つける必要がある場合があります。

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

これがお役に立てば幸いです。テストし、探索し、そして最後に、それを説明することは確かに私を助けました。

于 2012-10-17T10:43:15.423 に答える
5

ドキュメントには、「メソッドはアプリケーションのメインバンドルで指定された名前の画像を検索する」と書かれているので、いつでも名前だけを使用できると思います。唯一の例外は、サブフォルダ内に保存されている画像である可能性があります。特に、とがある場合はそうfoo/image.pngですbar/image.png。うまくいくかどうかはわかりませんが[UIImage imageNamed:@"foo/image"]、試してみるのは簡単です。

(これらの場合、少し混乱するのは、Xcodeツリーのグループが、結果のアプリバンドルのフォルダーに対応していないことです。通常の代わりに青いフォルダー参照を使用しない限り、それらのコンテンツはバンドルのルートにまとめられます。グループ。)

于 2012-04-30T08:54:20.703 に答える
0

新しいXcodeプロジェクト(シングルビュー、AppDelelgate、ViewControllerクラス、ストーリーボードなど)を作成しました。画像グループを作成しました。Paintbrushを使用して16x16pngファイルWall1.pngを作成し、XcodeのImagesグループにドロップしました(Xcodeにファイルをコピーさせます)。

ViewControllerのviewDidLoadメソッドに次のコードを追加しました。

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

携帯電話でアプリを実行すると、画像が表示されません

[self.view addSubview:imageView]にブレークポイントを追加しました。

画像がnullでした

ターミナルを開き、ディレクトリを私のプロジェクトに変更しました。Wall1.pngはグループフォルダImagesではありませんでした。プロジェクトからpngを削除し、Imagesフォルダーを作成し、Wall1.pngをフォルダーに移動しました。既存のファイルWall1.pngをグループImagesに追加しました。

アプリを実行しても、画像が表示されません。

画像がnullでした

Images/Wall1をWall1に変更しました

アプリを実行すると、ブーム画像が表示されます1

画像のグループを作成する場合、Xcodeはそれぞれのディレクトリを作成しません。必要に応じて手動で作成します(画像を別のフォルダーに保存することをお勧めします)。UIImage imageWithContentsOfFileを使用する場合は、画像ファイルへのフルパスを指定しないでください。

于 2015-01-30T14:49:15.513 に答える
-1

これを試して。

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

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

于 2012-04-30T09:13:54.770 に答える