Slide 1

Slide 1 text

bitFlyerΞϓϦ͸ ͍͔ʹͯ͠ϥΠϒϥϦґଘΛ࠷খݶʹ ։ൃΛߦ͍ͬͯΔͷ͔ ໦ גࣜձࣾCJU'MZFS ງݟफҰ࿠

Slide 2

Slide 2 text

ΞδΣϯμ • bitFlyer ͷΞϓϦͱ։ൃελΠϧͷ঺հ • ϥΠϒϥϦ࠾༻ͰؕΓ΍͍͢᠘ͱɺ
 bitFlyerͰͷΞϓϩʔν • ΞϓϩʔνΛৼΓฦͬͯ

Slide 3

Slide 3 text

bitFlyer ͷΞϓϦͱ։ൃελΠϧͷ঺հ

Slide 4

Slide 4 text

bitFlyer Wallet • ೔ຊ࠷େͷԾ૝௨՟औҾॴ CJU'MZFSͷJ04޲͚ΞϓϦ • ೥͔Β։ൃ։࢝ • ίʔυϕʔε͸ສߦ௒ *1 ௐࠪҕୗઌϚΫϩϛϧʢ2018 ೥ 2 ݄ɺΠϯλʔωοτௐࠪʮԾ૝௨՟ɾ҉߸௨՟औҾ
 αʔϏεʹؔ͢ΔΞϯέʔτʯʣɺBitcoin ೔ຊޠ৘ใαΠτௐ΂ɻ 2016 ೥ 4݄-2018 ೥ 4 ݄ɺࠃ಺औҾॴͷ૯݄ؒग़དྷߴʢݱ෺/ܾࠩۚࡁ/ઌ෺औҾΛؚΉʣ

Slide 5

Slide 5 text

ͲͷΑ͏ʹ࡞͍ͬͯΔ͔ • ݱࡏ4ਓͰ։ൃத • ΞʔΩςΫνϟ͸جຊతʹMVC • 3rd partyϥΠϒϥϦʹཔΓ"͗ͣ͢"։ൃ͍ͯ͠Δ

Slide 6

Slide 6 text

bitFlyerͰ࢖͍ͬͯΔϥΠϒϥϦ

Slide 7

Slide 7 text

bitFlyerͰ࢖͍ͬͯΔϥΠϒϥϦ

Slide 8

Slide 8 text

bitFlyerͰ࢖͍ͬͯΔϥΠϒϥϦ

Slide 9

Slide 9 text

bitFlyerͰ࢖͍ͬͯΔϥΠϒϥϦ ͘͝Ұ෦Ͱ࢖༻ ࠷ۙ͸$PEBCMFʹ

Slide 10

Slide 10 text

ຊ೔࿩͞ͳ͍͜ͱ • ඪ४SDKݪཧओٛతͳ࿩ɾOSSͷDisΓ • ϥΠϒϥϦʹͲΕ͘Β͍པΔ΂͖͔͸ঢ়گʹΑΔ • ੒௕ͷݟࠐΊΔαʔϏεɾҰఆͷ։ൃྗ͕͋ΔνʔϜ Ͱ͸ࣗલ࣮૷ͷํ͕ϝϦοτ͕ߴ͍

Slide 11

Slide 11 text

ຊ೔࿩͢͜ͱ • ϥΠϒϥϦ͸ศར͕ͩɺΉ΍Έʹ࢖͏ͱ଍͔ͤʹ • Ͳ͜Ͱ᠘ʹؕΓ΍͍͢ͷ͔ʁ • ͦ͜ͰͲ͏࣮૷͍ͯ͠Δͷ͔ʁʹ͍ͭͯ঺հ͠·͢

Slide 12

Slide 12 text

ϥΠϒϥϦ࠾༻ͰؕΓ΍͍͢᠘ͱ bitFlyerͰͷΞϓϩʔν

Slide 13

Slide 13 text

ϥΠϒϥϦ࠾༻ͰؕΓ΍͍͢᠘ͱ bitFlyerͰͷΞϓϩʔν • UIKitͰϥΠϒϥϦΛ࢖͍ͨ͘ͳΔϙΠϯτ 1. UITableViewͷѻ͍ʹ͘͞ 2. ૒ํ޲όΠϯσΟϯά 3. Style΍ComponentͷऔΓѻ͍ (Font, Color, IB) • Өڹൣғ͕ۃେԽ • ֶशίετɾϩοΫΠϯΛͲ͏ղܾ͢Δ͔ʁ

Slide 14

