Slide 1

Slide 1 text

iOSDC Japan 2018
 2018/08/30 גࣜձࣾϛΫγΟ/ΈͯͶࣄۀ෦ ؠ໊༐ً @rockname Playgroundۦಈ։ൃ ͷ͢͢Ί

Slide 2

Slide 2 text

@rockname גࣜձࣾϛΫγΟ / ΈͯͶࣄۀ෦
 ΞϓϦ։ൃG 18৽ଔ iOS(Swift, objc), Android(Kotlin, Java), Rails(ruby)…

Slide 3

Slide 3 text

UIͷ࣮૷Λ൐͏
 iOSΞϓϦ։ൃϑϩʔ

Slide 4

Slide 4 text

1 ϩδοΫΛ૊Ή 2 StoryboardͰϨΠΞ΢τ 3 ಈ࡞֬ೝ w ͦΕͧΕͷΞʔΩςΫνϟʹԠͯ͡ϩδοΫ͔Β૊ΜͰ͍͘ w $MFBO"SDIJUFDUVSFͳΒ%PNBJO͔Β w ςετॻ͘ w ΞχϝʔγϣϯͳͲಈతͳཁૉҎ֎͸ఆٛͯ͠͠·͏ w ࣮ػ΍4JNVMBUPSͰҙਤͨ͠ڍಈΛ͢Δ͔֬ೝ

Slide 5

Slide 5 text

1 ϩδοΫΛ૊Ή 2 StoryboardͰϨΠΞ΢τ 3 ಈ࡞֬ೝ w ͦΕͧΕͷΞʔΩςΫνϟʹԠͯ͡ϩδοΫ͔Β૊ΜͰ͍͘ w $MFBO"SDIJUFDUVSFͳΒ%PNBJO͔Β w ςετॻ͘ w ΞχϝʔγϣϯͳͲಈతͳཁૉҎ֎͸ఆٛͯ͠͠·͏ w ࣮ػ΍4JNVMBUPSͰҙਤͨ͠ڍಈΛ͢Δ͔֬ೝ 4 σβΠϯௐ੔

Slide 6

Slide 6 text

1 ϩδοΫΛ૊Ή 2 StoryboardͰϨΠΞ΢τ 3 ಈ࡞֬ೝ w ͦΕͧΕͷΞʔΩςΫνϟʹԠͯ͡ϩδοΫ͔Β૊ΜͰ͍͘ w $MFBO"SDIJUFDUVSFͳΒ%PNBJO͔Β w ςετॻ͘ w ΞχϝʔγϣϯͳͲಈతͳཁૉҎ֎͸ఆٛͯ͠͠·͏ w ࣮ػ΍4JNVMBUPSͰҙਤͨ͠ڍಈΛ͢Δ͔֬ೝ 4 σβΠϯௐ੔ ͕݁͜͜ߏਏ͍…

Slide 7

Slide 7 text

• ෳ਺ղ૾౓ͰͷϨΠΞ΢τ • ৚݅ʹΑͬͯมΘΔදࣔ಺༰ • ϩʔΧϥΠζͷจݴ…

Slide 8

Slide 8 text

Xcode Simulator
 /Device #VJME͕௨ΔͷΛ଴ͬͯ
 ϨΠΞ΢τΛ֬ೝ ϨΠΞ΢τΛௐ੔ͯ͠
 ࠶Ϗϧυ • ෳ਺ղ૾౓ͰͷϨΠΞ΢τ • ৚݅ʹΑͬͯมΘΔදࣔ಺༰ • ϩʔΧϥΠζͷจݴ…

Slide 9

Slide 9 text

UIͷௐ੔Λ΋ͬͱૣ͍αΠΫϧͰճ͍ͨ͠…

Slide 10

Slide 10 text

– Playground driven development “Playgroundۦಈ։ൃ”

Slide 11

Slide 11 text

