CocoaPodsを利用したPrivate Static Libraryの作り方(和訳&ちょっと意訳)

引用サイト: <a href="url">http://blog.sigmapoint.pl/developing-static-library-for-ios-with-cocoapods/</a>

著者:Kamil Burczyk

*  project生成でCocoa Touch Static Libraryを選択します。project名は`NetworkLib`とします。

	![image01.png](https://qiita-image-store.s3.amazonaws.com/0/49796/ac48664f-dc72-a62c-df91-7795045ac87a.png)

*  `pod init` でPodfileを作成します。
*  Podfileを以下のように編集します。

```  
platform :ios, "7.0"  
target "NetworkLib" do  
pod 'AFNetworking'  
end  
target "NetworkLibTests" do  
end  
```

* `pod install` すると以下の様にPodsフォルダが作成されます。

![image02.png](https://qiita-image-store.s3.amazonaws.com/0/49796/70ff34f9-70fb-b40b-39b7-0cccb6068491.png)

* アプリケーション内でCocoapodsに依存したprojectを使用するには`podspec`ファイルを持つ必要があり、以下の様に作成します。podspecがよくわからないという方はこちらを参照してください。(英語)[Cocoapods: Creating a Pod Spec](http://www.theonlylars.com/blog/2013/01/20/cocoapods-creating-a-pod-spec/)  


`pod spec create NetworkLib`


簡単に説明すると、作成したライブラリないしコンポーネントの対応プラットフォームやARC対応の有無、依存するフレームワークなどを記述したファイルです。


* `NetworkLib.podspec`を以下の様に編集

```  
Pod::Spec.new do |s|  
  s.name         = "NetworkLib"
  s.version      = "0.0.1"
  s.summary      = "A short description of NetworkLib."

  s.description  = <<-DESC
                   A longer description of NetworkLib in Markdown format.
                   DESC

  s.homepage     = "http://EXAMPLE/NetworkLib"
  s.license      = 'MIT (example)'
  s.author       = { "Kamil Burczyk" => "kamil.burczyk@sigmapoint.pl" }
  s.platform     = :ios, '7.0'
  s.source_files  = 'NetworkLib', 'NetworkLib/**/*.{h,m}'
  s.public_header_files = 'NetworkLib/**/*.h'
  s.resources    = "NetworkLib/*.png"
  s.framework    = 'SystemConfiguration'
  s.requires_arc = true

  s.dependency 'AFNetworking'

end  

```

すべてを上記の様に記述する必要はありませんが、`s.source_files`,`s.public_header_files`,`s.resources`は自身のprojectパスにマッチする必要があり、`s.framework`には依存するframeworkをかく必要があります。例えば、`SystemConfiguration.framework`に依存するのであれば、上記のように記述します。そして最後にPodfileのdependenciesを

```  
s.dependency 'AFNetworking'

```

のように記述します。`s.source`は今回はプライベートライブラリであり、外部に公開しないので削除します。

* では何か書いてみましょう。
任意のユーザーのgithubリポジトリに関するすべての情報を取得する関数を書いてみましょう。使用するAPIは`https://api.github.com/users/<username>/repos`です。

`NetworkLib.h`:

```
#import <Foundation/Foundation.h>

#import "AFNetworking.h"

@interface NetworkLib : NSObject

- (void)getGithubReposForUser:(NSString*)user withSuccess:(void (^)(id responseObject))success failure:(void (^)(NSError *error))failure;

@end
```

`NetworkLib.m`:

```
#import "NetworkLib.h"

@implementation NetworkLib

- (void)getGithubReposForUser:(NSString*)user withSuccess:(void (^)(id responseObject))success failure:(void (^)(NSError *error))failure
{
    AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
    [manager GET:[NSString stringWithFormat:@"https://api.github.com/users/%@/repos", user] parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
        success(responseObject);
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        failure(error);
    }];
}

@end

```

テストコードを書いてみましょう。

```
#import <XCTest/XCTest.h>
#import "NetworkLib.h"

@interface NetworkLibTests : XCTestCase

@end

@implementation NetworkLibTests

- (void)testGetReposForBurczyk
{
    NetworkLib *nl = [[NetworkLib alloc] init];
    XCTAssertNotNil(nl, @"");
}

@end
```

ここで`Cmd+U`とコマンドを打つと、`NetworkLib.h`に以下のエラーが表示されるはずです。

![image03.png](https://qiita-image-store.s3.amazonaws.com/0/49796/fcec3b24-ca5c-2691-2e0c-6b14ec8062be.png)


これは標準的な挙動であり、CocoaPodsライブラリがtestフェーズにリンクされていないデフォルトの設定であるためです。直していきましょう。  
青いprojectアイコンをクリックして、`Configurations`セクションの`Based Configuration File`欄で`Pods-NetworkLib`を選択してください。

![image04.png](https://qiita-image-store.s3.amazonaws.com/0/49796/05abee8b-5afd-741c-a1a0-abf1058215a0.png)

これでtestができるはずです。今回は非同期関数(asynchronous method)なので、結果が出るまで待つために、ちょっとした細工をします。そうしないと結果を得る前にtestが終了してしまいます。`@Holtwick`さんの[stackoverflow](http://stackoverflow.com/questions/2162213/how-to-unit-test-asynchronous-apis)を利用しました。

包括的なテストコードは以下の様になります:

```
#import <XCTest/XCTest.h>
#import "NetworkLib.h"

@interface NetworkLibTests : XCTestCase

@end

@implementation NetworkLibTests

- (void)testGetReposForBurczyk
{
    __block id JSON;

    hxRunInMainLoop(^(BOOL *done) {
        NetworkLib *nl = [[NetworkLib alloc] init];
        [nl getGithubReposForUser:@"burczyk" withSuccess:^(id responseObject) {
            NSLog(@"Response: %@", responseObject);
            JSON = responseObject;
            *done = YES;
        } failure:^(NSError *error) {
            *done = YES;
        }];
    });

    XCTAssertNotNil(JSON, @"");
}

- (void)testGetRepoForNotExistingUser
{
    __block id JSON;

    hxRunInMainLoop(^(BOOL *done) {
        NetworkLib *nl = [[NetworkLib alloc] init];
        [nl getGithubReposForUser:@"burczyk1234567890" withSuccess:^(id responseObject) {
            NSLog(@"Response: %@", responseObject);
            JSON = responseObject;
            *done = YES;
        } failure:^(NSError *error) {
            *done = YES;
        }];
    });

    XCTAssertNil(JSON, @"");
}

// Wrapper to test async methods: http://stackoverflow.com/questions/2162213/how-to-unit-test-asynchronous-apis
static inline void hxRunInMainLoop(void(^block)(BOOL *done)) {  
    __block BOOL done = NO;
    block(&done);
    while (!done) {
        [[NSRunLoop mainRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow:.1]];
    }
}

@end
```

成功する場合と失敗する場合を記述してあります。

では実際のappで使ってみましょう。

* 新しいiOS appを作り、名前を`ReposBrowser`として、作成したライブラリと同じ階層に置きます。

```
MacBook Pro:Projects kamil$ ls  
NetworkLib    ReposBrowser  
```

* 作ったproject(ReposBrowser)内で`pod init`を走らせ、`Podfile`を作成し、編集します。
ローカルにあるライブラリ(NetworkLib)との依存関係を追加するために以下のようにコードを書き加えます。

```
pod 'NetworkLib', :path => '../NetworkLib'
```

全体では以下の様になります。

`Podfile`:

```
# Uncomment this line to define a global platform for your project
# platform :ios, "7.0"

target "ReposBrowser" do
pod 'NetworkLib', :path => '../NetworkLib'
end

target "ReposBrowserTests" do

end

```

もし`NetworkLib.podspec`が正しく記述されているようでしたら、`pod install`で以下のような結果が得られるはずです。

```
MacBook Pro:ReposBrowser kamil$ pod install  
Analyzing dependencies  
Fetching podspec for `NetworkLib` from `../NetworkLib`  
Downloading dependencies  
Installing AFNetworking (2.1.0)  
Installing NetworkLib (0.0.1)  
Generating Pods project  
Integrating client project  
[!] From now on use `ReposBrowser.xcworkspace`.
MacBook Pro:ReposBrowser kamil$  
```


そしてXcodeのPodsプロジェクトブラウザには`NetworkLib`を持つ`Development Pods`が中に入っているはずです。  

![image05.png](https://qiita-image-store.s3.amazonaws.com/0/49796/16aa0d89-0168-1525-facb-5f577a8d444a.png)


* 以下の様にして作成したライブラリの関数を使ってみましょう。

```
#import "ViewController.h"
#import "NetworkLib.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self testLib];
}

- (void)testLib
{
    NetworkLib *nl = [[NetworkLib alloc] init];
    [nl getGithubReposForUser:@"burczyk" withSuccess:^(id responseObject) {
        NSLog(@"%@",responseObject);
    } failure:^(NSError *error) {
        NSLog(@"%@",error);
    }];
}

@end

```

問題が無ければ動きます。