Slide 14 text

1. UITableViewͷѻ͍ʹ͘͞

Slide 15

Slide 15 text

1. UITableViewͷѻ͍ʹ͘͞ • ࣌୅͸એݴతUITableView / CollectionViewઓࠃ࣌୅ʁ • RxDataSources Λ࢝ΊɺiOSDCͰ΋࿩୊ʹ • ܾఆతͳఆ൪͸·ͩͳ͘ɺͦΕͧΕҰ௕Ұ୹ΞϦ • ѻ͍΍͢͞ͱҾ͖׵͑ʹύϥμΠϜ่յ͕ى͜Δ

Slide 16

Slide 16 text

ബ͍ϑϨʔϜϫʔΫͷ੔උ • ͱ͸͍͑ૉͷUIKit͸ݫ͍͠ • ࣗલͰܰྔϑϨʔϜϫʔΫΛ࣮૷͍ͯ͠Δ • ࣮૷ίετ͸͔͔Δ͕ɺऔΓճ͠΍͘͢
 ඞཁʹԠ֦ͯ͡ு͠΍͍͢

Slide 17

Slide 17 text

ബ͍ϑϨʔϜϫʔΫͷ࣮૷ final class HistoryViewController: UIViewController {
 @IBOutlet private weak var tableView: UITableView!
 private var entities = [History]() private let dataSource = TableDataSource() private let entitiesProvider = EntitiesProvider() 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() }

Slide 18

Slide 18 text

ബ͍ϑϨʔϜϫʔΫͷ࣮૷ final class HistoryViewController: UIViewController {
 @IBOutlet private weak var tableView: UITableView!
 private var entities = [History]() private let dataSource = TableDataSource() private let entitiesProvider = EntitiesProvider() 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΁ͷڮ౉͠

Slide 19

Slide 19 text

ബ͍ϑϨʔϜϫʔΫͷ࣮૷ final class HistoryViewController: UIViewController {
 @IBOutlet private weak var tableView: UITableView!
 private var entities = [History]() private let dataSource = TableDataSource() private let entitiesProvider = EntitiesProvider() 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΁ͷڮ౉͠

Slide 20

Slide 20 text

ബ͍ϑϨʔϜϫʔΫͷ࣮૷ final class HistoryViewController: UIViewController {
 @IBOutlet private weak var tableView: UITableView!
 private var entities = [History]() private let dataSource = TableDataSource() private let entitiesProvider = EntitiesProvider() 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૬౰)

Slide 21

Slide 21 text

ബ͍ϑϨʔϜϫʔΫͷྑ͞ • ࠷খݶͷ࣮૷ • ෆඞཁͳ֓೦͕ಋೖ͞Εͳ͍ • ཁ݅ɾ໰୊ҙࣝυϦϒϯͰਐԽͰ͖Δ

Slide 22

Slide 22 text

2. ૒ํ޲όΠϯσΟϯά

Slide 23

Slide 23 text

2. ૒ํ޲όΠϯσΟϯά • ೖྗΛ൐͏6*5BCMF7JFX • 5FYUϑΥʔϜɺબ୒ࢶεΠον • #JOEJOH͸ΧοίΑ͘ॻ͚Δ͕
 ࿩Λ΍΍͘͜͢͠Δ • ෳࡶͳؔ਺Λ࢖͍࢝ΊΔͱ
 σόοάࠔ೉ʹ

Slide 24

Slide 24 text

TableViewCellͷ࠶ར༻Λ΍Ίͯγϯϓϧʹ • ΍Γ͍ͨͷ͸ೖྗʹԠͨ͡Πϕϯτॲཧɾೖྗ஋ࢀর • Cellͷ࠶ར༻Λ΍Ίͯ͠·͑͹ྑ͍ • ೖྗϑΥʔϜͱ͸༗ݶͳCellͰߏ੒͞Ε͍ͯΔ͸ͣ

Slide 25

Slide 25 text

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] } }

Slide 26

Slide 26 text

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] } }

Slide 27

Slide 27 text

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] } }

Slide 28

Slide 28 text

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ύʔπ͕͍࣋ͬͯΔσʔλΛݟʹ͍͘

Slide 29

Slide 29 text

࠶ར༻Λ΍ΊΔ͜ͱͷྑ͞ • γϯϓϧ • ૉ௚ͳ࣮૷ͳͷͰ୭͕ಡΜͰ΋෼͔Γ΍͍͢ • ొ৔ਓ෺Λݶఆ͢ΔͱϝϦοτ͕େ͖͍

