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
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
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
メールのエイリアス機能を履き違えない
isshinfunada
0
140
壊れたパーサから始める関数型設計と構成的なパーサ #fp_matsuri
raiga0310
2
410
20260722_microCMSで考える、AI時代のコンテンツ運用設計
yosh1
0
140
Claude Team Plan導入・ガイド
tk3fftk
0
240
信頼性について考えてみる(SRE NEXT 2026 miniLT)
hayama17
0
220
yield再入門 #phpcon
o0h
PRO
0
820
エンジニアにデザインハーネスを 〜デザインプロセスを規定するためのハーネス〜 / Design harness from an engineer's perspective
rkaga
2
1.8k
AI がコードを書く時代における新卒エンジニアの仕事風景 (2026) / New Graduate Engineers in the Era of AI Coding (2026)
sushichan044
0
240
今さら聞けない .NET CLI
htkym
0
150
AI時代に設計が 最大の生産性レバーになる 意図駆動開発とデータを消さない設計|Don't Delete Your Data or Your Intent — Design as the Deepest Lever in the AI Era
tomohisa
0
110
テーブルをDELETEした
yuzneri
0
120
AI Engineeringは、AIプロダクトだけのものか? 〜AIがソフトウェアを作る時代の新しい当たり前〜 / No AI in your product. AI Engineering in your development.
rkaga
4
270
Featured
See All Featured
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
25
2k
Optimising Largest Contentful Paint
csswizardry
37
3.8k
The AI Revolution Will Not Be Monopolized: How open-source beats economies of scale, even for LLMs
inesmontani
PRO
3
3.7k
Jamie Indigo - Trashchat’s Guide to Black Boxes: Technical SEO Tactics for LLMs
techseoconnect
PRO
0
530
Evolving SEO for Evolving Search Engines
ryanjones
0
250
How to build a perfect <img>
jonoalderson
1
5.8k
A Soul's Torment
seathinner
6
3.1k
Avoiding the “Bad Training, Faster” Trap in the Age of AI
tmiket
0
200
How to Think Like a Performance Engineer
csswizardry
28
2.7k
How to make the Groovebox
asonas
2
2.3k
AI Search: Where Are We & What Can We Do About It?
aleyda
0
7.7k
Large-scale JavaScript Application Architecture
addyosmani
515
110k
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