Slide 1

Slide 1 text

Translatorͷεεϝ potatotips #36 / @nonchalant0303

Slide 2

Slide 2 text

Profile • Takeshi Ihara / @nonchalant0303 • Recruit Marketing Partners • iOS Engineer

Slide 3

Slide 3 text

Translator • UseCaseͰऔಘͨ͠EntityΛPresentation૚ͷ ͨΊͷModelʹม׵͢Δ 1SFTFOUBUJPO %PNBJO *OGSBTUSVDUVSF 6TF$BTF 5SBOTMBUPS 7JFX.PEFM

Slide 4

Slide 4 text

Entity w/o Translator struct Entity { let title: String let description: String let imageUrl: URL let rank: Rank init(title: String, description: String, imageUrl: String, rank: Int) { self.title = title self.description = description self.imageUrl = URL(string: imageUrl)! self.rank = Rank(rank: rank) } }

Slide 5

Slide 5 text

Entity w/o Translator struct Entity { let title: String let description: String let imageUrl: URL let rank: Rank init(title: String, description: String, imageUrl: String, rank: Int) { self.title = title self.description = description self.imageUrl = URL(string: imageUrl)! self.rank = Rank(rank: rank) } } *OJUJBMJ[FSʹ ม׵ϩδοΫؚ͕·ΕͯΔ

Slide 6

Slide 6 text

ผʹ͍͍ͷͰ͸ʁ

Slide 7

Slide 7 text

ͨͱ͑͹… import Foundation struct Entity { let property1: String let property2: Float ... let property15: [String] init(property1: Int, property2: Int, property15: [Int]) { self.property1 = "\(property1)ԁ" self.property2 = Float(property2) * 1.08 ... self.property15 = property15.map { "\($0)ԁ" } } }

Slide 8

Slide 8 text

ͨͱ͑͹… import Foundation struct Entity { let property1: String let property2: Float ... let property15: [String] init(property1: Int, property2: Int, property15: [Int]) { self.property1 = "\(property1)ԁ" self.property2 = Float(property2) * 1.08 ... self.property15 = property15.map { "\($0)ԁ" } } } ཁૉ͕૿͑Δͱ ม׵ϩδοΫ͕ංେԽ͕ͪ͠

Slide 9

Slide 9 text

class TableViewCell: UITableViewCell { @IBOutlet private weak var label1: UILabel! @IBOutlet private weak var label2: UILabel! ... @IBOutlet private weak var label15: UILabel! func configure(entity: Entity) { label1.text = "\(entity.property1)ԁ" label2.text = "\(Float(entity.property2) * 1.08)" ... label15.text = entity.property15.map { "\($0)ԁ" }.reduce("") { $0 != "" ? "\($0), \($1)" : "\($1)" } } } 1. Translate in View

Slide 10

Slide 10 text

class TableViewCell: UITableViewCell { @IBOutlet private weak var label1: UILabel! @IBOutlet private weak var label2: UILabel! ... @IBOutlet private weak var label15: UILabel! func configure(entity: Entity) { label1.text = "\(entity.property1)ԁ" label2.text = "\(Float(entity.property2) * 1.08)" ... label15.text = entity.property15.map { "\($0)ԁ" }.reduce("") { $0 != "" ? "\($0), \($1)" : "\($1)" } } } 1. Translate in View 7JFXʹϩδοΫ͕ છΈग़ͯ͠Δ

Slide 11

Slide 11 text

struct Entity { let property1: String let property2: Int ... let property15: [String] } struct ViewModel { let property1: String let property2: String ... let property15: String } class Translator { static func translate(entity: Entity) -> ViewModel { return ViewModel( property1: "\(entity.property1)ԁ", property2: "\(Float(entity.property2) * 1.08)", ... property15: entity.property15.map { "\($0)ԁ" }.reduce("") { $0 != "" ? "\($0), \($1)" : "\($1)" } ) } } 2. Translator

Slide 12

Slide 12 text

struct Entity { let property1: String let property2: Int ... let property15: [String] } struct ViewModel { let property1: String let property2: String ... let property15: String } class Translator { static func translate(entity: Entity) -> ViewModel { return ViewModel( property1: "\(entity.property1)ԁ", property2: "\(Float(entity.property2) * 1.08)", ... property15: entity.property15.map { "\($0)ԁ" }.reduce("") { $0 != "" ? "\($0), \($1)" : "\($1)" } ) } } 2. Translater 1SFTFOUBUJPO૚ͷͨΊͷ .PEFMΛ༻ҙ͢Δ 5SBOTMBUPS

Slide 13

Slide 13 text

2. Translator class Repository { func findAll() -> [Entity] { return ... } } class UseCase { let repository: Repository init(repository: Repository) { self.repository = repository } func getAll() -> [ViewModel] { return repository.findAll().map { Translator.translate(entity: $0) } } } UseCaseͰऔಘͨ͠EntityΛPresentation૚ͷͨΊͷModelʹม׵͢Δ

Slide 14

Slide 14 text

2. Translater class Repository { func findAll() -> [Entity] { return ... } } class UseCase { let repository: Repository init(repository: Repository) { self.repository = repository } func getAll() -> [ViewModel] { return repository.findAll().map { Translator.translate(entity: $0) } } } UseCaseͰऔಘͨ͠EntityΛPresentation૚ͷͨΊͷModelʹม׵͢Δ &OUJUZΛ.PEFMʹม׵͢Δ

Slide 15

Slide 15 text

View, Entity͔Β
 ม׵ϩδοΫΛ෼཭Ͱ͖ͨʂ

Slide 16

Slide 16 text

Pros/Cons of Translator • Pros • ม׵ϩδοΫΛ෼཭Ͱ͖Δ • Cons • ৑௕ʹͳΓ͔Ͷͳ͍

Slide 17

Slide 17 text

ඞཁʹԠͯ͡TranslatorΛ ಋೖ͠Α͏ʂ

Slide 18

Slide 18 text

Translator͕༗ޮͩͱࢥ͏ྫ • UITableViewʹ
 දࣔ͢ΔΞΠςϜ਺͕ ʮEntityͷ਺+1ʯ

Slide 19

Slide 19 text

ViewController w/o Translator class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { private let tableView = UITableView(frame: UIScreen.main.bounds) var todos: [Todo] = [] // Entity override func viewDidLoad() { ... } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return todos.count + 1 } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = UITableViewCell() if indexPath.row < todos.count { cell.textLabel?.text = todos[indexPath.row].title } else { cell.textLabel?.text = "+ ௥Ճ͢Δ" cell.textLabel?.textColor = .gray } return cell } }

Slide 20

Slide 20 text

ViewController w/o Translator class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { private let tableView = UITableView(frame: UIScreen.main.bounds) var todos: [Todo] = [] // Entity override func viewDidLoad() { ... } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return todos.count + 1 } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = UITableViewCell() if indexPath.row < todos.count { cell.textLabel?.text = todos[indexPath.row].title } else { cell.textLabel?.text = "+ ௥Ճ͢Δ" cell.textLabel?.textColor = .gray } return cell } } *OEFY1BUIͰ؅ཧͯͯ͠πϥΠ 3VOUJNFFSSPSͷϦεΫ

Slide 21

Slide 21 text

Translate from Entity to Model protocol Translator { associatedtype Entity associatedtype Model static func translate(entity: Entity) -> Model } struct Todo { let title: String } enum Item { case todo(title: String) case add(title: String) } class TodoTranslator: Translator { typealias Entity = [Todo] typealias ViewModel = [Item] static func translate(entity: Entity) -> ViewModel { return Array( [ entity.map { Item.todo(title: $0.title) }, [ Item.add(title: "+ ௥Ճ͢Δ") ] ].joined() ) } }

Slide 22

Slide 22 text

Translate from Entity to Model protocol Translator { associatedtype Entity associatedtype Model static func translate(entity: Entity) -> Model } struct Todo { let title: String } enum Item { case todo(title: String) case add(title: String) } class TodoTranslator: Translator { typealias Entity = [Todo] typealias ViewModel = [Item] static func translate(entity: Entity) -> ViewModel { return Array( [ entity.map { Item.todo(title: $0.title) }, [ Item.add(title: "+ ௥Ճ͢Δ") ] ].joined() ) } } $FMM༻ͷ.PEFM 5BCMF7JFXදࣔ͢Δ ΞΠςϜΛ͢΂ͯ༻ҙ

Slide 23

Slide 23 text

ViewController w/ Translator class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { private let tableView = UITableView(frame: UIScreen.main.bounds) var items: [Item] = [] // Model override func viewDidLoad() { ... } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return items.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = UITableViewCell() switch items[indexPath.row] { case .todo(let title): cell.textLabel?.text = title case .add(let title): cell.textLabel?.text = title cell.textLabel?.textColor = .gray } return cell } }

Slide 24

Slide 24 text

ViewController w/ Translator class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { private let tableView = UITableView(frame: UIScreen.main.bounds) var items: [Item] = [] // Model override func viewDidLoad() { ... } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return items.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = UITableViewCell() switch items[indexPath.row] { case .todo(let title): cell.textLabel?.text = title case .add(let title): cell.textLabel?.text = title cell.textLabel?.textColor = .gray } return cell } } ܕͰ؅ཧ͞ΕͯΔͷͰ ҆શʂ

Slide 25

Slide 25 text

͋Γ͕ͱ͏͍͟͝·ͨ͠