関西モバイルアプリ研究会 #5 でCarthageの話をしてきました #関モバ

毎月恒例の関西モバイルアプリ研究会 #5で今回も発表させていただきました。会場と🍻に軽食を提供してくださるはてなさんに多謝 🙏

今回の資料はこちら。

CocoaPodsと並ぶ依存性管理ツールとして普及が進みつつあるCarthageですが、READMEにあまり情報がないCLIのコマンドのオプションや次期バージョンに入る予定の最新動向などについて紹介しました。

以前のエントリーでお話したように、今はCarthageのコミッターとして活動していることもあって現時点で46個ほどのPRを出していました。

今回の発表で知ってもらいたかったことの1つがGitHub Enterpriseのサポートです。

github "https://enterprise.local/ghe/desktop/git-error-translations"

という書き方でgithub.com上のリポジトリと同様にビルド済みバイナリーのダウンロードなどが機能するようになっています。現在 0.8: Llama Calculus が最新リリースですが、こちらは次期リリースに入るはずなのでGitHub Enterpriseを利用しているエンジニア・企業の方々は乞うご期待。

その他皆さんの発表資料などは以下からどうぞ!

kanmoba.connpass.com

おまけ

fabricの発表をしてくださったTwitterの中の方々からスピーカー特典としてスピーカーをいただきました!ありがとうございました!! ✨

関西モバイルアプリ研究会 #4 でLTしてきました #関モバ

第1回から参加させていただいている関西モバイルアプリ研究会 #4でLTをしてきました。なんだかんだでGoogle I/OWWDC 特別会だった#3以外の3回全てで発表できていて嬉しい限りです! 💖

以下が発表スライドです。

OS Xでは以前から使えたものの、iOSではiOS 8からやっと使えるようになったDynamic FrameworkをどうやってXcodeプロジェクトに導入するのか、という選択肢・手順についてまとめてみました。

またiOS 7ではDynamic Frameworkが使えず、そのままではSwift製のライブラリを導入するのが結構辛いのですが、その辺を簡単に導入してくれるCocoaSeedsというツールについても少しだけ触れてみました(まだあんまり知られてない)。

発表後にFrameworkのコード署名周りの話を @griffin_stewie さんとしていたんですが、Frameworkをアプリターゲットに導入する際に“Embed Frameworks”ビルドフェーズの各リスト項目で“Code Sign On Copy”というチェックボックスをオンにしておけば、アプリ用のコード署名設定でFrameworkが再署名されるので、Framework自体のコード署名はiPhone Developerの適当なものでも構わない、という知見を共有することもできたので、発表した甲斐がありました! 😄

次回の関モバ #5は2015/8/26(水)開催とのことでした 🚀

その他皆さんの発表資料などは以下からどうぞ!

kanmoba.connpass.com

itok.jp

usami-k.hatenablog.com

yashigani.hatenablog.com

Carthageのコミッター(Collaborator)になりました

先月の2015年6月に、CarthageというCocoaプラットフォーム(iOS/OS X/watchOS)用の依存性管理ツールコミッター(Collaborator)になりました

このプロジェクトは元々ReactiveCocoa 3.0APIを洗練させるためのショーケースとして始まったという側面もあり、ReactiveCocoaのCollaboratorとしては当然注目していました。Carthage v0.6.5からv0.7へのバージョンアップ時に、Swift 1.1から1.2への移行、それに伴うReactiveCocoaのアップデートがあったんですが、そこでRACAPI/設計が大きく変わったことで結構なバグが発生してしまっていました。それらのバグなどを調査・修正して色々とcontributeしている内にinviteしてもらった、という次第です。

RAC 3に慣れていないとなかなか修正し辛いコードベースなのは確かだと思うので、RACのCollaboratorでもあることを活かして貢献していくつもりです。Carthageユーザーで何かお困りの方はこのブログや@ikesyo経由で是非フィードバックをいただければと思っています。

Swiftでジェネリックなメソッドの特殊化を行う方法

今日色々とやり取りをしながら、Swiftでのジェネリックメソッドについてある知見を得たのでまとめておきます。

以下のようなSwiftの型・ジェネリックメソッドがある時、このままでは型指定(特殊化)が面倒になってしまいます。

class Hoge {
    class func genericMethod<T: Request>(callback: T -> Bool) {
        ...
    }
}

// 呼ぶ時
Hoge.genericMethod { (x: SomeRequest) in true }

上記のような場合、型情報のヒントが与えられないのでクロージャでパラメータの型を明示しないといけません。引数にTインスタンス・値を渡す場合は型推論が効くし、以下のように型自体がジェネリックな場合は初期化時に明示的に特殊化が出来るのですが。。

class Generic<T> {}

let generic = Generic<String>()

このようなケースでは、メソッドのパラメータとして型自体を渡させるようにするとそれが型のヒントとなりクロージャで型指定を行う必要がなくなります。

