だいたい死んでる

渋谷で働いているWEBプログラマーです。

SwiftUIでMVVM

この記事は ウィルゲート Advent Calendar 2019 の22日目の記事です。

ConbainとSwiftUIが登場したことで、データバインディングの仕組みを公式がサポートしました。 サンプルとしてMVVMでアプリを作ってみようと思います。

作るアプリ

天気を一覧で見れるアプリを作ってみる。 天気情報取得には以下のAPIを使用しました。

openweathermap.org

ディレクトリ構成について

app
- View
- ViewModel
- Model

上表のように各役割によってディレクトリを分ける。 役割ごとに依存の方向は下図のようにしていきます。

f:id:MikaE:20191216000004p:plain

Viewについて

ユーザーへ機能を提供するために描画を担当します。また、ユーザーからの入力を受け取りViewModelへ渡します。 またViewModelのデータとデータバインディングすることでデータの変更と描画の変更を同期させます。

ViewModelについて

Viewを描画するための状態の保持と、Viewから受け取った入力を適切な形に変換してModelに伝達する役目を持っています。 Viewとの通信はデータバインディングの機構を使って行われます。

Modelについて

アプリケーションのドメインを持つのがModelです。ビジネスロジックを書くところになります。また、データの永続化を行う箇所でもあります。

コードについての説明

Model

APIのレスポンス値からCodableのコードを作成してくれる、quicktypeを使用して自動生成できます。 自動生成したので基本的に何も変えずに使用します。

// MARK: - Weathers
struct Weathers: Codable {
    let coord: Coord
    let weather: [Weather]
    let base: String
    let main: Main
    let visibility: Int
    let wind: Wind
    let clouds: Clouds
    let dt: Int
    let sys: Sys
    let id: Int
    let name: String
    let cod: Int
}

// MARK: - Clouds
struct Clouds: Codable {
    let all: Int
}

// MARK: - Coord
struct Coord: Codable {
    let lon, lat: Double
}

// MARK: - Main
struct Main: Codable {
    let temp: Double
    let pressure, humidity: Int
    let tempMin, tempMax: Double

    enum CodingKeys: String, CodingKey {
        case temp, pressure, humidity
        case tempMin = "temp_min"
        case tempMax = "temp_max"
    }
}

// MARK: - Sys
struct Sys: Codable {
    let type, id: Int
    let message: Double
    let country: String
    let sunrise, sunset: Int
}

// MARK: - Weather
struct Weather: Codable {
    let id: Int
    let main, weatherDescription, icon: String

    enum CodingKeys: String, CodingKey {
        case id, main
        case weatherDescription = "description"
        case icon
    }
}

// MARK: - Wind
struct Wind: Codable {
    let speed: Double
    let deg: Int
}

ViewModel

データをAPIから取得する処理とModelの型に合わせて変数へ格納する処理を書いていきます。 また、Viewへデータバインドしたいので、PassthroughSubjectとObservableObjectを使用してバインドするための準備もしています。

class WeatherViewModel: Identifiable {
    
    let id = UUID()
    
    let weather: Weather
    
    init(weather: Weather) {
        self.weather = weather
    }
    
    var main: String {
        return self.weather.main
    }
}

class WeathersViewModel: ObservableObject {
    
   let didChange = PassthroughSubject<MemosViewModel,Never>()
    
    init() {
        fetchTopHeadlines()
    }
    
    var weathers = [MemoViewModel]() {
        didSet {
            didChange.send(self)
        }
    }
    
    private func fetchTopHeadlines() {
        let apKey = ""
        let baseURL = "https://samples.openweathermap.org/data/2.5/weather?q=London,uk&appid="
        guard let url = URL(string: baseURL + apKey) else {
            fatalError("URL is not correct!")
        }
        
        ApiCommon().loadTopHeadlines(url: url) { weathers in
            
            if let weathers = weathers {
                self.weathers = weathers.map(MemoViewModel.init)
            }
            
        }
        
    }
}

ViewModelをからデータをバインドするためObservedObjectを使用してオブザーバーを使用できるようにします。 こうすることでデータが変更されると自動的にViewが更新されるようになります。

View

import SwiftUI

struct WeathersView: View {
    @ObservedObject var model = WeathersViewModel()
    
    var body: some View {
        List(model.weathers) { weather in
            Text(weather.main)
        }
    }
}

struct MemoView_Previews: PreviewProvider {
    static var previews: some View {
        MemoView()
    }
}

まとめ

SwiftUIを使うことでこれまでよりも簡単にMVVMの実装をすることが出来ました。 その他のアーキテクチャについても実装をしてみます。

明日はcuresevenさんで、『アドベントカレンダー戦略』です。 お楽しみに!

netdataのメモ

isuconのとき毎回調べるので、netdataのメモを自分用に貼っておきます。

netdataとは

github.com

