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

How we build our app with minimum 3rd party dependencies

How we build our app with minimum 3rd party dependencies

bitFlyer Drink Meetup for iOSエンジニア 登壇資料
https://bitflyer.connpass.com/event/100661

horimislime

October 04, 2018
Tweet

More Decks by horimislime

Other Decks in Programming

Transcript

  1. bitFlyer Wallet • ೔ຊ࠷େͷԾ૝௨՟औҾॴ  CJU'MZFSͷJ04޲͚ΞϓϦ • ೥͔Β։ൃ։࢝ • ίʔυϕʔε͸ສߦ௒

    *1 ௐࠪҕୗઌϚΫϩϛϧʢ2018 ೥ 2 ݄ɺΠϯλʔωοτௐࠪʮԾ૝௨՟ɾ҉߸௨՟औҾ
 αʔϏεʹؔ͢ΔΞϯέʔτʯʣɺBitcoin ೔ຊޠ৘ใαΠτௐ΂ɻ 2016 ೥ 4݄-2018 ೥ 4 ݄ɺࠃ಺औҾॴͷ૯݄ؒग़དྷߴʢݱ෺/ܾࠩۚࡁ/ઌ෺औҾΛؚΉʣ
  2. 1. UITableViewͷѻ͍ʹ͘͞ • ࣌୅͸એݴతUITableView / CollectionViewઓࠃ࣌୅ʁ • RxDataSources Λ࢝ΊɺiOSDCͰ΋࿩୊ʹ •

    ܾఆతͳఆ൪͸·ͩͳ͘ɺͦΕͧΕҰ௕Ұ୹ΞϦ • ѻ͍΍͢͞ͱҾ͖׵͑ʹύϥμΠϜ่յ͕ى͜Δ
  3. ബ͍ϑϨʔϜϫʔΫͷ࣮૷ final class HistoryViewController: UIViewController {
 @IBOutlet private weak var

    tableView: UITableView!
 private var entities = [History]() private let dataSource = TableDataSource() private let entitiesProvider = EntitiesProvider<History>() override func viewDidLoad() { super.viewDidLoad() dataSource.mapper.register("HistoryCell") { (cell: HistoryCell, entity: History) in cell.update(with: entity) } dataSource.provider = entitiesProvider tableView.dataSource = dataSource tableView.delegate = self fetchData() }
  4. ബ͍ϑϨʔϜϫʔΫͷ࣮૷ final class HistoryViewController: UIViewController {
 @IBOutlet private weak var

    tableView: UITableView!
 private var entities = [History]() private let dataSource = TableDataSource() private let entitiesProvider = EntitiesProvider<History>() override func viewDidLoad() { super.viewDidLoad() dataSource.mapper.register("HistoryCell") { (cell: HistoryCell, entity: History) in cell.update(with: entity) } dataSource.provider = entitiesProvider tableView.dataSource = dataSource tableView.delegate = self fetchData() } EntitiesProvider: ίϯςϯπҰཡͷϚωʔδ TableDataSource: UITableViewDataSourceʹ४ڌ
 Provider -> TableView΁ͷڮ౉͠
  5. ബ͍ϑϨʔϜϫʔΫͷ࣮૷ final class HistoryViewController: UIViewController {
 @IBOutlet private weak var

    tableView: UITableView!
 private var entities = [History]() private let dataSource = TableDataSource() private let entitiesProvider = EntitiesProvider<History>() override func viewDidLoad() { super.viewDidLoad() dataSource.mapper.register("HistoryCell") { (cell: HistoryCell, entity: History) in cell.update(with: entity) } dataSource.provider = entitiesProvider tableView.dataSource = dataSource tableView.delegate = self fetchData() } EntitiesProvider: ίϯςϯπҰཡͷϚωʔδ TableDataSource: UITableViewDataSourceʹ४ڌ
 Provider -> TableView΁ͷڮ౉͠
  6. ബ͍ϑϨʔϜϫʔΫͷ࣮૷ final class HistoryViewController: UIViewController {
 @IBOutlet private weak var

    tableView: UITableView!
 private var entities = [History]() private let dataSource = TableDataSource() private let entitiesProvider = EntitiesProvider<History>() override func viewDidLoad() { super.viewDidLoad() dataSource.mapper.register("HistoryCell") { (cell: HistoryCell, entity: History) in cell.update(with: entity) } dataSource.provider = entitiesProvider tableView.dataSource = dataSource tableView.delegate = self fetchData() } reloadData()ͨ͠Βclosure͕ݺ͹ΕΔ (cellForRowAt૬౰)
  7. CellΛ࠶ར༻͠ͳ͍γϯϓϧͳTableView࣮૷ final class InputFormViewController: UIViewController { private lazy var userNameCell:

    TextFieldCell = { ... }() private lazy var preferenceCell: SwitchCell = { ... }()
 private lazy var rows: [UITableViewCell] = { 
 [userNameCell, preferenceCell] }() @IBAction private func doneTapped() { API.send( name: userNameCell.textField.text, preference: preferenceCell.toggle.isOn ) } }
 
 extension InputFormViewController: UITableViewDataSource {
 func tableView(…, cellForRowAt indexPath: IndexPath) -> UITableViewCell { return rows[indexPath.row] } }
  8. CellΛ࠶ར༻͠ͳ͍γϯϓϧͳTableView࣮૷ final class InputFormViewController: UIViewController { private lazy var userNameCell:

    TextFieldCell = { ... }() private lazy var preferenceCell: SwitchCell = { ... }()
 private lazy var rows: [UITableViewCell] = { 
 [userNameCell, preferenceCell] }() @IBAction private func doneTapped() { API.send( name: userNameCell.textField.text, preference: preferenceCell.toggle.isOn ) } }
 
 extension InputFormViewController: UITableViewDataSource {
 func tableView(…, cellForRowAt indexPath: IndexPath) -> UITableViewCell { return rows[indexPath.row] } }
  9. CellΛ࠶ར༻͠ͳ͍γϯϓϧͳTableView࣮૷ final class InputFormViewController: UIViewController { private lazy var userNameCell:

    TextFieldCell = { ... }() private lazy var preferenceCell: SwitchCell = { ... }()
 private lazy var rows: [UITableViewCell] = { 
 [userNameCell, preferenceCell] }() @IBAction private func doneTapped() { API.send( name: userNameCell.textField.text, preference: preferenceCell.toggle.isOn ) } }
 
 extension InputFormViewController: UITableViewDataSource {
 func tableView(…, cellForRowAt indexPath: IndexPath) -> UITableViewCell { return rows[indexPath.row] } }
  10. CellΛ࠶ར༻͠ͳ͍γϯϓϧͳTableView࣮૷ final class InputFormViewController: UIViewController { private lazy var userNameCell:

    TextFieldCell = { ... }() private lazy var preferenceCell: SwitchCell = { ... }()
 private lazy var rows: [UITableViewCell] = { 
 [userNameCell, preferenceCell] }() @IBAction private func doneTapped() { API.send( name: userNameCell.textField.text, preference: preferenceCell.toggle.isOn ) } }
 
 extension InputFormViewController: UITableViewDataSource {
 func tableView(…, cellForRowAt indexPath: IndexPath) -> UITableViewCell { return rows[indexPath.row] } } ֤Form Cell͸໊લͷࢀরΛ͍࣋ͬͯΔ ௚઀UIύʔπ͕͍࣋ͬͯΔσʔλΛݟʹ͍͘
  11. 3. Style΍
 ComponentͷऔΓѻ͍ • 5FYU $PMPSͳͲ޿ൣғʹӨڹ • /4"UUSJCVUFE4USJOH΍ 6*4UPSZCPBSE͕ΠϚΠν •

    ඪ४4%,͕ؤுͬͯ΄͍͠ • 044΋๲େͳ਺ ग़యWTPV[BBXFTPNFJPTUFYU
  12. Color Paletteͷ࣮૷ extension UIColor { private static func bf_blueColor() ->

    UIColor { return UIColor(red: 0.26, green: 0.52, blue: 0.75, alpha: 1.0) } private static func bf_lightBlueColor() -> UIColor { return UIColor(red: 0.16, green: 0.64, blue: 0.89, alpha: 1.0) } …
 static func primaryColor() -> UIColor { return bf_blueColor() } static func secondaryTextColor() -> UIColor { return bf_grayColor() } … }
  13. Color Paletteͷ࣮૷ extension UIColor { private static func bf_blueColor() ->

    UIColor { return UIColor(red: 0.26, green: 0.52, blue: 0.75, alpha: 1.0) } private static func bf_lightBlueColor() -> UIColor { return UIColor(red: 0.16, green: 0.64, blue: 0.89, alpha: 1.0) } …
 static func primaryColor() -> UIColor { return bf_blueColor() } static func secondaryTextColor() -> UIColor { return bf_grayColor() } … }
  14. Color Paletteͷ࣮૷ extension UIColor { private static func bf_blueColor() ->

    UIColor { return UIColor(red: 0.26, green: 0.52, blue: 0.75, alpha: 1.0) } private static func bf_lightBlueColor() -> UIColor { return UIColor(red: 0.16, green: 0.64, blue: 0.89, alpha: 1.0) } …
 static func primaryColor() -> UIColor { return bf_blueColor() } static func secondaryTextColor() -> UIColor { return bf_grayColor() } … } ΞϓϦ಺Ͱ࢖͏৭
  15. Color Paletteͷ࣮૷ extension UIColor { private static func bf_blueColor() ->

    UIColor { return UIColor(red: 0.26, green: 0.52, blue: 0.75, alpha: 1.0) } private static func bf_lightBlueColor() -> UIColor { return UIColor(red: 0.16, green: 0.64, blue: 0.89, alpha: 1.0) } …
 static func primaryColor() -> UIColor { return bf_blueColor() } static func secondaryTextColor() -> UIColor { return bf_grayColor() } … }
  16. Color Paletteͷ࣮૷ extension UIColor { private static func bf_blueColor() ->

    UIColor { return UIColor(red: 0.26, green: 0.52, blue: 0.75, alpha: 1.0) } private static func bf_lightBlueColor() -> UIColor { return UIColor(red: 0.16, green: 0.64, blue: 0.89, alpha: 1.0) } …
 static func primaryColor() -> UIColor { return bf_blueColor() } static func secondaryTextColor() -> UIColor { return bf_grayColor() } … } ίϯςΩετͷఆٛ
  17. Text Stylesͷ࣮૷ class TextStyle { let styleName: String // ελΠϧ໊

    var size: CGFloat // ϑΥϯταΠζ var color: UIColor // จࣈͷ৭ enum Weight { case thin, normal, bold } var weight: Weight // จࣈͷଠ͞ var textAlignment: NSTextAlignment // จࣈἧ͑ var kern: CGFloat // จࣈؒͷڑ཭ enum FontType { case proportional, monospaced, compact, monospacedCompact } var fontType: FontType // ϑΥϯτͷछྨ ...
  18. Text Stylesͷ࣮૷ extension TextStyle { static var body: TextStyle {

    return TextStyle("body", size: 17, color: UIColor.primaryTextColor(), weight: .normal, textAlignment: .left, kern: 0.2) } ... }
  19. Text Stylesͷ࣮૷ extension TextStyle { static var body: TextStyle {

    return TextStyle("body", size: 17, color: UIColor.primaryTextColor(), weight: .normal, textAlignment: .left, kern: 0.2) } ... }
  20. Text Stylesͷ࣮૷ extension TextStyle { static var body: TextStyle {

    return TextStyle("body", size: 17, color: UIColor.primaryTextColor(), weight: .normal, textAlignment: .left, kern: 0.2) } ... }
  21. Text Styleͷద༻ extension NSAttributedString { convenience init(string str: String, style:

    TextStyle, 
 tweak: (_ builder: TextStyle) -> Void) { tweak(style) self.init(string: str, attributes: style.build()) } } message.text = NSAttributedString(string: "Hello!", style: .body) name.text = NSAttributedString(string: "Taro", style: .body) { tweak in tweak.color = UIColor.secondaryTextColor() }
  22. Text Styleͷద༻ extension NSAttributedString { convenience init(string str: String, style:

    TextStyle, 
 tweak: (_ builder: TextStyle) -> Void) { tweak(style) self.init(string: str, attributes: style.build()) } } message.text = NSAttributedString(string: "Hello!", style: .body) name.text = NSAttributedString(string: "Taro", style: .body) { tweak in tweak.color = UIColor.secondaryTextColor() }
  23. Text Styleͷద༻ extension NSAttributedString { convenience init(string str: String, style:

    TextStyle, 
 tweak: (_ builder: TextStyle) -> Void) { tweak(style) self.init(string: str, attributes: style.build()) } } message.text = NSAttributedString(string: "Hello!", style: .body) name.text = NSAttributedString(string: "Taro", style: .body) { tweak in tweak.color = UIColor.secondaryTextColor() }
  24. Text Styleͷద༻ extension NSAttributedString { convenience init(string str: String, style:

    TextStyle, 
 tweak: (_ builder: TextStyle) -> Void) { tweak(style) self.init(string: str, attributes: style.build()) } } message.text = NSAttributedString(string: "Hello!", style: .body) name.text = NSAttributedString(string: "Taro", style: .body) { tweak in tweak.color = UIColor.secondaryTextColor() } Attributes DictionaryΛੜ੒
  25. Text Styleͷద༻ extension NSAttributedString { convenience init(string str: String, style:

    TextStyle, 
 tweak: (_ builder: TextStyle) -> Void) { tweak(style) self.init(string: str, attributes: style.build()) } } message.text = NSAttributedString(string: "Hello!", style: .body) name.text = NSAttributedString(string: "Taro", style: .body) { tweak in tweak.color = UIColor.secondaryTextColor() }
  26. Text Styleͷద༻ extension NSAttributedString { convenience init(string str: String, style:

    TextStyle, 
 tweak: (_ builder: TextStyle) -> Void) { tweak(style) self.init(string: str, attributes: style.build()) } } message.text = NSAttributedString(string: "Hello!", style: .body) name.text = NSAttributedString(string: "Taro", style: .body) { tweak in tweak.color = UIColor.secondaryTextColor() } .bodyʹclosure಺ͷΧελϚΠζΛద༻
  27. Storyboard, Xibͷѻ͍ • SwiftGenͳͲ͸࢖Θͣɺఆ൪ͷprotocol४ڌͷΈ protocol StoryboardInitializable: class { static var

    storyboardName: String { get } static func instantiateStoryboard(storyboardName: String?) -> Self } extension StoryboardInitializable where Self: UIViewController { static var storyboardName: String { return String(describing: self) } static func instantiateStoryboard() -> Self { ... } }