iOS開発完全に理解したのその一歩先へ...


この記事は CBcloud Advent Calendar 2019 4日目の記事です。
おそらくiOS/Androidエンジニアとして、CBcloudに2019/5/1から参画しましたが、
なぜか今はPM業のようなことをやっているentakuです。(この話は後日書こうとおもいます。)
念のため言っておくと、今の働き方に満足しているので、その辺は問題ないのです。

0. 自己紹介

entakuです。経歴は下記のようになっています。
なんちゃってSE
->NWエンジニア[SIer]
->
サーバーサイドエンジニア[SIer] ・java/PHP..etc
->
iOS/Android アプリ開発[スタートアップ]
->
Vue / Android アプリ開発 @ CBCloud

 最近は「ユーザーを動かす開発者」でありたいなと思います。

直近ではiOS開発が好きで下記のような活動をしていました。

一人iOSエンジニアでも気持ちよく開発できるiOSアプリ開発者になる!
iosの開発を始めたあの日の僕に伝えたいこと。

このQiitaでは「iOS開発完全に理解した」から、どのようにしてその先にレベルアップしていくかを考察していく記事です。

1. 設計の知識を深める

iOS開発を行っていると、こういうときどう書けばいいんだ..という様々な場面に巡り会います。
これは公式で指標となりうる設計フレームワークが無いこと、また

僕は「iOSアプリ設計パターン入門」という本をiOSエンジニアの友人から勧められ購入しました。

特に第1章「設計するということ」今後のiOS開発において不変的な考え方が述べられていると思います 
また、設計をただ紹介するだけで無く、

  • 今までのやり方のどんな問題があり
  • その問題はなぜ起こっていて
  • どのようなアプローチで解決できるのか?

がまとめられている、iOS開発に欠かせない内容だと思います。

また

  • 今までのやり方のどんな問題があり の箇所は、 一度iOS開発をした方は共感する部分が多いと思いますし、一歩先に進むためにはよいものだと思っています!

詳細な内容はぜひ購入して読んでいただきたいです!

※peaksリンク iOSアプリ設計パターン入門

2. RxSwiftへの挑戦

なぜRxSwiftを使うのか?

正直僕自身もRxSwiftの名前に先行して利用していた部分がありますので、僕の理解の範囲で書きます

基本的にRxSwiftでは下記の2つの処理をViewModelで繋げます。

- ユーザーの動作(input)
- APIなどデータを取得する処理(output)

下記の例では僕が書いたViewModelの簡単な例を載せております。

「viewDidLoad」がViewControllerから呼び出された際に、「viewDidLoadSubject」内の処理が呼び出されます。
ViewControllerでは「teams」を監視した処理を「viewModel.teams」内に書いており、何を検知した際にどのような処理を行うのか?をわかりやすく分離してあります。


class SportTalkListViewModel {

    override func viewDidLoad() {
        super.viewDidLoad()


        viewModel.viewDidLoad.onNext(())
        bindViewModel()
    }
    func bindViewModel() {


        viewModel.teams
            .bind(to: tableView.rx.items(cellIdentifier: "SportTalkListCell", cellType: SportTalkListCell.self)) { _, element, cell in
                cell.team = element
            }.disposed(by: disposeBag)

    }


class SportTalkListViewModel {

    private let disposeBag = DisposeBag()

    // input property
    var viewDidLoad: AnyObserver<Void>


    // output property
    var teams: Observable<[Team]>


    init(provider: TeamsProviderProvider = TeamsProviderProvider()) {
        let teamsRelay:BehaviorRelay = BehaviorRelay<[Team]>(value: [])
        let viewDidLoadSubject = PublishSubject<Void>()

        teams = teamsRelay.asObservable()
        viewDidLoad = viewDidLoadSubject.asObserver()


        viewDidLoadSubject.asObservable()
            .flatMap{ _ in provider.getTeams() }
            .flatMap { teams -> Observable<[Team]> in

                return .just(teams.teams)
            }.bind(to: teamsRelay)
            .disposed(by: disposeBag)


    }


正直このようなシンプルな構成では効力を発揮しませんが、画面内で多くの「ユーザーの動作」と「APIなどデータを取得する処理」が存在する場合、処理の変更や追加がしやすいです。

どのようにしてRxSwiftを学んだか??

これは強く断言できますが、
RxSwift経験者にマンツーマンで教えてもらうことがもっとも良い方法です!
僕自身も経験者に聴きながら、書きながら覚えていきました。
RxSwiftは自分でパーツを作りながら、少しずつできるようになっていくようなイメージで取り組んでいます。
この自分のパーツを増やしていく感覚が大切かなと考えています。

とても拙いアプリではありますが、下記でRxSwiftを利用した簡単すぎるアプリを作りました
footballアプリ(GitHub)

3. SwiftUIへの挑戦

ついについにiOSにも宣言的UIの潮流がきました!
正直AndroidのXMLで書けるUIに長らく嫉妬していましたね...

1.HotReloadでUIがリアルタイムかつ複数パターン確認できるようになったこと
2.TableViewなど固有Viewではなくなったところ

下記はいままでTableViewCellで表されていたものの一例です。
HStack (X軸を基準として横並びにViewを並べるレイアウト)を使って比較的自由なレイアウトができます。

struct TeamRow: View {

    var team: Team

    var body: some View {
        HStack {
            team.image
                .resizable()
                .frame(width: 50, height: 50)

            Text(team.name)

            Spacer()
        }
    }
}

struct TeamRow_Previews: PreviewProvider {
    static var previews: some View {

        Group {
            TeamRow(team: sampleTeams[0])
            TeamRow(team: sampleTeams[1])
        }
        .previewLayout(.fixed(width: 300, height: 70))
    }
}

SwiftUI公式
SwiftUIでつくったもの

4. まとめ

今年は多くの時間をiOS開発に使えたとは言い難いですが、自分なりにできる範囲でiOS開発を楽しみました🤗

多くの時間をiOSアプリ開発に注力できなかったとしても、一歩先へ行けるように来年も楽しんでアプリ開発します

この記事がどこかのiOSアプリ開発者の新しい一歩に役に立つことができたらとてもうれしいです!
お気軽にご意見やコメントください!