Swift 3 クロージャーについて

クロージャーについて少し知識が整理できていなかったので,メモしておきます.
なんとなく使えるけど,一からクロージャーを作るといろいろ疑問がでてきたので自分用にまとめてみました.
後になって考えると最初にこれを知っておけば理解が早かったのにということを忘れないようにメモしました.

▼ クロージャーの文法

1
2
3
{ (引数) -> 返値の型 in
	処理
}

▼ クロージャーを理解するときに知っておくと良いこと

– Swift クロージャーは,引数と返値の型を推論してくれる.
– 引数の()が省略できる.
– 返値を省略できる.
– 返値を暗黙に返してくれる.(クロージャ処理が1行の場合,return も省略できる)
– 引数も略式でかける.($0, $1, $2 というように記述できる)
– 最後の引数がクロージャーの場合,外に配置できる.(()内の引数から外に置ける.Trailing Closures)

– [weak self]
– @escaping

▼ 上記のサンプルコード

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// 文法どおりのクロージャー
let closureA = {(x: String) -> String in
    return x + "closureAの処理"
}
print(closureA("closureA:")) // closureA:closureAの処理
 
// 暗黙を利用した省略記法のクロージャー
let closureB = { x in
    x + "closureBの処理"
}
print(closureB("closureB:")) // closureB:closureBの処理
 
// クロージャーをパラメータに渡す定義
// (第2引数のクロージャーに第1引数の文字を渡す関数)
func closureParamA(_ x: String, _ y:(String) -> String) -> String {
    return y(x)
}
 
// 最後のパラメーターにクロージャーを渡す
// (既存のクロージャーにパラメータを渡す関数が書ける)
let param1 = closureParamA("closureParamA1:", closureA)
print(param1) // closureParamA1:closureAの処理
 
// 最後のパラメーターのクロージャーを()の外に配置する
// (新たにクロージャーにパラメータを渡す関数が書ける)
let param2 = closureParamA("closureParamA2:") { x in
    x + "closureParamの処理"
}
print(param2) // closureParamA2:closureParamの処理
 
// クロージャー定義をパラメータに書くのが大変なので,typealias を使う
typealias closureType = (String) -> String
func closureParamB(_ x: String, _ y:closureType) -> String {
    return y(x)
}
 
let param3 = closureParamB("closureParamB:", closureA)
print(param3) // closureParamB:closureAの処理

スマフォのマウントにラムマウントを試してみた件

ラムマウントXグリップ(RAM-HOL-UN7BU)¥3,000- を試してみたのでメモしておきます.

私がバイクに乗る用途は,主にツーリングが6割,サーキット走行が2割,街乗りが2割です.
たまに,ツーリング,サーキット走行時にラムマウントで GoPro をマウントすることがあり,ラムマウントを持っていたこと,必要に応じてマウントの取り外しができた方が利便性があると感じていたことから,固定するタイプのスマフォマントを敬遠していましたが,やはりたまに出向く初めての道ではスマフォナビを使用したいことがあり,ラムマウントXグリップを試してみることにしました.(iPhone6S Plusを使用)

商品はこんな感じです.

内容物はこんな感じです.
Xグリップ本体,ゴムバンド,接着剤が付属しています.

ハンドルマウント用のラムマウントとの組み合わせは,こんな感じです.

市街地,峠道,高速道路を走行してみましたが,特に問題はありませんでした.

以前,タンクバッグにスマフォを入れてナビゲーションを使用していた際に,1時間ほどで直射日光のためスマフォ本体が異常に熱を持ち,継続使用できないことがありましたが,走行中に外気にさらされているためか,本体が熱を持つことはありませんでした.

固定タイプのマウントを敬遠している方に,取り付け,取り外しが簡単なこと,必要十分な強度があること,取り付け位置の自由度があることから,おすすめできるマウント方法だと思います.

Xcode 8.3.2 で Alcatraz が使えなくなった件

Swift の整形ツールを探していて Xcode プラグインがいろいろ出ているようだったので Alcatraz からインストールしようとしたところ,メニューに「プラグイン マネージャ」がなかった.

いろいろ試して,関係はないが Homebrew を使用しようとしたら,Homebrew も利用できない事態になった.最悪だ.

以下の対処方法で Homebrew は使用できるようになった.(ホッ😌)

Homebrewを久々にupdateしたら出来なかった時の対処法
http://qiita.com/takezoux2/items/aa2a5f0bef19cd0d8508

その後,「プラグイン マネージャ」は一度使えるようになったが,再度 Xcode (8.3.2)を起動するとメニューに表示されなくなっていた.プラグインって廃止される傾向なのかなぁー?

Xcode 8 won’t load plug-ins #475
https://github.com/alcatraz/Alcatraz/issues/475

特に困っていないので,そのまま swimat を使用しています.

Swift3, APIKit, ObjectMapper, SnapKit を使って Web API にアクセスしてみた件

