めっきりiPhoneアプリ構築中です。
Twitterクライアントをいくつか作ってみたいので、API呼び出しなどの共通部分をライブラリとして外出ししようとした時のメモ書きです。
参考にしたのは以下のサイトです。
Twitterクライアントをいくつか作ってみたいので、API呼び出しなどの共通部分をライブラリとして外出ししようとした時のメモ書きです。
参考にしたのは以下のサイトです。
- iPhone/ライブラリ作成 - syati-project.jp
- staticライブラリにカテゴリを含む際に気をつけること - 風日記
- Xcodeでアプリのプロジェクトにライブラリのプロジェクトを追加したりね。 - このブログは証明できない。
プロジェクトの作成
Xcodeより、新規プロジェクトで「Cocoa Touch Static Library」テンプレートよりプロジェクトを作成します。「グループとファイル」内、「Classes」に実装ファイルを入れていきますが、実ファイル階層はフラットになっているので、必要に応じてFinderなりで階層を作ってグループの情報からパスを設定する必要があります。
ユニットテスト
Xcodeでは、「SenTestingKit.framework」というユニットテストのフレームワークがあります。ターゲットを追加
「グループとファイル」の「ターゲット」を右クリック、「追加」→「新規ターゲット」を選ぶと新規ターゲットダイアログが表示されるので、「Cocoa Touch」→「Unit Test Bundle」を選択し、適当な名前を付けて保存します。Xcode-3.2.4 ではそのままではテスト実行時にエラーになるので、追加したターゲット内「スクリプトを実行」の「情報を見る」とテスト実行スクリプトが表示されるので、これを修正します。
# Run the unit tests in this test bundle.
"${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests"
↓
# Run the unit tests in this test bundle.
"${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests" 1> /tmp/RunUnitTests.out
フレームワークの追加
「グループとファイル」から、「Frameworks」を右クリック、「追加」→「既存のフレームワーク...」を選んで表示されるダイアログの左下にある「その他を追加...」をクリックするとファイル選択ダイアログが開くので、/Developer/Library/Frameworks
にある SenTestingKit.framework を(フォルダごと)選択して追加します。
テスト実装
テスト用のグループを「TestClasses」として準備しておきます。(グループ名はなんでもいいです。)グループを右クリック、「追加」→「新規ファイル」から、「Cocoa Touch Class」内の「Objective-C test case class」を選択し、適当な名前をつけて保存します。
ただし、ファイル名を入力するダイアログにある「ターゲット」で、テスト用のターゲットのみを選択するようにします。
また、ヘッダファイルは作成せずに、mファイルに同居させてしまったほうが管理が楽になります。
テストコードを実装します。
例) HelloTest.m
#import <SenTestingKit/SenTestingKit.h>
#import "Hello.h"
@interface HelloTest : SenTestCase {
Hello *hello;
}
@end
@implementation HelloTest
- (void)setUp {
hello = [[Hello alloc] init];
}
- (void)testHello {
STAssertEqualObjects([hello sayHello:@"ueshin"], @"Hello, ueshin", @"sayHello:@\"ueshin\" must be @\"Hello, ueshin\".");
}
- (void)tearDown {
[hello release];
}
@end
アクティブターゲットをテストターゲットに変更してビルドすると、、、エラーになります。
まぁ、テスト対象の実装がありませんので。。。
実装
というわけで実装します。「Classes」グループを右クリック、「追加」→「新規ファイル」から、「Cocoa Touch Class」内の「Objective-C class」を選択し、適当な名前をつけて保存します。
ここで、ターゲットは実際のターゲットとテスト用ターゲットの両方共チェックをつけておきます。
例) Hello.h
#import <Foundation/Foundation.h>
@interface Hello : NSObject {
}
- (NSString*)sayHello:(NSString*)name;
@end
例) Hello.m
#import "Hello.h"
@implementation Hello
- (NSString*)sayHello:(NSString *)name {
return [NSString stringWithFormat:@"Hello, %@", name];
}
@end
さて、ビルドしてみると、無事に「問題なく完了しました」。
ターゲットを元に戻してビルドすると、オブジェクトファイルが出来ます。
注意:カテゴリについて
Objective-Cでは、カテゴリという機能を使って実装ファイルを分割したり、既存のクラスに機能を追加したりすることができますが、最終的に実行ファイルをビルドする際に、リンカのバグによってカテゴリを実装したファイルがリンクされません。これを防ぐために、カテゴリを実装する.mファイルに、ダミーの実装を付けておけばいいようです。
例) Hello+Sample.m
#import "Hello+Sample.h"
@interface FIXCATEGORYBUG_HELLO_SAMPLE @end
@implementation FIXCATEGORYBUG_HELLO_SAMPLE @end
@implementation Hello (Sample)
・・・
@end
FIXCATEGORYBUG_HELLO_SAMPLE
の部分は他と被らない名前をつけておきます。ライブラリの組み込み
ライブラリを組み込むプロジェクトを作成します。プロジェクトに、Finderからライブラリプロジェクトの .xcodeproj ファイルをドラッグ&ドロップすると、ライブラリの成果物である libXxx.a が表示されるようになります。
表示された libXxx.a をさらにドラッグして、ビルドターゲットの「バイナリをライブラリにリンク」にドロップします。
ユーザーヘッダ検索パス
プロジェクトの「情報を見る」→「ビルド」タブ内の「ユーザー検索パス」に、ヘッダの位置を指定します。組み込むプロジェクトからの相対パスで指定する場合には、
${SRCROOT}/../path/to/header
のように指定すればいいです。
その他のリンカフラグ
ライブラリ側でカテゴリなどを使っていると、リンカフラグを設定しないといけないようです。プロジェクトの「情報を見る」→「ビルド」タブ内の「その他のリンカフラグ」に、
-ObjC
と指定します。