Slide 30

Slide 30 text

3. Style΍ComponentͷऔΓѻ͍

Slide 31

Slide 31 text

3. Style΍
 ComponentͷऔΓѻ͍ • 5FYU $PMPSͳͲ޿ൣғʹӨڹ • /4"UUSJCVUFE4USJOH΍ 6*4UPSZCPBSE͕ΠϚΠν • ඪ४4%,͕ؤுͬͯ΄͍͠ • 044΋๲େͳ਺ ग़యWTPV[BBXFTPNFJPTUFYU

Slide 32

Slide 32 text

Text, Color Styles • ΞϓϦશମʹίϯϙʔωϯτɾελΠϧΨΠυ੔උࡁ • NSAttributedStringͷextension initializerͰશςΩετʹ ৭΍ϑΥϯτ౳ͷελΠϧΛద༻

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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() } … } ΞϓϦ಺Ͱ࢖͏৭

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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() } … } ίϯςΩετͷఆٛ

Slide 38

Slide 38 text

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 // ϑΥϯτͷछྨ ...

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

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Λੜ੒

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

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಺ͷΧελϚΠζΛద༻

Slide 48

Slide 48 text

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 { ... } }

Slide 49

Slide 49 text

Localizable, Assets౳ • LocalizedString͸ී௨ʹจࣈྻࢦఆ • ิ׬͕ޮ͔ͳ͍ͷ͸ඍົ • վमը໘Ҏ֎Ͱ͸ࣄނΔϦεΫ΋গͳ͘ࠔΒͳ͍ • Α͘ࠔΔͱͨ͠Β։ൃϑϩʔࣗମʹ໰୊͕͋Δ͍ٙ

Slide 50

Slide 50 text

ΞϓϩʔνΛৼΓฦͬͯ

Slide 51

Slide 51 text

ΞϓϩʔνΛৼΓฦͬͯ • ଟ͘ͷϥΠϒϥϦ͸՝୊ʹରͯ͠ΦʔόʔΩϧͩͬͨ • ࣮͸ࣗલͰ࣮૷ͯ͠΋େม͡Όͳ͔ͬͨέʔε΋ଟ͍ • ߟ͑ൈ͚͹γϯϓϧɾϕετͳղ๏͕ݟ͔ͭΔ

Slide 52

Slide 52 text

XcodeΞοϓσʔτָ͕ʹ • ϥΠϒϥϦͷϝϯςঢ়گʹ։ൃ͕ࠨӈ͞Εʹ͘͘ͳͬͨ • Xcode10ରԠ΋εϜʔζ

Slide 53

Slide 53 text

ඪ४SDK΍ຊ࣭తͳઃܭʹٞ࿦ΛूதͰ͖Δ

Slide 54

Slide 54 text

ϥΠϒϥϦ vs ಠ࣮ࣗ૷࿦͸ νʔϜ։ൃΛݟ௚͖͔͚ͬ͢ʹ΋ͳΔ • ϥΠϒϥϦΛ࠾༻ͯ͠ɺԿΛ໨ࢦ͔ͨͬͨ͠ͷ͔ • ෳࡶͳϥΠϒϥϦ͕ඞཁͳͷ͸࢓༷ʹ໰୊͕ͳ͍͔ʁ • σάϨͷසൃ͸ศརϥΠϒϥϦͰղܾͰ͖Δͷ͔ʁ

Slide 55

Slide 55 text

ϥΠϒϥϦ࠾༻ͷצॴ • ͢΂ͯࣗલ࣮૷͢Δͷ͸ݱ࣮తͰͳ͍ • ͋ͱͰҾ͖͸͕͠΍͍͢Ϟϊ͸අ༻ରޮՌ͕ߴ͍ • ੹຿͕໌֬ͳAPIKitɾNukeɻRx΋࢖͍ํ࣍ୈ • ૊৫΍ΤίγεςϜͷਐԽʹద༻͠΍͍ͨ͘͢͠

Slide 56

Slide 56 text

·ͱΊ • bitFlyerΞϓϦͱɺͦͷ։ൃελΠϧͷ঺հ • ϥΠϒϥϦ࠾༻ͷ஫ҙ఺ͱɺগͳ͍ґଘͷϝϦοτ • ·ͩ·ͩ՝୊ࢁੵΈɺ಺੡ϥΠϒϥϦ΋ۙ೔େվम!? ʘ"ຊ࣭"ʹϑΥʔΧε͍ͨ͠ΤϯδχΞɺͥͻฐࣾʹʂʗ