最近は,Swift3 で iOS アプリを開発しているのですが,改めて使用しているライブラリについて調べてみた.
仕事では日々実装しなくてはいけないテーマがあり,なかなか全体を俯瞰する機会がないので,GW を期に確認してみたというところです.
ネット上で公開されているライブラリに関する記事をざっとチェックしましたが,公開から1年以上経っていることもあり,なかなかそのままのコードで動作させることが難しいようだったので,個人的なメモとして簡単なコードを書くことにしました.

では早速,サンプルで使用する Web API を選びます.

1. Web API を選ぶ

▼ お天気Webサービス仕様
http://weather.livedoor.com/weather_hacks/webservice
ライブドアで無料提供している Web API のようです.
以下のように「地域ID」を指定することで天気情報を取得できるようです.

(例)「福岡県・久留米の天気」を取得する場合は,以下のURLにアクセスしてJSONデータを取得できるとのこと.
http://weather.livedoor.com/forecast/webservice/json/v1?city=400040

簡単そうなので,これにします.

2. APIKit でリクエスト

Xcode 8.3.2 で Swift3 を使用し,シングルページアプリを作成します.
CocoaPods で,APIKit / ObjectMapper / SnapKit を導入します.

APIKit
https://github.com/ishkawa/APIKit
- iOS 8.0 以降に対応.

ObjectMapper
https://github.com/Hearst-DD/ObjectMapper

SnapKit
http://cocoadocs.org/docsets/SnapKit/0.10.0/index.html
https://github.com/SnapKit/SnapKit

Xcode で作成された ViewController.swift に Web API リクエストのコードを記述します.

1
2
3
4
5
6
7
8
9
10
11
12
private func sendWeatherAPI() {
    let request = WeatherRequest(city: 130010)
    Session.send(request) { [weak self] result in
        switch result {
        case .success(let response):
            self?.dispWetherResponse(dto: response)	// ビューに取得データを表示する
 
        case .failure(let error):
            print("error: \(error)")
        }
    }
}

API リクエストは WeatherRequest という名前にしました.
http://weather.livedoor.com/forecast/webservice/json/v1?city=400040 にアクセするするのでこんな感じでしょう.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import Foundation
import APIKit
import ObjectMapper
 
struct WeatherRequest: Request {
    typealias Response = WeatherResponse
    let city: Int
 
    init(city: Int) {
        self.city = city
    }
    var baseURL: URL {
        return URL(string: "http://weather.livedoor.com/forecast/webservice/json")!
    }
    var method: HTTPMethod {
        return .get
    }
    var path: String {
        return "v1"
    }
    var parameters: Any? {
        return nil
    }
    var queryParameters: [String: Any]? {
        return ["city": city.description]
    }
    func response(from object: Any, urlResponse: HTTPURLResponse) throws -> Response {
        guard let object = Mapper<Response>().map(JSONObject: object) else {
            return Response()
        }
        return object
    }
}

3. 取得したデータをマッピング

WebAPI で取得したデータが
func response(from object: Any, urlResponse: HTTPURLResponse) throws -> Response {
に渡されますので,struct にマッピングします.
また,ライブラリのバージョンがあがり,返却するデータの方がオプショナルでなくなっているようです.

とりあえず,3つのデータだけ格納することにします.
階層が一つ下の項目にも map[“description.text”] のようにで参照できるのが便利ですね.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import Foundation
import ObjectMapper
 
struct WeatherResponse: Mappable {
    var publicTime = ""
    var title = ""
    var description = ""
 
    init() {
    }
    init?(map: Map) {
    }
 
    mutating func mapping(map: Map) {
        self.publicTime <- map["publicTime"]
        self.title <- map["title"]
        self.description <- map["description.text"]
    }
}

WeatherResponse が,ViewController.swift の Web API リクエスト部分のクロージャー記述に返されるので,画面に表示しておしまいです.

4. SnapKit で制約を指定する

あと,SnapKit で表示用ラベル位置を調整してみます.
SnapKit で制約を指定するわけですが,指定前にビューに対してラベルを addSubview() しておかなくてはなりません.

制約の指定は以下のようにしました.
一度,Autolayout の制約条件を Xcode から行いましたが,大変だった記憶があり,以下のコードだけで制約を指定できるのは大変便利かと思います.

1
2
3
4
5
6
7
8
9
10
titleLabel.snp.makeConstraints { make in
    make.top.equalTo(20)
    make.left.right.equalTo(view).inset(10)
    make.height.equalTo(30)
}
publicTimeLabel.snp.makeConstraints { make in
    make.top.equalTo(titleLabel.snp.bottom)
    make.left.right.equalTo(view).inset(10)
    make.height.equalTo(30)
}

titleLabel の下に publicTimeLabel が配置されるように制約を指定しています.
また,それぞれの高さは 30 です.

簡単にライブラリを使った検証でした.

▼ 追記

Himotoki っていうライブラリも結構紹介されているなぁーー
https://github.com/ikesyo/Himotoki