Embedded Frameworkの導入方法

# 概要
Embedded Frameworkの導入方法やはまったところについてまとめました

# Embedded Frameworkとは？
Embedded FrameworkはiOS 8・Xcode 6から追加された機能です。
アプリのコードを分割してFrameworkとして扱うことができます。

## Embedded Frameworkを導入することのメリット
コードを分割してFramework化することで以下のメリットがあります。

* コードのターゲットが分かれるため、差分コンパイルされビルドパフォーマンスが向上する
* App Extentionsを持つアプリの場合、メインターゲットとExtension間でコード共有することができる
* Frameworkに分けることで、依存関係がシンプルになる
* Frameworkごとにテストを書くことができる

# 導入方法
Xcode 7.3.2 Swift 2.2での導入方法です。

## Frameworkの作り方
Embedded Frameworkの導入は簡単で、Xcodeのツールバーから｢File｣ → ｢New｣ → ｢Target｣を選択すると、以下の画面が表示されます。


<img width="424" alt="スクリーンショット 2016-09-15 14.54.40.png" src="https://qiita-image-store.s3.amazonaws.com/0/69901/153f45e0-7e79-e5ea-13ce-62a4f218ec59.png">


そこから｢Framework & Library｣ → ｢Cocoa Touch Framework｣を選択すると新しくターゲットが追加されます。

<img width="1136" alt="d0337ade-fffd-1c29-27e5-1cd780a893c9.png" src="https://qiita-image-store.s3.amazonaws.com/0/69901/92562563-10b0-ec7a-625d-ae195e3ff249.png">



新しくできたTargetに分けたいコードを追加していきます。

## Frameworkの使い方
Frameworkとして扱うメソッドやclass、変数にはメインターゲットからアクセスできるように `public` 修飾子をつけてください。

``` swift
import Foundation
import Alamofire

public class Util {

    public var name: String?

    public init() {

    }
}
```

使用したいFrameworkをimportするだけで使えるようになります。

``` swift
import UIKit
import SampleFramework

class ViewController: UIViewController {
  
    override func viewDidLoad() {
        super.viewDidLoad()
        let util = Util()
        util.name = "hoge"
    }
}
```

Embedded Frameworkの導入はすごく簡単です。
しかし、Framework内でライブラリを使う場合はいろいろとハマる部分がありました。
その対応方法をいくつか紹介したいと思います。

## CocoaPodsでライブラリを使う場合
Embedded Frameworkだけでしか利用していないライブラリでも、メインターゲットにもインストールする必要があります。
Podfileにターゲットごとに同じライブラリ名を記述するのは手間なので、iQONでは`abstract_target`でまとめています。

``` ruby
// Podfile

abstract_target 'All' do # Targetとかぶらなければ、名前の文字列は何でも大丈夫です

  pod 'Alamofire'

  target 'SampleApp' do # AlamofireとSVProgressHUDがインストールされる
    pod 'SVProgressHUD'
  end

  target 'SampleFramework' do # Alamofireがインストールされる
  end
end
```

## Carthageでライブラリを使う場合
CarthageもCocoaPodsと同様にFrameworkとメインターゲットどちらにも、ライブラリを設定する必要があります。
メインターゲットの`Embedded Binaries`にFrameworkで利用しているライブラリを設定します。

<img width="879" alt="e73231a2-4962-be61-d4c4-2f184cf57a0c.png" src="https://qiita-image-store.s3.amazonaws.com/0/69901/51a02438-5701-d045-b462-65f21d604717.png">





## `Library not loaded`でクラッシュする場合
CocoaPodsでインストールしたライブラリが`Library not loaded`でクラッシュしてしまう時は｢Build Phases｣を確認してみてください。

おそらく、インストールしたライブラリをアプリ内に組み込むための Run Script が存在していないためにクラッシュしている可能性があります。
`[CP] Embed Pods Frameworks` という名前の Run Script は本来CocoaPodsが自動的に追加するもので、なぜそのRun Scriptが存在しないのかは詳しくは分かりませんが、追加すればクラッシュしなくなります。

<img width="875" alt="スクリーンショット_2016-09-15_12_19_42.png" src="https://vasily.qiita.com/files/0612f4db-217c-3914-3f55-676b72ea71cf.png">


## `Framework not found Pods_**`でビルドが通らない場合
[Build Phases] -> [Link Binary With Libraries]を確認してみてください。
エラーで表示されているFrameworkを削除してください。
以前からCocoaPodsでライブラリを管理しているプロジェクトだと、`Pod_**.framework`というものが`Link Binary With Libraries`に設定されています。
しかし、Podfileを`abstract_target`で書くようにした場合、新しく`Pods-**-**.framework`というものが設定されるので、`Pod_**.framework`が不要になります。
不要なものが設定されているために、ビルドに失敗していました。

<img width="816" alt="スクリーンショット 2016-09-15 12.47.16.png" src="https://qiita-image-store.s3.amazonaws.com/0/69901/3885dd6c-9824-b012-736b-0210fcfd4e7c.png">

# まとめ
Embedded Frameworkの導入は一部のハマりどころさえ超えれば、とても便利なのでおすすめです！