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
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
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
240
Reboot a personal app abandoned for 10 years with recent techs
417_72ki
0
120
iTunes・おぼえていますか〜ScriptingBridge今昔物語〜
417_72ki
1
220
The history of entry-point in iOS app Development
417_72ki
0
530
Refactor with using `available` and `deprecated`
417_72ki
3
830
CLIツールにSwift Concurrencyを適用させようとしている話
417_72ki
3
510
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
キャリア迷子上等 ─ "ない道"は自分で作ればいい
16bitidol
3
1.9k
Claspは野良GASの夢をみるか
takter00
0
180
正しくソフトウェアを作る、前提を疑うための認知の視点 / doubt-premise
minodriven
20
6.4k
JJUG CCC 2026 Spring: JSpecify で実現する Kotlin フレンドリーな Java API 設計
ternbusty
1
160
過去最大のMCPアップデート! 2026-07-28 RC版の謎に迫る
licux
6
230
OSもどきOS
arkw
0
480
LLM本来の能力を解き放つサンドボックス技術とAI民主化への適用
yukukotani
3
3.6k
CSC307 Lecture 17
javiergs
PRO
0
320
Agentic UI
manfredsteyer
PRO
0
130
Lemonade + Foundry Toolkit でお手軽アプリ開発
seosoft
1
320
フロントエンドとバックエンドで「1文字」を揃えよう
youkidearitai
PRO
0
250
Vite+ Unified Toolchain for the Web
naokihaba
0
230
Featured
See All Featured
A better future with KSS
kneath
240
18k
Deep Space Network (abreviated)
tonyrice
0
170
Testing 201, or: Great Expectations
jmmastey
46
8.2k
Claude Code のすすめ
schroneko
67
230k
My Coaching Mixtape
mlcsv
0
140
Pawsitive SEO: Lessons from My Dog (and Many Mistakes) on Thriving as a Consultant in the Age of AI
davidcarrasco
0
160
Building a A Zero-Code AI SEO Workflow
portentint
PRO
0
570
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
659
62k
Tell your own story through comics
letsgokoyo
1
950
Collaborative Software Design: How to facilitate domain modelling decisions
baasie
1
250
Statistics for Hackers
jakevdp
799
230k
Making Projects Easy
brettharned
120
6.7k
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