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

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

Yosuke Ishikawa
February 24, 2017
3.8k

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

Yosuke Ishikawa

February 24, 2017
Tweet

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() } }