web-dev-qa-db-ja.com

静的ライブラリのObjective-Cカテゴリ

静的ライブラリをiPhoneプロジェクトに適切にリンクする方法を教えてください。アプリプロジェクトに追加された静的ライブラリプロジェクトを直接依存関係(ターゲット->一般->直接依存関係)として使用し、すべて正常に動作しますが、カテゴリです。静的ライブラリで定義されたカテゴリがアプリで機能していません。

だから私の質問は、いくつかのカテゴリを持つ静的ライブラリを他のプロジェクトに追加する方法ですか?

そして一般的に、他のプロジェクトのアプリプロジェクトコードで使用するベストプラクティスは何ですか?

148
Vladimir

解決策:Xcode 4.2以降では、ライブラリ(ライブラリ自体ではなく)にリンクしているアプリケーションに移動し、 Project Navigatorでアプリのターゲットをクリックし、設定をビルドしてから、「その他のリンカーフラグ」を検索し、+ボタンをクリックして、「-ObjC」を追加します。 「-all_load」と「-force_load」は不要になりました。

詳細:さまざまなフォーラム、ブログ、およびApple docs。でいくつかの答えを見つけました。検索と実験。

問題は(Apple Technical Q&A QA1490 https://developer.Apple.com/library/content/qa/qa1490/_index.html )からの引用により引き起こされました:

Objective-Cは、各関数(またはObjective-Cのメソッド)のリンカーシンボルを定義しません-代わりに、リンカーシンボルはクラスごとにのみ生成されます。既存のクラスをカテゴリで拡張する場合、リンカーはコアクラス実装のオブジェクトコードとカテゴリ実装を関連付けることを知りません。これにより、結果のアプリケーションで作成されたオブジェクトが、カテゴリで定義されているセレクターに応答するのを防ぎます。

そしてその解決策:

この問題を解決するには、静的ライブラリが-ObjCオプションをリンカーに渡す必要があります。このフラグにより​​、リンカは、Objective-Cクラスまたはカテゴリを定義するライブラリ内のすべてのオブジェクトファイルをロードします。このオプションは、通常、アプリケーションに追加のオブジェクトコードがロードされるため、実行可能ファイルが大きくなりますが、既存のクラスのカテゴリを含む効果的なObjective-C静的ライブラリを正常に作成できます。

また、iPhone開発FAQにも推奨事項があります。

静的ライブラリ内のすべてのObjective-Cクラスをリンクするにはどうすればよいですか? Other Linker Flags build設定を-ObjCに設定します。

およびフラグの説明:

-all_load静的アーカイブライブラリのすべてのメンバーをロードします。

-ObjCObjective-Cクラスまたはカテゴリを実装する静的アーカイブライブラリのすべてのメンバーをロードします。

-force_load(path_to_archive)指定された静的アーカイブライブラリのすべてのメンバーをロードします。注:-all_loadは、すべてのアーカイブのすべてのメンバーを強制的にロードします。このオプションを使用すると、特定のアーカイブをターゲットにできます。

* force_loadを使用してアプリのバイナリサイズを削減し、all_loadが場合によっては発生する可能性のある競合を回避できます。

はい、プロジェクトに追加された* .aファイルで動作します。しかし、直接依存関係として追加されたlibプロジェクトで問題が発生しました。しかし、後でそれが私のせいであることがわかりました-直接依存プロジェクトが適切に追加されなかった可能性があります。私がそれを削除し、手順で再度追加すると:

  1. Libプロジェクトファイルをアプリプロジェクトにドラッグアンドドロップします(またはProject-> Add to project…で追加します)。
  2. Libプロジェクトアイコン-mylib.aファイル名の矢印をクリックし、このmylib.aファイルをドラッグして、[ターゲット]-> [バイナリをライブラリとリンク]グループにドロップします。
  3. 最初のページ(一般)でターゲット情報を開き、libを依存関係リストに追加します

その後はすべて正常に動作します。私の場合、「-ObjC」フラグで十分でした。

http://iphonedevelopmentexperiences.blogspot.com/2010/03/categories-in-static-library.html blogからのアイデアにも興味がありました。著者は、-all_loadまたは-ObjCフラグを設定せずにlibのカテゴリを使用できると言います。彼はカテゴリh/mファイルに空のダミークラスインターフェイス/実装を追加して、リンカがこのファイルを使用するようにします。そして、はい、このトリックは仕事をします。

しかし、著者は、ダミーオブジェクトのインスタンス化さえしていないとも述べました。 Mm…私が見つけたように、カテゴリファイルからいくつかの「実際の」コードを明示的に呼び出す必要があります。したがって、少なくともクラス関数を呼び出す必要があります。また、ダミークラスも必要ありません。単一のc関数も同じことを行います。

したがって、libファイルを次のように記述した場合:

// mylib.h
void useMyLib();

@interface NSObject (Logger)
-(void)logSelf;
@end


// mylib.m
void useMyLib(){
    NSLog(@"do nothing, just for make mylib linked");
}


@implementation NSObject (Logger)
-(void)logSelf{
    NSLog(@"self is:%@", [self description]);
}
@end

そしてuseMyLib()を呼び出すと; Appプロジェクトの任意の場所で、任意のクラスでlogSelfカテゴリメソッドを使用できます。

[self logSelf];

テーマに関するその他のブログ:

http://t-machine.org/index.php/2009/10/13/how-to-make-an-iphone-static-library-part-1/

http://blog.costan.us/2009/12/fat-iphone-static-libraries-device-and.html

224
Vladimir

この問題は LLVMで修正済み です。修正はLLVM 2.9の一部として出荷されます。修正を含む最初のXcodeバージョンは、LLVM 3.0とともに出荷されるXcode 4.2です。 XCode 4.2-all_loadを使用する場合、-force_loadまたは-ObjCの使用は不要になりました。

24
tonklon

静的ライブラリをコンパイルするときにこの問題を完全に解決するために必要なことは次のとおりです。

Xcode Build Settingsに移動し、Perform Single-Object PrelinkをYESまたはGENERATE_MASTER_OBJECT_FILE = YESビルド構成ファイル。

デフォルトでは、リンカーは.mファイルごとに.oファイルを生成します。したがって、カテゴリは異なる.oファイルを取得します。リンカが静的ライブラリの.oファイルを参照するとき、クラスごとにすべてのシンボルのインデックスは作成されません(ランタイムは何でも構いません)。

このディレクティブは、すべてのオブジェクトを1つの大きな.oファイルにパックするようリンカーに要求します。これにより、静的ライブラリを処理するリンカーにすべてのクラスカテゴリのインデックスを取得させます。

それを明確にすることを願っています。

16
amosel