iOS開発で導入しているライブラリの一言説明

あるプロジェクトで導入しているライブラリを簡単に説明を添えてくれと頼まれたので その内容をQiitaにも投稿します。

# iOSプロジェクトで導入しているライブラリの説明

実際にプロジェクトで使っているコードを一部抜粋して載せます。

※ 長くなってしまうので必要最低限の記述とし、Import等は省きます。
※ `App.XX`というのは自前で定義しているstructなのでスルーしてください。

### APIKit

[ishkawa/APIKit: Type-safe networking abstraction layer that associates request type with response type.](https://github.com/ishkawa/APIKit)

APIリクエストをする際に使用するネットワークライブラリです。
JSON デコーダのHimotokiと合わせて使っています。

> 例：お知らせ情報を取得

```swift

import APIKit
import Himotoki

struct InformationEntity {
    let id: Int
    let publishedAt: String
    let title: String
    let content: String
    let images: [ImageEntity]

    init(id: Int, publishedAt: String, title: String, content: String, images: [ImageEntity]) {
        self.id = id
        self.publishedAt = publishedAt
        self.title = title
        self.content = content
        self.images = images
    }
}

extension InformationEntity: Decodable {
    static let URLTransformer = Transformer<String, NSURL> { URLString throws -> NSURL in
        if let URL = NSURL(string: URLString) {
            return URL
        }
        throw customError("Invalid URL string: \(URLString)")
    }

    static func decode(_ e: Extractor) throws -> InformationEntity {
        return try InformationEntity(
            id:             e <| "id",
            publishedAt:    e <| "published_at",
            title:          e <| "title",
            content:        e <| "content",
            images:         e <|| "images"
        )
    }
}

struct InformationItemsRequest: Request {
    typealias Response = [InformationEntity]

    let number: Int

    var baseURL: URL {
        return URL(string: "http://xxxxxxx.com")!
    }

    var method: HTTPMethod {
        return .get
    }

    var parameters: Any? {
        return [
            "page": number
        ]
    }

    var path: String {
        return "/informations"
    }

    func response(from object: Any, urlResponse: HTTPURLResponse) throws -> Response {
        return try decodeArray(object, rootKeyPath: ["informations"])
    }
}
```

実際にリクエストを送る。

```swift

let informationsReqest = InformationItemsRequest(number: number)
Session.send(informationsReqest) { result in
    switch result {
    case .success(let response):
        closure(response)
    case .failure(let error):
        print(error)
    }
}
```


### Himotoki

[ikesyo/Himotoki: A type-safe JSON decoding library purely written in Swift](https://github.com/ikesyo/Himotoki)

JSONをデコードするライブラリです。
主にAPIKitで受け取ったJSONをデコードしてオブジェクトとして扱えるようにします。

以下の `e <| "id”` 部分。

```swift

static func decode(_ e: Extractor) throws -> InformationEntity {
        return try InformationEntity(
            id:             e <| "id",
            publishedAt:    e <| "published_at",
            title:          e <| "title",
            content:        e <| "content",
            images:         e <|| "images"
        )
    }
}

```


### Result

[antitypical/Result: Swift type modelling the success/failure of arbitrary operations.](https://github.com/antitypical/Result)

成功・エラーをResult型として返すライブラリです。
以下の様にSwitch文で判断し処理を振り分けます。

```swift
let informationsReqest = InformationItemsRequest(number: number)
Session.send(informationsReqest) { result in
    switch result {
    case .success(let response):
        closure(response)
    case .failure(let error):
        print(error)
    }
}
```


### Kingfisher

[onevcat/Kingfisher: A lightweight, pure-Swift library for downloading and caching images from the web.](https://github.com/onevcat/Kingfisher)

画像のダウンロード・キャッシュを行うライブラリです。
例えば、以下のようにURLを渡すと画像を取得してImageViewに表示します。

```swift
@IBOutlet weak var targetImageView: UIImageView!
...

guard let imageUrl = model.imageUrl else { return }
targetImageView.kf.setImage(with: URL(string: imageUrl))

```


### SwiftyJSON

[SwiftyJSON/SwiftyJSON: The better way to deal with JSON data in Swift](https://github.com/SwiftyJSON/SwiftyJSON)

JSONを簡単に扱うためのライブラリです。
PUSH通知のPayloadをデコードするのに使っています。
参考：[iOSのPUSH通知(APNS)の特徴・ノウハウまとめ(iOS 9まで対応) - Qiita] (http://qiita.com/mono0926/items/df03c61adc56934e2e7a#%E9%80%9A%E7%9F%A5%E3%83%9A%E3%82%A4%E3%83%AD%E3%83%BC%E3%83%89%E3%82%92struct%E3%81%A7%E3%83%A9%E3%83%83%E3%83%97%E3%81%97%E3%81%A6%E6%89%B1%E3%81%86%E3%81%A8%E4%BE%BF%E5%88%A9)　:pray:  

（Himotokiと被っているのでコードを書き換えて1つにするべきかも）

```swift 
import SwiftyJSON

struct NotificationPayload {
    let json: JSON
    fileprivate var aps: JSON { return json["aps"] }
    var alert: String? { return aps["alert"].string }
    var badge: Int? { return aps["badge"].int }
    var sound: String? { return aps["sound"].string }
    var contentAvailable: Int? { return aps["content-available"].int }
    var notificationId: Int? { return aps["notification_id"].int }

    fileprivate var body: JSON { return json["body"] }
    var category: String? { return body["category"].string }

    init(userInfo: [AnyHashable: Any]) {
        json = JSON(userInfo)
    }
}
```


### SwiftyUserDefaults

[radex/SwiftyUserDefaults: Modern Swift API for NSUserDefaults](https://github.com/radex/SwiftyUserDefaults)

UserDefaultsを扱いやすくするライブラリです。
Keyを予め設定することで文字列ではなく、Value Typeで扱うことができます。

Keyを定義

```swift
import SwiftyUserDefaults

extension DefaultsKeys {
    static let deviceToken = DefaultsKey<String?>("deviceToken")
    static let accessToken = DefaultsKey<String?>("accessToken")
    static let firstLaunchAt = DefaultsKey<Date?>("firstLaunchAt")
}
```

更新・取得

```swift 
let deviceToken = deviceToken.map { String(format: "%.2hhx", $0) }.joined()
Defaults[.deviceToken] = deviceToken
...

let deviceToken = Defaults[.deviceToken]
```


### Fabric、Crashlytics

Fabric上でデータを取得したり、配布を行うためのSDKです。

コード自体はAppDelegateに以下を記述するだけです。

```AppDelegate.swift
...

Fabric.with([Crashlytics.self])
Crashlytics.sharedInstance().setUserIdentifier(Defaults[.accessToken])
```


### GoogleMaps

GoogleMapsのSDKです。
ちなみにGoogleMapsのマーカーからGoogleMapsアプリに飛ばす処理を書いたら、
審査の際に純正のMapを使えとリジェクトされました。

```swift

@IBOutlet weak var mapView: UIView!
...

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    setupMap() /// AutoLayoutが設定されてからセットしたいのでviewDidLayoutSubviewsで呼んでます
}

fileprivate func setupMap() {
    let googleMap = GMSMapView(frame: CGRect(x: 0, y: 0, width: mapView.bounds.width, height: mapView.bounds.height))
    let camera = GMSCameraPosition.camera(withLatitude: latitude, longitude: longitude, zoom: zoom)
    googleMap.camera = camera

    let marker = GMSMarker()
    marker.position = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
    marker.map = googleMap
    marker.icon = UIImage(named: "MarkerIcon")
    mapView.addSubview(googleMap)
}
```


### DZNEmptyDataSet

[dzenbot/DZNEmptyDataSet: A drop-in UITableView/UICollectionView superclass category for showing empty datasets whenever the view has no content to display](https://github.com/dzenbot/DZNEmptyDataSet)

UITableVIewやUICollectionViewでコンテンツが空だった場合に、簡単に画像やボタン等を配置するためのライブラリです。（Objective-C）

```swift

func viewDidLoad() {
	  tableView.emptyDataSetSource = self
	  tableView.emptyDataSetDelegate = self
}

...

// MARK: - DZNEmptyDataSetSource, DZNEmptyDataSetDelegate
extension CouponViewController: DZNEmptyDataSetSource, DZNEmptyDataSetDelegate {
    func title(forEmptyDataSet scrollView: UIScrollView!) -> NSAttributedString! {
        let text = "XXXXXXXが見つかりませんでした"
        return NSAttributedString(string: text, attributes: [NSFontAttributeName: App.Font.main(14), NSForegroundColorAttributeName: UIColor.gray])
    }

    func description(forEmptyDataSet scrollView: UIScrollView!) -> NSAttributedString! {
        let text = "配信の際はPUSH通知でお知らせ致します"
        return NSAttributedString(string: text, attributes: [NSFontAttributeName: App.Font.main(12), NSForegroundColorAttributeName: UIColor.gray])
    }
}

```


### Eureka

[xmartlabs/Eureka: Elegant iOS form builder in Swift](https://github.com/xmartlabs/Eureka)

多彩なフォームを作成できるライブラリです。
コードでStatic Table View を構成すると少々面倒ですが、このライブラリを使うと簡単に設計できます。
（とはいえ書き方のクセが強い）

```SettingViewController.swift
import UIKit
import Eureka

class SettingViewController: FormViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        form
            +++ Section("PUSH通知設定")
            <<< LabelRow("通知設定を開く") {
                $0.title = $0.tag
                }.onCellSelection(){row in
                    let url = URL(string: UIApplicationOpenSettingsURLString)!
                    let app = UIApplication.shared
                    app.openURL(url)
            }

            +++ Section("このアプリについて")
            <<< ButtonRow("利用規約") {
                $0.title = $0.tag
                $0.presentationMode = .segueName(segueName: R.segue.settingViewController.toTermsOfUseVC.identifier, onDismiss: nil)
            }

            <<< LabelRow(){
                $0.title = "このアプリを評価する"
                }.onCellSelection(){row in
                    let url = URL(string: App.URL.itunes)!
                    let app = UIApplication.shared
                    app.openURL(url)
            }

            <<< LabelRow() {
                $0.title = "バージョン"
                $0.value = App.version
        }
    }
}
```


### NVActivityIndicatorView

[ninjaprox/NVActivityIndicatorView: A collection of awesome loading animations](https://github.com/ninjaprox/NVActivityIndicatorView)

色々なローディングインジケータを扱えるライブラリです。
オリジナルの[gontovnik/DGActivityIndicatorView](https://github.com/gontovnik/DGActivityIndicatorView) はObjective-Cですが、こちらはSwiftで書き直されています。


### PMAlertController

[Codeido/PMAlertController: PMAlertController is a great and customizable substitute to UIAlertController](https://github.com/Codeido/PMAlertController)

UIAlertControllerがカスタマイズされたライブラリです。
普通のUIAlertControllerのように使います。（普通のUIAlertControllerでいい件）

```
let popAlertController = PMAlertController(title: "ダウンロード頂き\nありがとうございます！", description: terms.description, image: nil, style: .alert)
popAlertController.addAction(PMAlertAction(title: "OK", style: .default, action: { () in
    self.viewController?.enableTabBar() /// タブバーを有効にする
}))
self.present(popAlertController, animated: true, completion: nil)
```


### SwiftDate

[malcommac/SwiftDate: The best way to manage Dates and Timezones in Swift](https://github.com/malcommac/SwiftDate)

日付に関する値を扱いやすくするライブラリです。


### Realm

[ realm/realm-cocoa: Realm is a mobile database: a replacement for Core Data & SQLite](https://github.com/realm/realm-cocoa)

Databeseフレームワークライブラリです。ローカルにデータを保持する際に使います。


### R.swift

[mac-cain13/R.swift: Get strong typed, autocompleted resources like images, fonts and segues in Swift projects](https://github.com/mac-cain13/R.swift)

Resourceを管理するライブラリです。
`R.~~` という書き方で以下のものがコード補完されるようになります。

- Images
- Fonts
* Resource files
* Colors
* Localized strings
* Storyboards
* Segues
* Nibs
* Reusable cells

```swift
let icon = R.image.settingsIcon()
let font = R.font.sanFrancisco(size: 42)
let viewController = CustomViewController(nib: R.nib.customView)
let string = R.string.localizable.welcomeWithName("Arthur Dent")
```

文字列で管理しなくなるのでtypo等の心配もなくなりいいのですが、
全部 `R`から始まり、コードが増えてきた際の可読性が落ちる気がするので、[SwiftGen](https://github.com/SwiftGen/SwiftGen)の方がいいかも。


### Instructions

[ephread/Instructions: Create walkthroughs and guided tours (coach marks) in a simple way, with Swift.](https://github.com/ephread/Instructions)

吹き出しを表示できるライブラリです。チュートリアルなどで使います。

```swift 
...

extension AreaShopViewController: CoachMarksControllerDataSource, CoachMarksControllerDelegate {

    func numberOfCoachMarks(for coachMarksController: CoachMarksController) -> Int {
        return 1
    }

    func coachMarksController(_ coachMarksController: CoachMarksController, coachMarkAt index: Int) -> CoachMark {
        var coachMark: CoachMark = coachMarksController.helper.makeCoachMark(for: tableView, pointOfInterest: nil, cutoutPathMaker: nil)
        coachMark.arrowOrientation = .bottom
        return coachMark
    }

    func coachMarksController(_ coachMarksController: CoachMarksController, coachMarkViewsAt index: Int, coachMark: CoachMark) -> (bodyView: CoachMarkBodyView, arrowView: CoachMarkArrowView?) {
        let coachViews = coachMarksController.helper.makeDefaultCoachViews(withArrow: true, withNextText: true, arrowOrientation: coachMark.arrowOrientation)
        coachViews.bodyView.hintLabel.text = "💡お気に入りに登録して店舗のオトクな情報をゲットしよう!"
        coachViews.bodyView.nextLabel.text = "OK"
        coachViews.bodyView.nextLabel.font = UIFont.boldSystemFont(ofSize: UIFont.labelFontSize)
        return (bodyView: coachViews.bodyView, arrowView: coachViews.arrowView)
    }
}
```


### TextAttributes

[delba/TextAttributes: An easier way to compose attributed strings](https://github.com/delba/TextAttributes)

テキストの装飾を扱いやすくするライブラリです。

```
var titleLabel = UILabel()
let attrs = TextAttributes()
				.lineHeightMultiple(1.4)
				.underlineStyle(.styleSingle)
titleLabel.attributedText = NSAttributedString(string: "タイトル", attributes: attrs)
```


### AttributedLabel

[KyoheiG3/AttributedLabel: Easy to use, fast, and higher performance than UILabel.](https://github.com/KyoheiG3/AttributedLabel)

UILabelよりもパフォーマンスを上げ、扱いやすくするライブラリです。 ※ UILabelの継承じゃないことに注意

```
var bodyLabel = AttributedLabel()
bodyLabel.frame = CGRect(x: 0, y: 0, width: view.bounds.width, height: 30)
bodyLabel.font = UIFont.systemFont(ofSize: 15)
bodyLabel.contentAlignment = .topLeft
bodyLabel.padding = 15
view.addSubview(bodyLabel)
```


以上となります。　実は現状使ってないライブラリもあります。