Playgroundۦಈ։ൃͱ͸ • ViewͷΈΛ୹࣌ؒͰϏϧυͯ͠ର৅ͷγʔϯΛ PlaygroundͰදࣔ͢Δ͜ͱͰσβΠϯௐ੔ͷϑ ϩʔΛૣ͘͢Δ։ൃख๏
 • Kickstarter͕ఏএ
 (https://github.com/kickstarter/ios-oss)

Slide 12

Slide 12 text

Kickstarter͸͜Μͳײ͡

Slide 13

Slide 13 text

Kickstarter͸͜Μͳײ͡

Slide 14

Slide 14 text

Kickstarter͸͜Μͳײ͡

Slide 15

Slide 15 text

ಋೖखॱ

Slide 16

Slide 16 text

1. Cocoa Touch frameworkΛ λʔήοτʹ௥Ճ

Slide 17

Slide 17 text

1. Cocoa Touch frameworkΛ λʔήοτʹ௥Ճ

Slide 18

Slide 18 text

2. ࡞੒ͨ͠Frameworkʹ
 ViewΛ௥Ճ͍ͯ͘͠

Slide 19

Slide 19 text

3. (CarthageΛ࢖༻ͨ͠৔߹ͷΈ)
 ViewͷදࣔʹඞཁͳϥΠϒϥϦΛ௥Ճ

Slide 20

Slide 20 text

4. PlaygroundΛ
 ϓϩδΣΫτʹ௥Ճ

Slide 21

Slide 21 text

5. PlaygroundͰViewΛදࣔ let vc = ViewController() PlaygroundPage.current.liveView = vc

Slide 22

Slide 22 text

5. PlaygroundͰViewΛදࣔ

Slide 23

Slide 23 text

5. PlaygroundͰViewΛදࣔ

Slide 24

Slide 24 text

͞ΒʹPlaygroundʹ৽ػೳ͕…

Slide 25

Slide 25 text

What’s new in Playground
 - WWDC 2018 Xcode10͔ΒPlaygroundͷஞ࣮࣍ߦ͕Մೳʹ…!!
 (https://developer.apple.com/videos/play/ wwdc2018/402/) Alex Brown, Core OS Engineer • Running Step by Step NEW

Slide 26

Slide 26 text

What’s new in Playground
 - WWDC 2018 ҰʑίϝϯτΞ΢τ͢Δඞཁ͕ͳ͘ ϑϩʔΛڞ௨Խ͠΍͘͢ͳͬͨ Alex Brown, Core OS Engineer • Running Step by Step NEW

Slide 27

Slide 27 text

۩ମతʹͲΜͳखॱͰ σβΠϯௐ੔͢Δͷ

Slide 28

Slide 28 text

DEMO IUUQTHJUIVCDPNSPDLOBNF1MBZHSPVOE%SJWFO%FWFMPQNFOU

Slide 29

Slide 29 text

DEMOͷྲྀΕ • TwitterͷΑ͏ͳΞϓϦΛ࡞ͬͨʂ • σβΠϯ֬ೝ͢Δͧʂ ౤ߘ͕ ͳ͍/͋Δ ͱ͖ͷදࣔ͸ਖ਼͍͠ʁ ͪΌΜͱ ϩʔΧϥΠζ ͞ΕͯΔʁ খ͍͞, େ͖͍୺຤Ͱ ϨΠΞ΢τ ่Εͯͳ͍ʁ • मਖ਼ͯ͠ View͚ͩ ϏϧυͰ࠶֬ೝʂ

Slide 30

Slide 30 text

࣮૷આ໌

Slide 31

Slide 31 text

func display(device: Device, orientation: Orientation, language: Language) {
 let vc = R.storyboard.twitter.instantiateInitialViewController()!
 
 let (parent, _) = playgroundControllers(device: device, orientation: .portrait, child: vc)
 
 
 AppEnvironment.language = language
 
 
 PlaygroundPage.current.liveView = parent
 vc.load(statuses) } 1SPKFDUQMBZHSPVOE5XJUUFSYDQMBZHSPVOEQBHF

Slide 32

Slide 32 text

func display(device: Device, orientation: Orientation, language: Language) {
 let vc = R.storyboard.twitter.instantiateInitialViewController()!
 
 let (parent, _) = playgroundControllers(device: device, orientation: .portrait, child: vc)
 
 
 AppEnvironment.language = language
 
 
 PlaygroundPage.current.liveView = parent
 vc.load(statuses) } 1SPKFDUQMBZHSPVOE5XJUUFSYDQMBZHSPVOEQBHF

Slide 33

Slide 33 text

1SPKFDUQMBZHSPVOE5XJUUFSYDQMBZHSPVOEQBHF func display(device: Device, orientation: Orientation, language: Language) {
 let vc = R.storyboard.twitter.instantiateInitialViewController()!
 
 let (parent, _) = playgroundControllers(device: device, orientation: .portrait, child: vc)
 
 
 AppEnvironment.language = language
 
 
 PlaygroundPage.current.liveView = parent
 vc.load(statuses) } simulatorͷsizeͳͲΛࢦఆ

Slide 34

Slide 34 text

public func playgroundControllers(device: Device = .phone4_7inch, orientation: Orientation, child: UIViewController, additionalTraits: UITraitCollection) -> (parent: UIViewController, child: UIViewController) { let parent = UIViewController() parent.addChild(child) parent.view.addSubview(child.view) child.view.autoresizingMask = [.flexibleWidth, .flexibleHeight] let traits: UITraitCollection switch (device, orientation) { case (.phone3_5inch, .portrait): parent.view.frame = .init(x: 0, y: 0, width: 320, height: 480) traits = .init(traitsFrom: [ .init(horizontalSizeClass: .compact), .init(verticalSizeClass: .regular), .init(userInterfaceIdiom: .phone) ]) ɾ
 ɾ
 ɾ simulatorͷsizeͳͲΛࢦఆ 1SPKFDUQMBZHSPVOE4PVSDFTEFWJDFTXJGU

Slide 35

Slide 35 text

public func playgroundControllers(device: Device = .phone4_7inch, orientation: Orientation, child: UIViewController, additionalTraits: UITraitCollection) -> (parent: UIViewController, child: UIViewController) { let parent = UIViewController() parent.addChild(child) parent.view.addSubview(child.view) child.view.autoresizingMask = [.flexibleWidth, .flexibleHeight] let traits: UITraitCollection switch (device, orientation) { case (.phone3_5inch, .portrait): parent.view.frame = .init(x: 0, y: 0, width: 320, height: 480) traits = .init(traitsFrom: [ .init(horizontalSizeClass: .compact), .init(verticalSizeClass: .regular), .init(userInterfaceIdiom: .phone) ]) 1SPKFDUQMBZHSPVOE4PVSDFTEFWJDFTXJGU ɾ
 ɾ
 ɾ simulatorͷsizeͳͲΛࢦఆ Device, OrientationʹԠͯ͡
 sizeΛࢦఆ͢Δ

Slide 36

Slide 36 text

ɾ
 ɾ
 ɾ child.view.frame = parent.view.frame parent.preferredContentSize = parent.view.frame.size parent.view.backgroundColor = .white child.view.backgroundColor = .white let allTraits = UITraitCollection.init(traitsFrom: [traits, additionalTraits]) parent.setOverrideTraitCollection(allTraits, forChild: child) return (parent, child) } simulatorͷsizeͳͲΛࢦఆ 1SPKFDUQMBZHSPVOE4PVSDFTEFWJDFTXJGU

Slide 37

Slide 37 text

ɾ
 ɾ
 ɾ child.view.frame = parent.view.frame parent.preferredContentSize = parent.view.frame.size parent.view.backgroundColor = .white child.view.backgroundColor = .white let allTraits = UITraitCollection.init(traitsFrom: [traits, additionalTraits]) parent.setOverrideTraitCollection(allTraits, forChild: child) return (parent, child) } simulatorͷsizeͳͲΛࢦఆ 1SPKFDUQMBZHSPVOE4PVSDFTEFWJDFTXJGU preferredContentSizeΛࢦఆ͢Δ͜ͱͰ Playground্Ͱදࣔ͢ΔViewͷେ͖͞ΛมߋՄೳ

Slide 38

Slide 38 text

func display(device: Device, orientation: Orientation, language: Language) {
 let vc = R.storyboard.twitter.instantiateInitialViewController()!
 
 let (parent, _) = playgroundControllers(device: device, orientation: .portrait, child: vc)
 
 
 AppEnvironment.language = language
 
 
 PlaygroundPage.current.liveView = parent
 vc.load(statuses) } 1SPKFDUQMBZHSPVOE5XJUUFSYDQMBZHSPVOEQBHF

Slide 39

Slide 39 text

func display(device: Device, orientation: Orientation, language: Language) {
 let vc = R.storyboard.twitter.instantiateInitialViewController()!
 
 let (parent, _) = playgroundControllers(device: device, orientation: .portrait, child: vc)
 
 
 AppEnvironment.language = language
 
 
 PlaygroundPage.current.liveView = parent
 vc.load(statuses) } 1SPKFDUQMBZHSPVOE5XJUUFSYDQMBZHSPVOEQBHF LanguageΛࢦఆ

Slide 40

Slide 40 text

public struct AppEnvironment { public static var language: Language = .ja public static var currentUser: String? = nil public var isLoggedIn: Bool { return AppEnvironment.currentUser != nil } } GlobalʹΞϓϦͷ؀ڥΛ͍࣋ͨͤͯΔ LanguageΛࢦఆ %PNBJO"QQ&OWJSPONFOUTXJGU

Slide 41

Slide 41 text

extension StringResourceType { func localized(language: Language = AppEnvironment.language) -> String { return NSLocalizedString(key, bundle: Bundle(path: stringsBundle.path(forResource: language.rawValue, ofType: "lproj") ?? "") ?? stringsBundle, comment: "") } } private class Pin {} public let stringsBundle = Bundle(for: Pin.self) LanguageΛࢦఆ 1SFTFOUBUJPOʜ4USJOH3FTPVSDF5ZQFMPDBMJ[FETXJGU

Slide 42

Slide 42 text

extension StringResourceType { func localized(language: Language = AppEnvironment.language) -> String { return NSLocalizedString(key, bundle: Bundle(path: stringsBundle.path(forResource: language.rawValue, ofType: "lproj") ?? "") ?? stringsBundle, comment: "") } } private class Pin {} public let stringsBundle = Bundle(for: Pin.self) 1SFTFOUBUJPOʜ4USJOH3FTPVSDF5ZQFMPDBMJ[FETXJGU NSLocalizedStringͷҾ਺ʹ LanguageʹԠͨ͡BundleΛ౉͢Α͏ʹ͢Δ LanguageΛࢦఆ

Slide 43

Slide 43 text

func display(device: Device, orientation: Orientation, language: Language) {
 let vc = R.storyboard.twitter.instantiateInitialViewController()!
 
 let (parent, _) = playgroundControllers(device: device, orientation: .portrait, child: vc)
 
 
 AppEnvironment.language = language
 
 
 PlaygroundPage.current.liveView = parent
 vc.load(statuses) } 1SPKFDUQMBZHSPVOE5XJUUFSYDQMBZHSPVOEQBHF

Slide 44

Slide 44 text

func display(device: Device, orientation: Orientation, language: Language) {
 let vc = R.storyboard.twitter.instantiateInitialViewController()!
 
 let (parent, _) = playgroundControllers(device: device, orientation: .portrait, child: vc)
 
 
 AppEnvironment.language = language
 
 
 PlaygroundPage.current.liveView = parent
 vc.load(statuses) } 1SPKFDUQMBZHSPVOE5XJUUFSYDQMBZHSPVOEQBHF Playground্ͰViewΛදࣔͯ͠
 Cellʹදࣔ͢Δ౤ߘΛಡΈࠐΉ

Slide 45

Slide 45 text

ViewΛදࣔ

Slide 46

Slide 46 text

ViewΛදࣔ

Slide 47

Slide 47 text

Α͠ɺΈͯͶͰ΋ಋೖʂ

Slide 48

Slide 48 text

Α͠ɺΈͯͶͰ΋ಋೖʂ

Slide 49

Slide 49 text

ಋೖ·ͰͷಓͷΓ Viewʹදࣔ͢Δ΋ͷΛϞοΫͰ͖ΔΑ͏ʹઃܭ ଟݴޠରԠΛ͍ͯ͠ΔͷͰɺNSLocalizedStringͷ ॳظԽ࣌ʹBundleͷpathΛ౉͢ Embedded Frameworkͷಋೖ PlaygroundͷPageಋೖϑϩʔڞ௨Խɾڞ༗

Slide 50

Slide 50 text

৽نϓϩδΣΫτͳΒ ׂͱαΫοͱಋೖͰ͖ͦ͏

Slide 51

Slide 51 text

Playgroundۦಈ։ൃͰ
 ര଎ʹ։ൃ͠Α͏