koogawa blog

iOS、Android、foursquareに関する話題

ローディング中に画面ごと回転するライブラリを作った話

アプリが何らかの処理中にローディング画面を出すのは一般的だと思います。

f:id:koogawa:20161112233719p:plain

SVProgressHUD

これらに対抗して、画面全体がぐるぐる回るライブラリをネタで作ってみました。

github.com

インストール

CocoaPods でインストールできます。

pod "RollingProgressHUD"

使い方

RollingProgressHUD をインポートします。

import RollingProgressHUD

ローディング開始時に

RollingProgressHUD.show()

を呼び、ローディング完了時に

RollingProgressHUD.dismiss()

を呼ぶだけです。

デモ

ローディング中に画面ごと回転します。

f:id:koogawa:20161112234359g:plain

目が回りそうですね(^q^)

エンジニア立ち居振舞い:自分のタスクよりメンバーのコードレビューを優先する

お題「エンジニア立ち居振舞い」 ということで自分も書きます。

以前、Twitterにつぶやいたのですが

自分のタスクに着手する前に、チームメンバーのコードレビューをするように心掛けています。

コードレビューが滞ると、次のような悪影響があると思っています。

  • 他のメンバーが次のタスクに着手できない
  • プルリクエストが消化されないうちにもメインのブランチはどんどん進んでいるのでコンフリクトが起こる
    • →コンフリクトを直す手間が増える
  • 誰が何をしているか把握しにくくなる

当然、自分の作業は止まってしまいますが、それよりも上に書いた悪影響の方がまずいと思っていて、ここを解決することで全体的には開発スピードが上がると思っています。

共感した立ち居振る舞い

RxSwiftを使ってfoursquareのベニューを取得するメモ(Swift 3.0版)

以前書いたこちらの記事がさっそくビルドできなくなっていたので、Swift 3.0 対応版としてリライトしました。

blog.koogawa.com


RxSwift のメリットを理解するには実際に使ってみるのが一番!ということで、とりあえず foursquare のベニューを取得するサンプルを作ってみました。

f:id:koogawa:20160515223640p:plain

※RxSwift は絶賛勉強中なので間違ったことを書いている可能性が高いです。ツッコミ歓迎です!

動作環境

  • Swift 3.0
  • RxCocoa (3.0.0-rc.1):
  • RxSwift (3.0.0-rc.1)
  • SwiftyJSON (3.1.1)
  • Xcode 8.0

APIクライアント

APIにアクセスする部分を作ります。戻り値を Observable<[Venue]> にしているのがポイントです。

func search(query: String = "") -> Observable<[Venue]> {
    return Observable.create{ observer in
        let client = FoursquareAPIClient(accessToken: "YOUR_TOKEN")
        let parameter: [String: String] = [
            "ll": "40.7,-74",
            "query": query
        ];
        client.request(path: "venues/search", parameter: parameter) {
            [weak self] data, error in
            guard let strongSelf = self, let data = data else { return }
            let json = JSON(data: data)
            let venues = strongSelf.parse(venuesJSON: json["response"]["venues"])
            observer.on(.next(venues))
            observer.on(.completed)
        }
        return Disposables.create {}
    }
}

fileprivate func parse(venuesJSON: JSON) -> [Venue] {
    var venues = [Venue]()
    for (key: _, venueJSON: JSON) in venuesJSON {
        venues.append(Venue(json: JSON))
    }
    return venues
}

通信ライブラリは拙作 FoursquareAPIClient を使用しました。

ViewModel

ViewModel から先ほどの serch を呼び出す部分です。

public func fetch(query: String = "") {
    client.search(query: query)
        .subscribe { [weak self] result in
            switch result {
            case .next(let value):
                self?.venues.value = value
            case .error(let error):
                print(error)
            case .completed:
                ()
            }
        }
        .addDisposableTo(disposeBag)
}

search の戻り値が Observable<[Venue]> なので、これを subscribe することができます。その中で、返ってくる値(ベニューリストなど)を Variable 型の venues にセットしています。この venues は ViewController から bind されるため、値が変更されるタイミングで何か処理を発火させることができるわけです。

ViewController