class Hoge {
    class func genericMethod<T: Request>(type: T.Type, callback: T -> Bool) {
        ...
    }
}

// 呼ぶ時
Hoge.genericMethod(SomeRequest.self) { x in true }

振り返ってみればObjective-CではこのようにClassをパラメータで渡すことも多かった気がしますね。

このパターンを使うと、例えばUITableViewCellのdequeueが以下のように出来、キャストが不要になります。

extension UITableView {
    func registerNibForClass<T: UITableViewCell>(type: T.Type) -> UINib {
        let nib = UINib(nibName: type.nibName(), bundle: nil)
        registerNib(nib, forCellReuseIdentifier: type.reuseIdentifier())
        return nib
    }

    func dequeueCell<T: UITableViewCell>(type: T.Type, forIndexPath indexPath: NSIndexPath) -> T {
        return dequeueReusableCellWithIdentifier(type.reuseIdentifier(), forIndexPath: indexPath) as T
    }
}

extension UITableViewCell {
    class func simpleClassName() -> String {
        return NSStringFromClass(self).componentsSeparatedByString(".").last!
    }

    class func nibName() -> String { return simpleClassName() }

    class func reuseIdentifier() -> String { return simpleClassName() }
}

let cell = tableView.dequeueCell(HogeCell.self, forIndexPath: indexPath)

Javaとかでは出来たような気がしますが Hoge.genericMethod<SomeRequest> { x in true } みたいにメソッドコール時に明示的に特殊化が出来ればいいんですけどね。

逆引きReactiveCocoa: 固定値をRACSignalでラップする

非常に基本的なことですが、あまりはっきりと触れられていない(触れる必要がない?)のが、単純に固定値をラップしたシグナルを生成するケースです。方法自体は単純で、以下のようなメソッドが用意されています。

// 値の場合
RACSignal *singleValueSignal = [RACSignal return:@"foobar"];

// 下記と同義
[RACSignal createSignal:^ RACDisposable * (id<RACSubscriber> subscriber) {
    [subscriber sendNext:@"foobar"];
    [subscriber sendCompleted];
    return nil;
}];

// `completed`だけの場合
RACSignal *emptySignal = [RACSignal empty];

// 下記と同義
[RACSignal createSignal:^ RACDisposable * (id<RACSubscriber> subscriber) {
    [subscriber sendCompleted];
    return nil;
}];

// `error`だけの場合
NSError *someError = ...;
RACSignal *errorSignal = [RACSignal error:someError];

// 下記と同義
[RACSignal createSignal:^ RACDisposable * (id<RACSubscriber> subscriber) {
    [subscriber sendError:someError];
    return nil;
}];

利用ケースについて、例えば引数のシグナルの変化に合わせて指定したセレクターを実行する -[NSObject rac_liftSelector:withSignals:] では、引数は全てシグナルでなければならないのですが、

[self.mapView rac_liftSelector:@selector(setCamera:animated:) withSignals:cameraSignal, [RACSignal return:@YES], nil];

というように、固定値を使いたい場合などにはよく使う必要が出てくるのではないでしょうか。

ReactiveCocoaのコミッターになりました(なってました)

もう結構前で昨年末か年始からなのですが、自分でもいくつか解説を書いている ReactiveCocoa というObjective-C用のFunctional Reactive Programmingライブラリのコミッターになりました!

ReactiveCocoa

ちなみに現時点までで19個のプルリクをしていて、マージされたのが15個、クローズされたのが3個、未マージなのが1個という感じです。

以下一覧

結構細かい改善・リファクタリングや機能追加が多いですが、こんな感じの貢献でもスター4,300超えのプロジェクトのコミッターになれるという一例になればと思います。

これからも逆引きReactiveCocoaの記事を書いたり、日本語での情報発信も増やしていければと考えています。日本でRACをお使いの方はどしどしご質問ください!

それでは Let's use ReactiveCocoa!

P.S. 絶賛お仕事も募集中です! (特にReactiveCocoaを使えるiOSなお仕事)

ACAccountStoreのReactiveCocoaラッパーを作った

タイトルのままですが ikesyo/ReactiveAccountStore というAccounts.framework (ACAccountStore) のReactiveCocoaラッパーを作ってみました。

現時点では、以下の4つの非同期メソッドのRACSignalラップ版をサポートしています。

  • -requestAccessToAccountsWithType:options:completion:
  • -saveAccount:withCompletionHandler:
  • -renewCredentialsForAccount:completion:
  • -removeAccount:withCompletionHandler:

より詳しくはヘッダードキュメントを参照してください。

すでにCocoaPodsに登録済みなので、以下で利用できるようになります。

pod 'ReactiveAccountStore'

対応プラットフォームは、OS Xのサポートとdeprecatedのメソッドの関係上、

となっています。

Accounts.frameworkを使用することがあるReactiveCocoaユーザーは利用してみてください(どれだけいるのか)。