Upgrade to Pro — share decks privately, control downloads, hide ads and more …

実践クライアントサイドSwift

Avatar for Yosuke Ishikawa Yosuke Ishikawa
February 24, 2017
4.3k

 実践クライアントサイドSwift

Avatar for Yosuke Ishikawa

Yosuke Ishikawa

February 24, 2017
Tweet

More Decks by Yosuke Ishikawa

Transcript

  1. struct FormField { let name: String let value: String func

    validate() throws {...} } 文字を入力するフィールド
  2. struct FormField<Value> { let name: String let value: Value func

    validate() throws {...} } 何を入力するフィールドにもなれる型
  3. protocol FormField { associatedtype Value var name: String { get

    } var value: Value { get } func validate() throws }
  4. struct StringFormField: FormField { let name: String let value: String

    let maxCharactersCount: Int func validate() throws { if value.isEmpty { throw FormFieldError( title: "未入力 項目 ", message: "\(name) 入力 ") } if value.characters.count > maxCharactersCount { throw FormFieldError( title: "文字数 ", message: "\(name) \(maxCharactersCount) } } } 文字を入力するフィールド
  5. struct SelectionFormField<Value>: FormField { let name: String let value: Value?

    func validate() throws { if value == nil { throw FormFieldError( title: "未選択 項目 ", message: "\(name) 選択 ") } } } 値を選択するフィールド
  6. let prefecture = Prefecture(id: 13, name: "東京都") let selectionFormField =

    SelectionFormField( name: 都道府県, value: prefecture) try selectionFormField.validate() let product = selectionFormField.value!
  7. let prefecture = Prefecture(id: 13, name: "東京都") let selectionFormField =

    SelectionFormField( name: 都道府県, value: prefecture) try selectionFormField.validate() let product = selectionFormField.value! バリデーションと値の取り出しが別々
  8. protocol FormField { associatedtype Value associatedtype Product var name: String

    { get } var value: Value { get } func buildProduct() throws -> Product } バリデーションと結果の取得を同時に行う
  9. struct SelectionFormField<Value>: FormField { let name: String let value: Value?

    func buildProduct() throws -> Value { guard let value = value else { throw FormFieldError( title: "未選択 項目 ", message: "\(name) 選択 ") } return value } } 修正版の値を選択するフィールド
  10. let prefecture = Prefecture(id: 13, name: "東京都") let selectionFormField =

    SelectionFormField( name: 都道府県, value: prefecture) let product = try selectionFormField.buildProduct() バリデーションと結果の取得が同時になった
  11. struct SignUpForm { let nameField: StringFormField let emailField: EmailFormField let

    prefectureFormField: SelectionFormField<Prefecture init(name: String, email: String, prefecture: Prefecture }
  12. struct SignUpForm: Form { let nameField: StringFormField let emailField: EmailFormField

    let prefectureFormField: SelectionFormField<Prefecture init(name: String, email: String, prefecture: Prefecture // SignUpRequest API 表 型 func buildProduct() throws -> SignUpRequest {...} }
  13. struct SignUpForm: Form { let nameField: StringFormField let emailField: EmailFormField

    let prefectureFormField: SelectionFormField<Prefecture init(name: String, email: String, prefecture: Prefecture // 全 // 組 立 同時 行 func buildProduct() throws -> SignUpRequest { return SignUpRequest( name: try nameField.buildProduct(), email: try emailField.buildProduct(), prefectureID: try prefectureFormField.buildProdu } }
  14. // 入力値 渡 let form = SignUpForm( name: nameTextField.text, email:

    emailTextField.text, prefecture: prefecturePickerView.selectedValue) do { sendRequest(try form.buildProduct()) } catch { // 発生 }
  15. protocol FormField { associatedtype FieldID associatedtype Value associatedtype Product var

    id: FieldID { get } var name: String { get } var value: Value { get } func buildProduct() throws -> Product } フィールドにFieldID を導入
  16. struct FormFieldError<FieldID> { let fieldID: FieldID let title: String let

    message: String } フィールドエラーにもFieldID を導入
  17. struct SignUpForm: Form { enum FieldID { case name case

    email case prefecture } let nameField: StringFormField<FieldID> let emailField: EmailFormField<FieldID> let prefectureField: SelectionFormField<FieldID, Prefect init(name: String, email: String, prefecture: Prefecture ... } }
  18. struct SignUpForm: Form { ... init(name: String, email: String, prefecture:

    Prefecture nameField = StringFormField( id: .name, name: " 名", value: name, maxCharactersCount: 20) emailField = EmailFormField( id: .email, name: " ", value: email) prefectureField = SelectionFormField( id: .prefecture, name: " 住 都道府県", value: prefecture) } }
  19. let form = SignUpForm( name: nameTextField.text, email: emailTextField.text, prefecture: prefecturePickerView.selectedValue)

    do { sendRequest(try form.buildProduct()) } catch let error as FormFieldError<SignUpForm.FieldID> { switch error.fieldID { case .name: nameTextField.becomeFirstResponder() case .email: emailTextField.becomeFirstResponder() case .prefecture: pushPrefectureViewController() } } catch { // 来 }
  20. let form = SignUpForm( name: nameTextField.text, email: emailTextField.text, prefecture: prefecturePickerView.selectedValue)

    do { sendRequest(try form.buildProduct()) } catch let error as FormFieldError<SignUpForm.FieldID> { // ↑ 型 存在 気 難 } catch { // 何 ... }
  21. protocol Form { associatedtype FieldID associatedtype Product // ↓ 時点

    型 失 func buildProduct() throws -> Product }
  22. protocol FormField { associatedtype FieldID associatedtype Value associatedtype Product var

    id: FieldID { get } var name: String { get } var value: Value { get } func buildProduct() -> Result<Product, FormFieldError<FieldID>> }
  23. struct SignUpForm: Form { let nameField: StringFormField let emailField: EmailFormField

    let prefectureFormField: SelectionFormField<Prefecture ... func buildProduct() throws -> SignUpRequest { return SignUpRequest( name: try nameField.buildProduct(), email: try emailField.buildProduct(), prefectureID: try prefectureFormField.buildProdu } } try の場合
  24. struct SignUpForm: Form { let nameField: StringFormField let emailField: EmailFormField

    let prefectureFormField: SelectionFormField<Prefecture ... func buildProduct() -> Result<SignUpRequest, FormFieldError<FieldID let nameResult = nameField.buildProduct() let emailResult = emailField.buildProduct() let prefectureResult = prefectureFormField.buildProd // 3 楽 組 合 ... } } の場合
  25. struct SignUpForm: Form { let nameField: StringFormField let emailField: EmailFormField

    let prefectureFormField: SelectionFormField<Prefecture ... func buildProduct() -> Result<SignUpRequest, FormFieldError<FieldID // Curry, Runes 使 Haskell return curry(SignUpRequest.init) <^> nameField.buildProduct() <*> emailField.buildProduct() <*> prefectureField.buildProduct() } }
  26. let form = SignUpForm( name: nameTextField.text, email: emailTextField.text, prefecture: prefecturePickerView.selectedValue)

    // case 消 switch form.buildProduct() { case .success(let request): sendRequest(request) case .failure(let error): switch error.fieldID { case .name: nameTextField.becomeFirstResponder() case .email: emailTextField.becomeFirstResponder() case .prefecture: pushPrefectureViewController() } }