Netdata is distributed, real-time, performance and health monitoring for systems and applications. It is a highly optimized monitoring agent you install on all your systems and containers.

Netdataはシステムの監視を行うためのアプリケーションです。すべてのシステムのコンテナにインストールすることができます。

Netdata provides unparalleled insights, in real-time, of everything happening on the systems it runs (including web servers, databases, applications), using highly interactive web dashboards. It can run autonomously, without any third party components, or it can be integrated to existing monitoring tool chains (Prometheus, Graphite, OpenTSDB, Kafka, Grafana, etc).

Netdataは、インタラクティブなWebダッシュボードを使用して、実行中のシステムで発生するすべてのリアルタイムで監視することが出来ます。 サードパーティコンポーネントなしで実行され、既存の監視ツール(Prometheus、Graphite、OpenTSDB、Kafka、Grafanaなど)に統合することもできます。

 以下みたいな画面を作れる。 f:id:MikaE:20191217105034p:plain

使い方

ドキュメントを見たほうがいいのでドキュメントを貼ります。

GitHub - netdata/netdata

 導入方法

bash <(curl -Ss https://my-netdata.io/kickstart.sh)
systemctl status netdata.service

1999ポートを開ける http://Host:1999で見ることができる

止める

systemctl stop netdata.service

動かす

systemctl start netdata.service

SwiftUIについて調べたこと

この記事は ウィルゲート Advent Calendar 2019 の17日目の記事です。

最近業務でSwiftを触ることがなくなり少しさみしいのでSwiftUIについて調べたことをまとめていきます。

SwiftUIの登場まで

iOS SDKの登場以降、iOSアプリのViewを開発する場合はAppleが提供しているUIフレームワークのUIKitを使用してきました。このフレームワークを使用することで、簡単にViewを組み立てることができました。 ただUIKitで作られたアプリはViewControllerに処理が集まっていることが多く、FatViewController になることが多くありました。

問題を解消するため、開発者はMVVM,Viper,クリーンアーキテクチャなどの設計を取り入れてアプリを開発してきました。 2019年WWDCで宣言的にViewを組み立てる仕組みとしてのSwiftUIが発表されました。 SwiftUIの登場によりアプリ開発がどう変わるかをまとめていきます。

SwiftUIとUIkitの違い

UIKit SwiftUI
アーキテクチャ イベント駆動 状態駆動
イベント処理 コールバック,デリゲート クロージャーコールバック

SwiftUIとUIKitの大きな違いは、構文が変わったこと以外に、Viewに状態をもたせることができるようになったことです。 アプリ開発では複雑な状態を扱う事が多く、状態どこで管理しどう扱うかに頭を悩ませることが多くありました。 状態を管理する方法として、AppleはCombineをSwiftUIと同時に発表しました。 CombineはViewへ状態をバインドするための仕組みを提供しています。またViewの中で状態を管理することができるようになりました。 SwiftUIとCombineを使用することで状態の管理が簡単になると思います。

WWDCのセッションではユーザーのアクションをViewへ伝えていくためにどうするか説明がされています。 興味がある人は見てみるといいと思います。 f:id:MikaE:20191212123119p:plain

アーキテクチャについて

SwiftUIとCombineを使用することにより画面の状態をViewに持たせることが出来ます。またデータバインドの仕組みを標準でサポートしているため、MVVMアーキテクチャを使用して作成することが簡単になりました。@Publishedや@Stateような属性や@ObservableObjectを使用しViewModelを作ることが出来ます。

まとめ

SwiftUIはまだまだ登場したばかりで資料がすくないため導入は難しいかもしれません。今後も動向を追っていきたいと思います。

明日はokashoiさんで、『PHP + Swoole で論理回路シミュレータを作ってみた(仮)』です。 お楽しみに!

参考資料

developer.apple.com

developer.apple.com

developer.apple.com

developer.apple.com

若手エンジニアで振り返り会をやった

若手エンジニアが集まって振り返り会を行いました。

今後どういったキャリアを描きたいのかやどういった成長をしてきたかをまとめることを目的に行いました。

やったこと

  • 2時間くらい個人でモクモク振り返り

  • 2時間くらいで振り返ったことを共有

雑に発表した人まとめ

覚えてることを雑多に書きます

アッキー (@akki_megane) | Twitter

  • ISUCON優勝

02 (@cocoeyes02) | Twitter

  • 推進力が足らないので自信を持って推進する

しょーぞー (@shozo_ms) | Twitter

  • アウトプット少ないのでアウトプットする

ぴんくもひかん (@pinkumohikan) | Twitter

  • Railsでサービス作ってみる

おかしょい@アーキテクト 兼 技術広報 (@okashoi) | Twitter

  • プライベートが充実

広高@エンジニア兼プレゼン講師 (@yutanpo_it) | Twitter

  • 深く学びたいことを探したい

キュアセブン (@cureseven) | Twitter

  • 強くなりたい

for_3 | ZOE (@for__3) | Twitter

  • 身近な人を救うようなアウトプットをするためにどうするかを考える
  • ISUCON予選突破できなかったらユニセフ

ShuzoN@webエンジニアとヘッドホン (@ShuzoN__) | Twitter

  • 本をめっちゃ読んだ

振り返って

  • 個人的にはインプットを多くできていたと感じている
  • アウトプットが少なかったので今後は少しでも増やしていきたい

iOSで該当のViewControllerが生成されているかを確認する関数を作る

最近暖かくなったり寒くなったりするので体調を崩し気味ですがなんとか気合で乗り越えています。 業務はいい感じなのでいい感じです。

最近iOSを書いていてバックグラウンドで描画している画面を検索したいことがありなんとか実装したのでメモとして残します。

import Foundation
import UIKit

extension UIViewController {
    /**
     * ViewControllerが子や孫に存在する場合はそのViewControllerを返す
     */
    func findChildren<T:UIViewController>(kind:T.Type?) -> T? {
        if let viewControler = self as? T {
            return viewControler
        }
        if let viewControler = self.presentedViewController as? T {
            return viewControler
        }
        if let viewControlers = self.presentedViewController?.children {
            return viewControlers.compactMap{$0.findChildren(kind: kind)}.first
        }
        return nil
    }
}

いい感じにかけた気がするのですが、急いで書いたので抜けてる部分とかありそう。 ご利用は計画的に。

Codableで使える構造体をJsonから自動生成してくれる便利拡張

最近業務でSwiftを書くことが多くなり(ここ6ヶ月はほぼSwift)わからないことだらけで右往左往しています。

業務ではAPIとのやり取りを行うことが多くSwift4から追加されたCodableを使用してJsonの整形を行っています。Codableを利用するときはAPIのレスポンスに合った構造体の定義する必要があり、APIごとに定義していくことが面倒になっていました。

 

そんなときXcodeの便利そうな拡張を見つけました。

github.com

この拡張を使うと、Jsonの構造からCodableで使える構造体を自動的に生成してくれます。

 

f:id:MikaE:20181014175659g:plain

便利そう

導入(メモ)

  1. Alcatrazで入れられそうと思った
  2. f:id:MikaE:20181014182613p:plain
    アーカイブされてた・・・
    読み取ることはできるけどこれって入れていいの?

  3. speakerdeck.coし

    少し調べてみたら良さそうな資料が出てきた。この資料を見たところ一旦.appを生成すれば導入できるよって書いてありました。なのでソースコードを落としてきてArchiveする。
  4. Archiveした結果を「アプリケーション」ディレクトリに入れる。
  5. システム環境設定から拡張機能を開き有効化することで使用できます。

    f:id:MikaE:20181016125830p:plain

  6. 有効化後xcodeを再起動することで機能をしようるることができました。

まとめ

いろいろ調べて便利な拡張機能を使っていきたい。

 

アプリケーションアーキテクチャ設計パターン【目次】

本を読む習慣をつけるために、少しずつ読んだ内容をブログとしてまとめていきたいと思います。

1冊目は、「アプリケーションアプリケーションアーキテクチャ設計パターン」についてまとめていきます。

この本を読む理由は、アーキテクチャって何なんだろうと疑問に思ったことと、いざ業務でやることがあったときに少しでも困らないようにしようと思ったからです。

まとめたブログ記事は、この記事からリンクさせていきます。

目次

  • 第1章 アプリケーションアーキテクチャとは
  • 第2章 エンタープライズアプリケーションの共通概念と処理形態
  • 第3章 エンタープライズアプリケーションの機能配置とレイヤ化
  • 第4章 プレゼンテーション層の設計パターン
  • 第5章 インスタンスの生成や構造に関する設計パターン
  • 第6章 ビジネス層の設計パターン
  • 第7章 トランザクション管理とデータ整合性確保のための設計パターン
  • 第8章 データアクセス層の設計パターン
  • 第9章 検証と例外のための設計パターン
  • 第10章 非同期呼び出しと並列処理のための設計パターン
  • 第11章 その他のアーキテクチャパターン
  • 第12章 クライアントサイドのアーキテクチャ概要
  • 第13章 Webページの設計パターン
  • 第14章 シングルページアプリケーションの設計パターン
  • 第15章 バッチ処理の概要
  • 第16章 オフラインバッチアプリケーションの設計パターン
  • 第17章 オンラインバッチとディレードオンラインの設計パターン
  • 第18章 ビッグデータ技術による分散並列バッチ処理
  • 第19章 システム間連携の概要
  • 第20章 アプリケーション連携の設計パターン
  • 第21章 メッセージングの設計パターン
アプリケーションアーキテクチャ設計パターン

アプリケーションアーキテクチャ設計パターン