ViewController は30行程と、かなりスッキリしました。rx.items(dataSource: ) でベニューリストと TableView を bind しているのがポイントです。ViewModel のベニューリストに変化があるとTableViewがリロードされます。

import UIKit
import RxSwift
import RxCocoa

class ViewController: UIViewController {

    @IBOutlet weak var tableView: UITableView!
    
    var viewModel = ViewModel()
    var dataSource = DataSource()
    var delegate = Delegate()
    let disposeBag = DisposeBag()

    override func viewDidLoad() {
        super.viewDidLoad()
        self.tableView.delegate = self.delegate
        self.viewModel.fetch()

        self.viewModel.venues
            .asDriver()
            .drive (
                self.tableView.rx.items(dataSource: self.dataSource)
            )
            .addDisposableTo(self.disposeBag)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

完全なソースコードはこちらです。

GitHub - koogawa/RxSwiftSample: RxSwiftSample

参考にさせて頂いた記事など

CocoaPodsに登録した自作ライブラリを更新するメモ

毎回忘れるのでメモ。

前提

  • すでに自作ライブラリを CocoaPods に公開済み

最初にライブラリを公開する際は下記記事がとても参考になる。

手順

1. ライブラリを更新

変更内容を push しておく。

実際に pod install して使えるかテストしておくこと。ブランチ指定が便利。

pod 'FoursquareAPIClient', :git => 'https://github.com/koogawa/FoursquareAPIClient.git', :branch => 'develop'

1. podspec ファイルを編集

s.version を上げるのを忘れずに。

2. git にタグ追加

$ git tag -a 2.0.0 -m 'Compatible Swift 3.0'
$ git push origin 2.0.0

3. podspec をバリデーション

$ pod spec lint

なんか怒られたら直す。

Swift 3対応でちょっとハマったので下の方に対処法を書いておいた。

4. CocoaPodsへ公開

pod trunk push FoursquareAPIClient.podspec 

トラブルシューティング

困ったらとりあえず pod を最新に上げてみる

$ sudo gem install cocoapods

Swift 3 対応

pod spec lint したら次のエラーが出た。

Check dependencies
“Use Legacy Swift Language Version” (SWIFT_VERSION) is required to be configured correctly for targets which use Swift. Use the [Edit > Convert > To Current Swift Syntax…] menu to choose a Swift version or use the Build Settings editor to configure the build setting directly.
“Use Legacy Swift Language Version” (SWIFT_VERSION) is required to be configured correctly for targets which use Swift. Use the [Edit > Convert > To Current Swift Syntax…] menu to choose a Swift version or use the Build Settings editor to configure the build setting directly.

** CLEAN FAILED **


The following build commands failed:
    Check dependencies
(1 failure)

ググったら、同じように困っている人がいた。

Swift 3 CocoaPod does not pass lint - Stack Overflow

cocoapod を最新に上げて、.swift-version ファイルを追加しないといけないらしい。

↑これは解決したけど、また新たなエラーが。

pod trunk push: "xcodebuild: error: 'App.xcworkspace' does not exist." · Issue #5843 · CocoaPods/CocoaPods

で解決。

Swift 5 対応

pod spec lint したら次のエラーが出た。

    ** BUILD FAILED **
    
   Testing with `xcodebuild`. 
 -> FoursquareAPIClient (5.0.0)
    - ERROR | [iOS] xcodebuild: Returned an unsuccessful exit code.
    - NOTE  | xcodebuild:  note: Using new build system
    - NOTE  | [iOS] xcodebuild:  note: Planning build
    - NOTE  | [iOS] xcodebuild:  note: Constructing build description
    - NOTE  | xcodebuild:  error: SWIFT_VERSION '3.0' is unsupported, supported versions are: 4.0, 4.2, 5.0. (in target 'App')
    - NOTE  | xcodebuild:  error: SWIFT_VERSION '3.0' is unsupported, supported versions are: 4.0, 4.2, 5.0. (in target 'FoursquareAPIClient')

Analyzed 1 podspec.

[!] The spec did not pass validation, due to 1 error.

SWIFT_VERSION3.0 なんか指定してないよ!と思ったけど、podspec ファイルに

  s.swift_version = '5.0'

を指定してないのが原因?

さらに、Swift 3 対応のときに追加した.swift-version ファイルも今は deprecated らしいので削除。

これでも解決しない場合は workaround だけど --allow-warnings オプションで回避できるらしい。

リンク

「理科系の作文技術」を読んだ

以前、id:hyoshiok さんのブログで紹介されており、ずっと気になっていたので読んでみました。

対象とする読者

「私がこの書物の読者と想定するのは、ひろい意味での理科系の、わかい研究者・技術者と学生諸君だ。これらの人たちが仕事でものを書くとき――学生ならば勉学のためにものを書くとき――に役立つような表現技術のテキストを提供したい」。

序章で著者がこう述べているように、本書は主に理系層がターゲットとなっています。 しかし、実際に読んでみると、文書を書くすべての人におすすめできる内容になっています。

以下、印象に残った内容をいくつか紹介していきます。(数字は章を表す)

読者を意識する(2.3.4)

書くことに慣れていない人は、誰が読むのかを考えずに書き始める傾向がある、と著者は述べています。

読者が誰であり、その読者はどれだけの予備知識を持っているか、またその文書に何を期待し、要求するだろうかを、十分に考慮しなければならない。

これは技術ブログを書く際にも通じると感じました。読者がプログラミング初心者なのか、それとも基本的なことは理解している中級者なのか。読者のレベルによっても書く内容は変わってくると思います。

目標規定文(2.4)

自分は何を目標としてその文書を書くのか、そこで何を主張しようとするのかを熟考して、それを一つの文にまとめる。そういう文を、この本では目標規定文と読んでいました。

私はふだん、業務用の文書(Wikiなど)を書く際に、「これは何」という段落を一番上に用意するようにしています。そこに文書の目的を書くことが多いのですが、これがまさに目標規定文なのかな、と思いました。これがあるだけで、読者は読む・読まないの判断ができるようになります。

まぎれのない文を(8.3)

黒い目のきれいな女の子

この文はなんと 8通り に読むことができます。(ロゲルギスト共著『第四物理の散歩道』、(岩波書店、1969)、p226より)

「読むことができる」と表現しましたが、それだけ読者に誤解を与えてしまう可能性があるとも言えます。

この例は読点を入れることでまぎれがなくなります。

  • 黒い目の、きれいな、女の子
  • 黒い、目のきれいな、女の子

一つの文を書くたびに、読者がどういう意味に取るだろうかと、あらゆる可能性を検討するべきです。

字面の白さ(8.5.1)

次の2つの文を比べてみてください。

  1. 電源電圧の変動は普通0.1%程度だが、これでは普通  10^-7 程度の周波数安定性しか得られない。我々の実験目的を達成するには、抵抗R1を調整して安定性を良くする必要がある。

  2. 電源電圧の変動はふつう0.1%程度だが、これではふつう  10^-7 程度の周波数安定性しか得られない。われわれの実験目的を達成するには、抵抗R1を調整して安定性をよくする必要がある。

パッと見たとき、A. は全体として黒く、B. はそれとくらべて白く感じられると思います。字面の白さとはそういう意味です。無駄に漢字を使うと文章に難解な印象を与えてしまうので、適切な白さにすべきです。

手紙(10.1)

まだ e-mail も普及していなかった時代なので、手紙で要件を伝える方法についても書かれています。

印象的だったのが、10.1.3 本文 の

私なら、情報伝達に関係のない「拝啓、時下ますます・・・」は省いて〜

の部分。

メール文化になった今も「○○様 お世話になっております。△△株式会社の・・・」から始まるメールで溢れており、この辺は今もあまり変わっていないですね。

「読む」のではなく「話す」(11.1)

最終章では学会講演の要領についても書かれています。ここは「学会講演」を「勉強会での発表」に置き換えて読みました。

講演では原稿を「読む」のは禁物だ。聞く立場になってみればすぐにわかることだが、ひとが原稿を読みあげるのについていくには非常な努力がいる。

これは確かにその通りで、例えば「真空中で400℃、2時間の熱処理をした試料の表面に金の電極を蒸着し、・・・」というような複文は、読めばスラスラとわかっても、聞く側になると結構つらいものがあります。

この例は「資料はあらかじめ真空中で400℃、2時間の熱処理をします。その試料の表面に金の電極を蒸着し・・・」と単文に分割することで救われそうです。しかし、著者も述べているように、原稿をただ読みあげるのではなく、多少下手でも一生懸命「自分の言葉」でオーディエンスに話しかけることが重要なのだと思います。

おわりに

出版が1981年ということもあり、中にはOHP(オーバーヘッドプロジェクタ)の使い方など、今ではあまり使われなくなった内容も含まれています。しかし、それ以外の内容は30年以上たった今でも十分通用すると思いました。もっと早くこの本に出会いたかった!

理科系の〜と銘打ってはいますが、文章を書くすべての人におすすめしたい一冊です。

#iosdc で "「まりも」とiOSの6年間" の話をしてきたよ

f:id:koogawa:20160821091002p:plain

8/19〜20、 練馬で開催された iOSDC Japan 2016 にスピーカー兼スタッフとして参加してきました。

発表した内容

iPhone OS 3時代にリリースした「まりも」アプリの進化とともに、iOSの歴史を皆で振り返っていく、というスタイルでした。

↑のスライドだとアニメーションしませんが、iOS 9より磨きがかかったまりもの回転 についても触れました。

iOS 8 までは矩形の衝突判定にしか対応していなかったのが、

f:id:koogawa:20160821090034g:plain

iOS 9 からは円形の衝突判定にも対応したのでした!

f:id:koogawa:20160821090101g:plain

Togetter さんに、発表中のツイートをまとめて頂きましたm( )m

今後もがんばります💪

お越しいただいた方ありがとうございました!

感想

スタッフとして

f:id:koogawa:20160821094450p:plain

今回は Track B のチームリーダー兼ストリーミング配信を担当しました。

  • 会場は暑くないか
  • 照明は明るすぎないか
  • スライドは見にくくないか
  • トークがタイムテーブル通りに進んでいるか
  • 配信は途切れていないか

などを常に気にしなければならなかったので、かなり忙しかった!残念ながら、ほとんどのトークは落ち着いて聞くことができませんでした。これからゆっくり録画を観たいと思います👍

スピーカーとして

f:id:koogawa:20160821094514j:plain (Thanks: Tecco)

やはり緊張していたこともあり、予定より数分早く終わってしまいました。知らないうちに早口になってしまうんだなぁ。聴きづらかったらすんません🙇🏻

また、今回はスピーカーのみなさまへ、お知らせとお願い | iOSDC Japan 2016にもあるように

トーク終了後のQ&Aタイムでは質問者にもマイクを渡して質問してもらいますが、録画や配信には質問者のマイクの音声は乗らないことがあります。必ず質問を復唱してからの回答をお願いします。例: 「○○というご質問ですね。それは〜」

というのをやってみたのですが、これがやってみると意外と難しい。途中からグダグダになってしまった気がします😫

あとで自分の発表を見て、今後に活かしたいと思います。

練馬について

「練馬ってどこにあるの?東京なの?」などとよく聞かれる練馬ですが、実は新宿や池袋に乗り換えなしでアクセスできる、とても良い位置にあるのですよ。私もかれこれ10年以上住んでいます。

id:ryo_pan さんのエントリにもあるように、美味しいラーメン屋もたくさんあるので、ぜひ近くに来たら寄ってみてください!

まとめ

一言でまとめると「最高」でした。

久しぶりに心の底から「超楽しい!!」と思えた2日間でした。

会場まで足を運んで頂いた皆さま、スポンサーの皆様、スタッフの皆さま、ありがとうございました!

2016/7/21 #potatotips #31 (iOS/Android開発Tips共有会) に参加してきたよ

f:id:koogawa:20160721235858p:plain

今日はFiNCさんで開催された potatotips #31 (iOS/Android開発Tips共有会) に参加してきました。

potatotips.connpass.com

噂では聞いていたのですが、とても綺麗なオフィスでした。

f:id:koogawa:20160722001424j:plain

ペッパーくんもいましたよ!

f:id:koogawa:20160722001231p:plain

懇親会のメニューも健康的!ごちそうさまでしたm( )m

f:id:koogawa:20160722014225p:plain

ツイートもまとめておきました。

以下は発表のメモになります。間違いなどあれば教えて下さい。


目次:

UICollectionViewでインタラクティブなCellの並び替え

元同僚である平松さんの発表です。 UICollectionView の Interactive Reordering が超便利だよ!というお話でした。

この機能、実は iOS 9 からあったそうなんですが、なかなか知られていないみたいです(自分も知らなかった)。

実装方法は、UIGestureRecognizer などと組み合わせて reorder を呼ぶだけ。 これだけで簡単にiOSのホーム画面のような実装ができるそうな。ぜひ使っていきたいですな!

UIPageViewControllerをつかって無限スクロールできるタブUIを実装した話

Vasily の EndoMari さんによる発表。 最近良く見るタブを横にスクロールできるUIを実装した時のお話でした。

この手のライブラリはたくさん出てるけど、ライフサイクルが把握しにくかったり、ログ集計が難しいという理由から、Vasilyさんでは自前で実装されたそうです。

http://tech.vasily.jp/entry/tab_page_viewcontrollertech.vasily.jp

iOSアプリ100個考察してみた(中間報告)

mafmoff さんによる発表です。iOSアプリ100個を考察してみて気付いたことについて語られていました。

github.com

iOSアプリ100個を考察してみて気付いたこと:

  • 設定画面が灰色!
  • 一覧スクロールでナビゲーションバーが引っ込むの多いよね
  • 横スクロールタブが多い(スマニュー風のやつ)
  • そのチュートリアルいる?すぐ使いたいのでスキップできないと辛み
  • WebViewの中にヘッダーがあって二重に表示されちゃってる
  • ライセンスをアプリの設定画面に表示しちゃってる →iOS標準の設定画面に表示してみては?

ひょっとすると、iOS標準の設定画面にアプリ独自の設定項目を置けることが意外と知られていないのかもしれませんね。

[iOS] アプリの設定画面にバージョン表記と謝辞を自動で設定する | DevelopersIO

Binding Realm

woxtu(おつ)さんによる発表。最初にアカウント名をどう発音するのか話題になりました。

Realm のオブジェクトを KVO を使って監視し、データが更新されたらViewにも反映させる方法について解説されていました。他にも SwiftBond, RxSwift などで実現できそうですが、KVO を推しているそうです。

SketchでUIを楽に組もう! - ZeplinとSympli -

d_date さんによる発表です。Sketch はとても良いけど、使う人が中身を見れないことがあります。また、Storyboard をそのまま作ることができない。それを解決してくれる Sympli というツールがあるよ!というお話でした。

sympli.io

ストレッチタイム

ここで体をほぐすためのストレッチタイムが入りました。さすがは FiNC さんですね!(写真は自粛)

実装とアプリ開発と独学でiOSアプリ開発と向き合うこと

fumiyasacさんによる発表です。fumiyasacさんは30歳から独学でアプリ開発を始めたそうです。

コードレビューがない孤独な環境でバッドノウハウを実装してしまうこともありましたが、Qiitaに記事を投稿したり、勉強会に参加することで壁を乗り越えてきたそうです。 アプリ開発を勉強する際に読んだ参考書なども紹介されていました。

Notification in iOS10

Tachibana Kaoru さんによる Notification の発表!ちなみに、Tachibanaさんは来月からフリーランスになられるそうです!🎉

iOS 10 からは Notification の配信状況を簡単にハンドリングできるようになりました。例えば、「Notificationがまだ発火してない」「発火したけどユーザがタップしてない」、などを取得できます。また、Notificationにidを振ることにより、あとから編集・削除ができるそうです。

iOS 10 で Notification はだいぶ進化しましたね〜

[iOS 10] Programmatically creating a custom Sticker application

akio0911 さんによる発表です。iOS 10から作れるようになった Sticker についてのお話でした。

個人的にまず驚いたのは、いよいよ「アプリ本体が無いアプリ」が登場する、という点でした。

MSStickerBrowserController などのクラス構造もわかりやすく解説されていました。Sticker を選択する画面は CollectionView を使ってカスタマイズすることもできるそうです。

さいごに

最初の potatotips 開催からそろそろ3年経つんですな。

時が経つのは早いものです😌