その Swift コード、 こう書き換えてみないか / Polishing your Swift code with me!
DeNA×STORES×ラクマ iOS Meetup!! 2023/05/22 19:00〜 https://connpass.com/event/283989/
登壇ノートはこちら: https://zenn.dev/treastrain/articles/65f6cae11e0dc7
Copyright © 2023 treastrain / Tanaka RyogaɹAll rights reserved.USFBTUSBJO5BOBLB3ZPHBͦͷ4XJGUίʔυɺ ͜͏ॻ͖͑ͯΈͳ͍͔1PMJTIJOHZPVS4XJGUDPEFXJUINF1DeNA×STORES×ϥΫϚ iOS Meetup!! #dena_stores_rakuma
View Slide
Copyright © 2023 treastrain / Tanaka RyogaɹAll rights reserved."CPVUNFUSFBTUSBJO5BOBLB3ZPHB24XJGU J04 XBUDI04 $PSF/'$ 044 ɹɹJU`TNZNPUIFSUPOHVF ɹɹ࠷ۙ#MVFTLZΛ͡Ί·ͨ͠ɹɹɹɹɹɹɹɹɹɹ!USFBTUSBJOɹɹIUUQTUSFUKQ %F/"$P -UE ɹɹJ04"QQ%FWFMPQFSʢ"QSJM$VSSFOUʣ
Copyright © 2023 treastrain / Tanaka RyogaɹAll rights reserved.BoolΛస͢Δʹtoggle()Λ͏flag = !flagΑΓΘ͔Γ͍͢w !ͰసͰ͖Δ͚Ͳʜʜ3var flag = trueflag = !flagprint(flag) // false
Copyright © 2023 treastrain / Tanaka RyogaɹAll rights reserved.BoolΛస͢Δʹtoggle()Λ͏flag = !flagΑΓΘ͔Γ͍͢4struct Hoge {var fuga1 = Fuga(); var fuga2 = Fuga()struct Fuga {var piyo1 = Piyo(); var piyo2 = Piyo()struct Piyo {var flag = true}}}var hoge = Hoge()hoge.fuga1.piyo2.flag = !hoge.fuga2.piyo1.flag // fuga1ɾ2ɺpiyo2ɾ1 ͕ٯʂ
Copyright © 2023 treastrain / Tanaka RyogaɹAll rights reserved.BoolΛస͢Δʹtoggle()Λ͏flag = !flagΑΓΘ͔Γ͍͢w toggle()ͰಡΈ͘͢ɺهड़ϛεͷ৺ݮΔ5flag.toggle()hoge.fuga1.piyo2.flag.toggle()
Copyright © 2023 treastrain / Tanaka RyogaɹAll rights reserved.isMultiple(of:)Λ͏x % 2 == 0Θͳ͍w ӳޠͷจষͷΑ͏ʹಡΊͯɺՄಡੑ্͕6let x = 4print(x % 2 == 0) // true - `%` ԋࢉࢠΛ༻͍Δྫprint(x & 1 == 0) // true - `&` ԋࢉࢠΛ༻͍Δྫprint(x.isMultiple(of: 2)) // true - ӳޠͷจষͷΑ͏ʹಡΊΔprint(x.isMultiple(of: 3)) // false
Copyright © 2023 treastrain / Tanaka RyogaɹAll rights reserved.ίϨΫγϣϯͷendIndexΛ͏countͬΆ͍͚ΕͲw ʮ࠷ޙͷΠϯσοΫεʯΛࣔ͢w count0 OɺendIndex0 7let list = ["DeNA", "STORES", "Rakuten Rakuma”]print(list.count) // 3print(list.endIndex) // 3
Copyright © 2023 treastrain / Tanaka RyogaɹAll rights reserved.ίϨΫγϣϯ͕ۭ͔Ͳ͏͔isEmptyͰಘΔcount == 0Θͳ͍w ಡΈ͍͢w count0 OɺisEmpty0 8let list1 = ["DeNA", "STORES", "Rakuten Rakuma"]print(list1.count == 0) // falseprint(list1.isEmpty) // falsevar list2 = list1list2.removeAll()print(list2.count == 0) // trueprint(list2.isEmpty) // true
Copyright © 2023 treastrain / Tanaka RyogaɹAll rights reserved.ίϨΫγϣϯͷΠϯσοΫεindexed()ͰಘΔenumerated()zip(_:_:)Ͱͳ͘w enumerated()ཁૉͱҰॹʹʮ0͔Β࢝·Δ࿈൪ʯΛฦ͢9let prefectures = ["Hokkaido", "Aomori", "Iwate", "Miyagi", "Akita", "Yamagata", “Fukushima"]for (offset, prefecture) in prefectures.enumerated() {print(offset, prefecture, prefectures[offset])/*0 Hokkaido Hokkaido1 Aomori Aomori2 Iwate Iwate3 Miyagi Miyagi4 Akita Akita5 Yamagata Yamagata6 Fukushima Fukushima*/}
Copyright © 2023 treastrain / Tanaka RyogaɹAll rights reserved.ίϨΫγϣϯͷΠϯσοΫεindexed()ͰಘΔenumerated()zip(_:_:)Ͱͳ͘w ʮ0͔Β࢝·Δ࿈൪ʯͱʮίϨΫγϣϯͷΠϯσοΫεʯҰக͠ͳ͍͔10let tohoku = prefectures.dropFirst()for (offset, prefecture) in tohoku.enumerated() {print(offset, prefecture, prefectures[offset])/*0 Aomori Hokkaido1 Iwate Aomori2 Miyagi Iwate3 Akita Miyagi4 Yamagata Akita5 Fukushima Yamagata*/}print(tohoku[0]) // 💥 Fatal error: Index out of bounds
Copyright © 2023 treastrain / Tanaka RyogaɹAll rights reserved.ίϨΫγϣϯͷΠϯσοΫεindexed()ͰಘΔenumerated()zip(_:_:)Ͱͳ͘w ඪ४తͳସҊzip(_:_:)enumerated()ΑΓύϑΥʔϚϯε͕ѱ͍11for (index, prefecture) in zip(tohoku.indices, tohoku) {print(index, prefecture, prefectures[index])/*1 Aomori Aomori2 Iwate Iwate3 Miyagi Miyagi4 Akita Akita5 Yamagata Yamagata6 Fukushima Fukushima*/}
Copyright © 2023 treastrain / Tanaka RyogaɹAll rights reserved.ίϨΫγϣϯͷΠϯσοΫεindexed()ͰಘΔenumerated()zip(_:_:)Ͱͳ͘w 4XJGU"MHPSJUINTͷindexed()zip(_:_:)ΑΓ ύϑΥʔϚϯε͕ྑ͍12import Algorithmsfor (index, prefecture) in tohoku.indexed() {print(index, prefecture, prefectures[index])/*1 Aomori Aomori2 Iwate Iwate3 Miyagi Miyagi4 Akita Akita5 Yamagata Yamagata6 Fukushima Fukushima*/}
Copyright © 2023 treastrain / Tanaka RyogaɹAll rights reserved.ೋॏͷϧʔϓproduct(_:_:)Λ͏for-inΛճॻ͘ඞཁ͕ͳ͘ͳΔ13let years = [2021, 2022, 2023]let months = ["January", "February", "March", /* ... */]for year in years {for month in months {print(year, month)/*2021 January2021 February2021 March...2022 January2022 February2022 March...*/}}
Copyright © 2023 treastrain / Tanaka RyogaɹAll rights reserved.ೋॏͷϧʔϓproduct(_:_:)Λ͏for-inΛճॻ͘ඞཁ͕ͳ͘ͳΔw 4XJGU"MHPSJUINTͷproduct(_:_:)ͰωετΛݮΒͤΔw Ұํ͕ۭͷ߹ɺແବͳϧʔϓॲཧ͕ൃੜ͠ͳ͍14import Algorithmsfor (year, month) in product(years, months) {print(year, month)}
Copyright © 2023 treastrain / Tanaka RyogaɹAll rights reserved.for-inͱforEach(_:)ͷ͍͚Λߟ͑ͯΈΔforEach(_:)ࣗମfor-inͰ࣮͞Ε͍ͯΔ͚Ͳ15func printWithLowercased(_ value: String) {print(value.lowercased())}let list = ["DeNA", "STORES", "Rakuten Rakuma"]for name in list {printWithLowercased(name)}// ಉ͡ग़ྗlist.forEach { name inprintWithLowercased(name)}// ಉ͡ग़ྗ
Copyright © 2023 treastrain / Tanaka RyogaɹAll rights reserved.for-inͱforEach(_:)ͷ͍͚Λߟ͑ͯΈΔforEach(_:)ࣗମfor-inͰ࣮͞Ε͍ͯΔ͚Ͳ16for-inϧʔϓ forEach(_:)ϧʔϓΛ్தͰΊΔ breakΛ͏ Ͱ͖ͳ͍ॲཧͷ్தͰ࣍ͷཁૉʹҠΔ continueΛ͏ returnΛ͏SFUVSOจΛ͏ͱ ϧʔϓ͕͋Δείʔϓ͔Βग़Δ ࣍ͷཁૉͷॲཧʹҠΔཁૉ໊ͷলུ Ͱ͖ͳ͍ Ͱ͖Δʢ$0ʣؔͳͲΛ͢ Ͱ͖ͳ͍ Ͱ͖ΔʢforEach(someFunc())ʣඇಉظʢBTZODBXBJUʣॲཧ Ͱ͖Δ Ͱ͖ͳ͍
Copyright © 2023 treastrain / Tanaka RyogaɹAll rights reserved.໊લۭؒʢ/BNFTQBDFTʣʹenumΛ͏classstructͰͳ͘w structclassΛ͏ͱɺ internalͰ͑ΔΠχγϟϥΠβ͕σϑΥϧτͰ༻ҙ͞Εͯ͠·͏17enum BreakfastMenu {static let rice = "͝൧"static let bread = "ύϯ"// ...}print(BreakfastMenu.rice) // ͝൧
Copyright © 2023 treastrain / Tanaka RyogaɹAll rights reserved.ϥϯμϜͳɾཁૉ͕΄͍͠arc4random()arc4random_uniform(_:)Θͳ͍w 4XJGU͔Β͑ΔΑ͏ʹͳͬͨ random()ɾrandom(in:)ɾrandomElement()Λ͏18let flag = Bool.random()let num = Int.random(in: 0..<10)let area = [1: "Shibuya", 2: "Shinjuku"].randomElement()let player = ["uhooi", "treastrain"].randomElement()
Copyright © 2023 treastrain / Tanaka RyogaɹAll rights reserved.Optional.map(_:)Λ͏nilͷͱ͖nilͷ··ɺnilͰͳ͍ͱ͖͚ͩॲཧΛߦ͏w nilͷͱ͖ʜͷذΛࣗͰॻ͔ͳͯ͘ࡁΉ19struct Talk {let title: String}let selectedTalkTitle: String? = nillet selectedTalk: Talk? = selectedTalkTitle.map { Talk(title: $0) }print(selectedTalk) // nil
Copyright © 2023 treastrain / Tanaka RyogaɹAll rights reserved.ʮOptionalͳvarʯΛʮඇ0QUJPOBMͳletʯʹʮHFU͢Δͱ͖·ͰʹඞͣTFU͞Ε͍ͯΔʯϓϩύςΟͰ20enum Area {case osaka, hiroshima}let area: Area = // ...var okonomiyaki: String?switch area {case .osaka:okonomiyaki = "ؔ෩"case .hiroshima:okonomiyaki = "ౡ෩"}print(okonomiyaki)
Copyright © 2023 treastrain / Tanaka RyogaɹAll rights reserved.ʮOptionalͳvarʯΛʮඇ0QUJPOBMͳletʯʹʮHFU͢Δͱ͖·ͰʹඞͣTFU͞Ε͍ͯΔʯϓϩύςΟͰ21enum Area {case osaka, hiroshima}let area: Area = // ...let okonomiyaki: Stringswitch area {case .osaka:okonomiyaki = "ؔ෩"case .hiroshima:okonomiyaki = "ౡ෩"}print(okonomiyaki)
Copyright © 2023 treastrain / Tanaka RyogaɹAll rights reserved.͋ͱ͔ΒTFU͞ΕΔϓϩύςΟΛOptionalʹ͠ͳ͍ඞͣTFU͞ΕΔͳΒpreconditionFailure(_:file:line:)ΛԾஔ͖͢Δ22import UIKitfinal class ViewController: UIViewController {// ͜ͷ collectionView viewDidLoad() ͷޙʹ࡞Δ͜ͱʹ͍ͯ͠ΔʢͱԾఆʣprivate var collectionView: UICollectionView?override func viewDidLoad() {super.viewDidLoad()// collectionView Λ࡞ΔcollectionView = UICollectionView(frame: .null)// ...// collectionView Λ͏view.addSubview(collectionView!)}}
Copyright © 2023 treastrain / Tanaka RyogaɹAll rights reserved.͋ͱ͔ΒTFU͞ΕΔϓϩύςΟΛOptionalʹ͠ͳ͍ඞͣTFU͞ΕΔͳΒpreconditionFailure(_:file:line:)ΛԾஔ͖͢Δ23import UIKitfinal class ViewController: UIViewController {// ͜ͷ collectionView viewDidLoad() ͷޙʹ࡞Δ͜ͱʹ͍ͯ͠ΔʢͱԾఆʣprivate lazy var collectionView: UICollectionView ={ preconditionFailure("collectionView has not been set") }()override func viewDidLoad() {super.viewDidLoad()// collectionView Λ࡞ΔcollectionView = UICollectionView(frame: .null)// ...// collectionView Λ͏view.addSubview(collectionView)}}
Copyright © 2023 treastrain / Tanaka RyogaɹAll rights reserved.֦ுʢ&YUFOTJPOTʣϓϩτίϧʢ1SPUPDPMTʣ͝ͱʹ࡞Δͦͷϓϩτίϧͷ४ڌͷͨΊͷ࣮ͦͷதͰͷΈߦ͏24import Foundationstruct Book {let name: Stringlet uuid: UUID}extension Book: Identifiable, Hashable {var id: UUID { uuid }}extension Book {func hash(into hasher: inout Hasher) {hasher.combine(id)}}
Copyright © 2023 treastrain / Tanaka RyogaɹAll rights reserved.֦ுʢ&YUFOTJPOTʣϓϩτίϧʢ1SPUPDPMTʣ͝ͱʹ࡞Δͦͷϓϩτίϧͷ४ڌͷͨΊͷ࣮ͦͷதͰͷΈߦ͏25import Foundationstruct Book {let name: Stringlet uuid: UUID}extension Book: Identifiable {var id: UUID { uuid }}extension Book: Hashable {func hash(into hasher: inout Hasher) {hasher.combine(id)}}
Copyright © 2023 treastrain / Tanaka RyogaɹAll rights reserved.֦ுʢ&YUFOTJPOTʣϓϩτίϧʢ1SPUPDPMTʣ͝ͱʹ࡞Δͦͷϓϩτίϧͷ४ڌͷͨΊͷ࣮ͦͷதͰͷΈߦ͏w 4XJGU6*ͷྫ26import SwiftUIstruct ContentView: View {let greeting = "Hello, happy world!"var body: some View { // ϓϩτίϧ View ଆͷఆٛͰ @MainActor ʹͳ͍ͬͯΔText(greeting)}}
Copyright © 2023 treastrain / Tanaka RyogaɹAll rights reserved.֦ுʢ&YUFOTJPOTʣϓϩτίϧʢ1SPUPDPMTʣ͝ͱʹ࡞Δͦͷϓϩτίϧͷ४ڌͷͨΊͷ࣮ͦͷதͰͷΈߦ͏w 4XJGU6*ͷྫ27import SwiftUIstruct ContentView: View {let greeting = "Hello, happy world!"}extension ContentView {var body: some View { // 😫 ҉తʹ @MainActor Ͱͳ͘ͳΓɺ// ϓϩτίϧ View ଆͷఆٛͱҟͳͬͯ͠·͏Text(greeting)}}
Copyright © 2023 treastrain / Tanaka RyogaɹAll rights reserved.֦ுʢ&YUFOTJPOTʣϓϩτίϧʢ1SPUPDPMTʣ͝ͱʹ࡞Δͦͷϓϩτίϧͷ४ڌͷͨΊͷ࣮ͦͷதͰͷΈߦ͏w 4XJGU6*ͷྫ28import SwiftUIstruct ContentView {let greeting = "Hello, happy world!"}extension ContentView: View {var body: some View { // ✅ ϓϩτίϧ View ଆͷఆٛΑΓ// ҉తʹ @MainActor ʹͳΔText(greeting)}}
Copyright © 2023 treastrain / Tanaka RyogaɹAll rights reserved.ͦͷ΄͔͔͑ͨͬͨ͜ͱ͕࣌ؒΓͳ͔ͬͨʜʜw switchจͰͪΌΜͱཏͯ͠ɺ ݟམͱ͠Λແͨ͘͠Γޙͷมߋʹڧͨ͘͠Γ͢Δw Resultͱεϩʔؔʢ5ISPXJOH'VODUJPOTʣͷ૬ޓมw %FMFHBUFɾΫϩʔδϟΛBTZODͳؔʹ͢Δw NotificationCenterΛ4XJGU$PODVSSFODZ͔Β͏w $PNCJOFɾ3Y4XJGUΛ4XJGU$PODVSSFODZ͔Β͏29
Copyright © 2023 treastrain / Tanaka RyogaɹAll rights reserved.͞ΒʹεςοϓΞοϓ6*,JUʢJ04ͳͲʣͰʮͬͪ͜ͷํ͕͍͍Αʯ30
Copyright © 2023 treastrain / Tanaka RyogaɹAll rights reserved.ɹɹɹɹɹεϥΠυɾൃද༰IUUQTUSFUKQͰެ։͍ͯ͠·͢ɹ⏩ͦͷ4XJGUίʔυɺ ͜͏ॻ͖͑ͯΈͳ͍͔1PMJTIJOHZPVS4XJGUDPEFXJUINF31DeNA×STORES×ϥΫϚ iOS Meetup!! #dena_stores_rakuma