Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
R.swift to Asset Symbols
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
417.72KI
September 26, 2023
Programming
390
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
R.swift to Asset Symbols
417.72KI
September 26, 2023
More Decks by 417.72KI
See All by 417.72KI
Comparing decimals in Swift Testing
417_72ki
0
250
Reboot a personal app abandoned for 10 years with recent techs
417_72ki
0
120
iTunes・おぼえていますか〜ScriptingBridge今昔物語〜
417_72ki
1
230
The history of entry-point in iOS app Development
417_72ki
0
540
Refactor with using `available` and `deprecated`
417_72ki
3
840
CLIツールにSwift Concurrencyを適用させようとしている話
417_72ki
3
520
CI with Danger-Swift
417_72ki
1
280
Graduation from Playground beginner
417_72ki
3
1k
Trap Questions in Java and Obj-C
417_72ki
1
380
Other Decks in Programming
See All in Programming
変わらないものが、変わるものを決める — 意図駆動開発 × イベントソーシング × イミュータブル | What Doesn't Change Decides What Can — IDD × Event Sourcing × Immutability
tomohisa
0
640
ここ半年くらいでAIに作らせたR用ツール
eitsupi
0
330
PHP初心者セッション2026 〜生成AIでは見えない裏側を知る:今だからLAMPを通して仕組みを学ぶ〜
kashioka
0
720
TSX の <Hoge<Fuga>> という構文に驚いた話 / tsx-type-argument-syntax
kanaru0928
0
110
The Past, Present, and Future of Enterprise Java
ivargrimstad
0
430
komatsuna「分散システムにおけるバグ分析手法」
komatsunaqa
0
120
改善しないと、タスクが回らない。 “てんこ盛りポジション” を引き継いだ情シスの、入社3ヶ月の業務改善録
krm963
0
220
GDG Korea Android: 2026 I/O Extended ~ What's new in Android development tools
pluu
0
190
壊れたパーサから始める関数型設計と構成的なパーサ #fp_matsuri
raiga0310
2
410
音楽のための関数型プログラミング言語mimiumにおける多段階計算の活用
tomoyanonymous
1
360
Welcome to the "Parametricity" 🏙️ − Generic だけど Specific な世界 −
guvalif
PRO
1
190
その節約、円になってますか?
isamumumu
0
250
Featured
See All Featured
Paper Plane (Part 1)
katiecoart
PRO
1
9.9k
Applied NLP in the Age of Generative AI
inesmontani
PRO
4
2.4k
Unsuck your backbone
ammeep
672
58k
The untapped power of vector embeddings
frankvandijk
2
1.8k
How STYLIGHT went responsive
nonsquared
100
6.2k
Agile Leadership in an Agile Organization
kimpetersen
PRO
0
190
BBQ
matthewcrist
89
10k
The agentic SEO stack - context over prompts
schlessera
0
850
Designing for Timeless Needs
cassininazir
1
410
Dealing with People You Can't Stand - Big Design 2015
cassininazir
367
27k
4 Signs Your Business is Dying
shpigford
187
22k
How Fast Is Fast Enough? [PerfNow 2025]
tammyeverts
3
670
Transcript
4XJGUѪձWPM,PUMJOѪձWPM!,* 3TXJGU͔Β"TTFU$BUBMPH ʙ4XJGU4ZOUBYΛԊ͑ͯʙ
.FTXJGU let name = "(redacted)" let twitter = "417_72ki" let
github = "417-72KI" let company = "(redacted)" var products = [ "MockUserDefaults", "MultipartFormDataParser", "BuildConfig.swift", "SSGH", ] var contributing = [ "Danger-Swift", "octokit.swift", "etc..." ]
3TXJGUͬͯ·͔͢ʁ
3TXJGUͱ w YDPEFQSPKͷதΛղੳͯ͠ը૾YJCɺTUPSZCPBSEͳͲΛίʔυิͰ͖ΔΑ ͏ʹͯ͘͠ΕΔπʔϧ w 4XJGUొॳظ͔Β͋ΔރΕͨπʔϧ͔ͱࢥ͍͖#VJME5PPM1MVHJOʹରԠ ͍ͯͨ͠ΓࠓͰΜʹߋ৽͞Ε͍ͯΔ w IUUQTHJUIVCDPNNBDDBJO3TXJGU
՝ 9DPEFͰϏϧυʹࣦഊ͢Δ߹͕͋Δ
ݪҼ A*NBHF3FTPVSDFA͕෦Ͱੜ͞Ε͍ͯΔ
ݪҼ A*NBHF3FTPVSDFA͕෦Ͱੜ͞Ε͍ͯΔ
(FOFSBUFE"TTFU4ZNCPMTTXJGU 🤔
9DPEFͷ"TTFU4ZNCPMT ग़యIUUQTEFWFMPQFSBQQMFDPNEPDVNFOUBUJPOYDPEFSFMFBTFOPUFTYDPEFSFMFBTFOPUFT
9DPEFͷ"TTFU4ZNCPMT ҙ w Ϧιʔε໊શͯDBNFM$BTFʹม͞ΕΔ w ม͞Εͨ݁Ռඃͬͨ߹ແࢹ͞ΕΔϦιʔε͕ൃੜ͢Δ
ҙ w Ϧιʔε໊શͯDBNFM$BTFʹม͞ΕΔ w ม͞Εͨ݁Ռඃͬͨ߹ແࢹ͞ΕΔϦιʔε͕ൃੜ͢Δ
ରԠࡦ "TTFU4ZNCPMTͷࣗಈੜΛແޮʹ͢Δ A3TXJGU3FTPVSDFTAΛ໌ࣔ͢Δ 3ʓʓͷݺͼग़͠Λ"TTFU4ZNCPMTʹࠩ͠ସ͑Δ
ରԠࡦ "TTFU4ZNCPMTͷࣗಈੜΛແޮʹ͢Δ
ରԠࡦ "TTFU4ZNCPMTͷࣗಈੜΛແޮʹ͢Δ A3TXJGU3FTPVSDFTAΛ໌ࣔ͢Δ 3ʓʓͷݺͼग़͠Λ"TTFU4ZNCPMTʹࠩ͠ସ͑Δ
ରԠࡦ A3TXJGU3FTPVSDFTAΛ໌ࣔ͢Δ import SwiftUI import RswiftResources struct Item { var
image: ImageResource } struct ItemView: View { var item: Item var body: some View { VStack { Image(item.image) } } } #if DEBUG struct ItemView_Previews: PreviewProvider { static var previews: some View { Group { ItemView(item: .init(image: R.image.foo)) // Cannot convert value of type } } } #endif
ରԠࡦ A3TXJGU3FTPVSDFTAΛ໌ࣔ͢Δ import SwiftUI import RswiftResources struct Item { var
image: RswiftResources.ImageResource } struct ItemView: View { var item: Item var body: some View { VStack { Image(item.image) } } } #if DEBUG struct ItemView_Previews: PreviewProvider { static var previews: some View { Group { ItemView(item: .init(image: R.image.foo)) // no error } } } #endif
ରԠࡦ "TTFU4ZNCPMTͷࣗಈੜΛແޮʹ͢Δ A3TXJGU3FTPVSDFTAΛ໌ࣔ͢Δ 3ʓʓͷݺͼग़͠Λ"TTFU4ZNCPMTʹࠩ͠ସ͑Δ
ରԠࡦ 3ʓʓͷݺͼग़͠Λ"TTFU4ZNCPMTʹࠩ͠ସ͑Δ import SwiftUI import RswiftResources struct Item { var
image: ImageResource } struct ItemView: View { var item: Item var body: some View { VStack { Image(item.image) } } } #if DEBUG struct ItemView_Previews: PreviewProvider { static var previews: some View { Group { ItemView(item: .init(image: R.image.foo)) // Cannot convert value of type } } } #endif
ରԠࡦ 3ʓʓͷݺͼग़͠Λ"TTFU4ZNCPMTʹࠩ͠ସ͑Δ import SwiftUI import RswiftResources struct Item { var
image: ImageResource } struct ItemView: View { var item: Item var body: some View { VStack { Image(item.image) } } } #if DEBUG struct ItemView_Previews: PreviewProvider { static var previews: some View { Group { ItemView(item: .init(image: .foo)) // no error } } } #endif
ରԠࡦ 3ʓʓͷݺͼग़͠Λ"TTFU4ZNCPMTʹࠩ͠ସ͑Δ import SwiftUI struct Item { var image: ImageResource
} struct ItemView: View { var item: Item var body: some View { VStack { Image(item.image) } } } #if DEBUG struct ItemView_Previews: PreviewProvider { static var previews: some View { Group { ItemView(item: .init(image: .foo)) // no error } } } #endif
؆୯ΜɺΤϥʔҎ֎ม͑ͨΖ ʌ AЧ ů
ΜͳΘ͚͋Δ͔͍ bшb㱬ኯˑ Ч ůŰƅŖƃ
3TXJGUͰݺͼग़ͤΔόϦΤʔγϣϯ // Image(UIKit) R.image.foo() UIImage(resource: R.image.foo) // Image(SwiftUI) Image(R.image.foo) Image(uiImage:
R.image.foo()!) Image(uiImage: UIImage(resource: R.image.foo)!) // Color(UIKit) R.color.primary() UIColor(resource: R.color.primary) //Color(SwiftUI) Color(R.color.primary) Color(uiColor: R.color.primary()!) Color(uiColor: UIColor(resource: R.color.primary)!)
͜ΕΛݸݸݟͯॻ͖͑Δͱ͔ ʌůɾ㱼ɾA ŷžŷž ਖ਼نදݱͰؤு͍͍͚ͬͯͲ
ͦ͜Ͱ
4XJGU4ZOUBY
4XJGU4ZOUBY w 4XJGUίʔυͷߏจղੳɺݕࠪɺੜɺม͕Ͱ͖Δ"QQMFͷϥΠϒϥϦ w IUUQTHJUIVCDPNBQQMFTXJGUTZOUBY w ؛͞Μͷ͋Γ͕͍͓ͨ w IUUQTTQFBLFSEFDLDPNLJTIJLBXBLBUTVNJNBTUFSJOHTXJGUTZOUBY
4XJGU4ZOUBYͰΓ͍ͨ͜ͱ w 3JNBHFGPP 6**NBHF SFTPVSDF3JNBHFGPP Λ 6**NBHF SFTPVSDFGPP ʹม͢Δ w
*NBHF 3JNBHFGPP Λ*NBHF GPP ʹม͢Δ w 3DPMPSGPP 6*$PMPS SFTPVSDF3DPMPSGPP Λ 6*$PMPS SFTPVSDFGPP ʹม͢Δ w $PMPS 3DPMPSGPP Λ$PMPS GPP ʹม͢Δ
Δ͜ͱ w ύλʔϯຖʹରԠͨ͠มॲཧΛ࣮͢Δ w 3JNBHFGPP 6**NBHF SFTPVSDFGPP w 3JNBHFGPP
6**NBHF SFTPVSDFGPP w 6**NBHF SFTPVSDF3JNBHFGPP 6**NBHF SFTPVSDFGPP w 6**NBHF SFTPVSDF3JNBHFGPP 6**NBHF SFTPVSDFGPP w *NBHF 3JNBHFGPP *NBHF GPP w *NBHF VJ*NBHF3JNBHFGPP *NBHF GPP w *NBHF VJ*NBHF6**NBHF SFTPVSDF3JNBHFGPP *NBHF GPP
Δ͜ͱ w ύλʔϯຖʹରԠͨ͠มॲཧ3FXSJUFSΛ࣮ͯ͠࠶ؼతʹݺͼग़͢ w 3JNBHFGPP 3JNBHFGPP 6**NBHF SFTPVSDFGPP w
6**NBHF SFTPVSDF3JNBHFGPP 6**NBHF SFTPVSDF3JNBHFGPP 6**NBHF SFTPVSDFGPP w *NBHF 3JNBHFGPP *NBHF GPP w *NBHF VJ*NBHF3JNBHFGPP *NBHF VJ*NBHF6**NBHF SFTPVSDF 3JNBHFGPP *NBHF GPP
3JNBHFGPP 6**NBHF SFTPVSDFGPP final class RswiftResourceRewriter: SyntaxRewriter { private let
rewritableAssets = [ "image": "UIImage", "color": "UIColor" ] override func visit(_ node: FunctionCallExprSyntax) -> ExprSyntax { if let base = node.calledExpression.as(MemberAccessExprSyntax.self), let expr = visit(base).as(MemberAccessExprSyntax.self), base != expr, let assetType = base.base?.as(MemberAccessExprSyntax.self)?.declName.baseName.text, let convertedType = rewritableAssets[assetType] { // return `UIImage(resource: .expr)` or `UIColor(resource: .expr)` syntax } }
3JNBHFGPP 6**NBHF SFTPVSDFGPP 3JNBHFGPPGPP override func visit(_ node: MemberAccessExprSyntax) ->
ExprSyntax { if let base = node.base?.as(MemberAccessExprSyntax.self), base.base?.as(DeclReferenceExprSyntax.self)?.baseName.text == "R" { let resourceName = node.declName.baseName.text if rewritableAssets.keys.contains(base.declName.baseName.text) { return ExprSyntax( MemberAccessExprSyntax( leadingTrivia: node.leadingTrivia, period: .periodToken(), name: .identifier(resourceName.camelized), trailingTrivia: node.trailingTrivia ) ) } } return super.visit(node) }
3JNBHFGPP 6**NBHF SFTPVSDFGPP 3JNBHFGPP 3JNBHFGPP override func visit(_ token: ForceUnwrapExprSyntax)
-> ExprSyntax { if let expr = token.expression.as(FunctionCallExprSyntax.self), let converted = visit(expr).as(FunctionCallExprSyntax.self), expr != converted { return ExprSyntax(converted) } return super.visit(token) }
6**NBHFΛม final class UIImageRewriter: SyntaxRewriter { private let typeName =
"UIImage" override func visit(_ node: FunctionCallExprSyntax) -> ExprSyntax { if case typeName = node.calledExpression.as(DeclReferenceExprSyntax.self)?.baseName.text, let argument = node.arguments.first, argument.label?.text == "resource" { let newArgument = rswiftResourceRewriter.visit(argument) return ExprSyntax(node.with(\.arguments, [newArgument])) } if let member = node.calledExpression.as(MemberAccessExprSyntax.self), case "init" = member.declName.baseName.text, let argument = node.arguments.first, argument.label?.text == "resource" { let newArgument = rswiftResourceRewriter.visit(argument) return ExprSyntax(node.with(\.arguments, [newArgument])) } return super.visit(node) }
6**NBHFΛม 6**NBHF SFTPVSDF3JNBHFGPP 6**NBHF SFTPVSDFGPP final class UIImageRewriter: SyntaxRewriter {
private let typeName = "UIImage" override func visit(_ node: FunctionCallExprSyntax) -> ExprSyntax { if case typeName = node.calledExpression.as(DeclReferenceExprSyntax.self)?.baseName.text, let argument = node.arguments.first, argument.label?.text == "resource" { let newArgument = rswiftResourceRewriter.visit(argument) return ExprSyntax(node.with(\.arguments, [newArgument])) } if let member = node.calledExpression.as(MemberAccessExprSyntax.self), case "init" = member.declName.baseName.text, let argument = node.arguments.first, argument.label?.text == "resource" { let newArgument = rswiftResourceRewriter.visit(argument) return ExprSyntax(node.with(\.arguments, [newArgument])) } return super.visit(node) }
6**NBHFΛม JOJU SFTPVSDF3JNBHFGPP 6**NBHF SFTPVSDFGPP final class UIImageRewriter: SyntaxRewriter {
private let typeName = "UIImage" override func visit(_ node: FunctionCallExprSyntax) -> ExprSyntax { if case typeName = node.calledExpression.as(DeclReferenceExprSyntax.self)?.baseName.text, let argument = node.arguments.first, argument.label?.text == "resource" { let newArgument = rswiftResourceRewriter.visit(argument) return ExprSyntax(node.with(\.arguments, [newArgument])) } if let member = node.calledExpression.as(MemberAccessExprSyntax.self), case "init" = member.declName.baseName.text, let argument = node.arguments.first, argument.label?.text == "resource" { let newArgument = rswiftResourceRewriter.visit(argument) return ExprSyntax(node.with(\.arguments, [newArgument])) } return super.visit(node) }
3"$$POWFSUFS w 3TXJGUUP"TTFU$BUBMPH w IUUQTHJUIVCDPN,*3"$$POWFSUFS
%FNP
·ͱΊ w 3TXJGUͷ"1*ͱ9DPEFͷ"TTFU4ZNCPMT͕$PO fl JDU͢Δ w 4XJGU4ZOUBYΛͬͯ3JNBHF̋̋Λ"TTFU4ZNCPMTʹมͰ͖Δ w શ3TXJGUʹ·ͩ՝͕͋Δ w
"TTFU4ZNCPMT͕9*#4UPSZCPBSE%BUB"TTFUTʹରԠ͍ͯ͠ͳ͍
ελʔ͍ͩ͘͞ ҙ༁ɿUIY