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
iOSDC 2021 Restore
Search
coe
September 19, 2021
Technology
6
1.9k
iOSDC 2021 Restore
iOSDC 2021 バックグラウンドでアプリがキルされても怖くない!アプリの状態を元に戻すリストア機能の全て
coe
September 19, 2021
Tweet
Share
More Decks by coe
See All by coe
すべてのヘルスケアデータを紐解く.pdf
coe
0
2.4k
About HealthKit nutrition
coe
0
370
Kotlin Dynamic type
coe
0
320
iOSDC 2023 Web in tvOS and watchOS
coe
1
580
iOSDC 2023 Push To Talk
coe
1
1.8k
iOSDC手で触れずにアプリを動かす技術
coe
1
1.5k
iOSDC令和時代のXML処理を考える
coe
3
2.2k
詳解Storyboard
coe
7
3.5k
あなたの知らない連絡先の世界
coe
15
8.1k
Other Decks in Technology
See All in Technology
MC906491 を見据えた Microsoft Entra Connect アップグレード対応
tamaiyutaro
1
410
Developer Summit 2025 [14-D-1] Yuki Hattori
yuhattor
17
3.5k
7日間でハッキングをはじめる本をはじめてみませんか?_ITエンジニア本大賞2025
nomizone
2
450
開発者が自律的に AWS Security Hub findings に 対応する仕組みと AWS re:Invent 2024 登壇体験談 / Developers autonomously report AWS Security Hub findings Corresponding mechanism and AWS re:Invent 2024 presentation experience
kaminashi
0
180
飲食店予約台帳を支えるインタラクティブ UI 設計と実装
siropaca
6
1.3k
ゆもつよがこの30年間自ら経験してきたQA、テストの歴史と未来
ymty
4
720
室長と気ままに学ぶマイクロソフトのビジネスアプリケーションとビジネスプロセス
ryoheig0405
0
230
第13回 Data-Centric AI勉強会, 画像認識におけるData-centric AI
ksaito_osx
0
340
トラシューアニマルになろう ~開発者だからこそできる、安定したサービス作りの秘訣~
jacopen
2
670
BLEAでAWSアカウントのセキュリティレベルを向上させよう
koheiyoshikawa
0
190
CZII - CryoET Object Identification 参加振り返り・解法共有
tattaka
0
170
データの品質が低いと何が困るのか
kzykmyzw
6
980
Featured
See All Featured
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
4
400
Side Projects
sachag
452
42k
Agile that works and the tools we love
rasmusluckow
328
21k
GitHub's CSS Performance
jonrohan
1030
460k
[RailsConf 2023] Rails as a piece of cake
palkan
53
5.2k
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
7
620
Intergalactic Javascript Robots from Outer Space
tanoku
270
27k
It's Worth the Effort
3n
184
28k
The Pragmatic Product Professional
lauravandoore
32
6.4k
The Illustrated Children's Guide to Kubernetes
chrisshort
48
49k
Writing Fast Ruby
sferik
628
61k
Designing Experiences People Love
moore
139
23k
Transcript
όοΫάϥϯυͰΞϓϦ͕Ωϧ͞Εͯ ා͘ͳ͍ʂ ΞϓϦͷঢ়ଶΛݩʹ͢ϦετΞػೳͷશͯ J04%$5TVZPTIJIZVHB
όοΫάϥϯυͰΞϓϦ͕Ω ϧ͞Εͯා͘ͳ͍
όοΫάϥϯυͰΞϓϦ͕Ωϧ͞Εͯා͘ͳ͍ w J04%$ w ৄղ4UPSZCPBSEͰগ͠ղઆ
.PSF*OGPSNBUJPO IUUQTXXXZPVUVCFDPNXBUDI WV'I6DIC0@TUT ৄղ4UPSZCPBSE
όοΫάϥϯυͰΞϓϦ͕Ω ϧ͞Εͯා͘ͳ͍
"QQ" -BVODI4DSFFO ΞϓϦ"Λىಈ
ΞϓϦ"Λར༻த
ΞϓϦ"Ͱɺ͍͍͘͢͝໘·ͰਐΜͰ͍Δ
ΞϓϦ# ΞϓϦ#͔Β௨
ΞϓϦ#ʹભҠͯ͠ɺ৭ʑΔ "QQ#
ΞϓϦ"ʹΔ "QQ" -BVODI4DSFFO
ΞϓϦ"࠷ॳ͔Βʹͳ͍ͬͯΔ
ΞϓϦར༻ΛΊΔ
ΞϓϦ͕ऴྃͨ࣌͠ͷରࡦ
ͦΕɺ4UPSZCPBSEͰ ରࡦͰ͖·͢Α
3FTUPSBUJPO
3FTUPSBUJPO w 6*"QQMJDBUJPO%FMFHBUFͰঢ়ଶͷอଘͱ෮ݩΛ༗ޮʹ͢Δ w ෮ݩ͍ͨ͠7JFX$POUSPMMFSʹରͯ͠3FTUPSBUJPO*%Λઃఆ͢Δ
6*"QQMJDBUJPO%FMFHBUFͰ ঢ়ଶͷอଘͱ෮ݩΛ༗ޮʹ͢Δ
ঢ়ଶͷอଘͱ෮ݩΛ༗ޮʹ͢Δ w 6*"QQMJDBUJPO%FMFHBUFͷ3FTUPSFܥϝιουΛUSVFʹ͢Δ w BQQMJDBUJPO @TIPVME4BWF4FDVSF"QQMJDBUJPO4UBUF w BQQMJDBUJPO @TIPVME3FTUPSF4FDVSF"QQMJDBUJPO4UBUF
w BQQMJDBUJPO @TIPVME4BWF"QQMJDBUJPO4UBUF w BQQMJDBUJPO @TIPVME3FTUPSF"QQMJDBUJPO4UBUF
extension AppDelegate { func application(_ application: UIApplication, shouldSaveApplicationState coder: NSCoder)
-> Bool { return true } func application(_ application: UIApplication, shouldRestoreApplicationState coder: NSCoder) -> Bool { return true } @available(iOS 13.2, *) func application(_ application: UIApplication, shouldSaveSecureApplicationState coder: NSCoder) -> Bool { return true } @available(iOS 13.2, *) func application(_ application: UIApplication, shouldRestoreSecureApplicationState coder: NSCoder) -> Bool { return true } }
෮ݩ͍ͨ͠7JFX$POUSPMMFSʹରͯ͠ 3FTUPSBUJPO*%Λઃఆ͢Δ
3FTUPSBUJPO*%ͷઃఆ ෮ݩ͍ͨ͠ରͷ7JFX$POUSPMMFSશͯʹϢχʔΫͳ3FTUPSBUJPO*%ΛׂΓͯΔ
ϦετΞͷςετ
ϦετΞͷςετ తͷը໘·ͰભҠ͢Δ ྫͱͯ͠.PEBMભҠΛߦ͏ ʢ/BWJHBUJPOભҠͰՄʣ
ϦετΞͷςετ ҰϗʔϜը໘ʹΔ
ϦετΞͷςετ 9DPEF͔Β3VOΛߦ͏
ϦετΞͷςετ ௨ৗͰ͋Εॳظը໘͔Β࢝· Δͱ͜Ζɺઌఔͷଓ͖ͷϞʔμ ϧը໘͔ΒΞϓϦ͕࢝·Δ
͔͠͠
໊લڧ
ॴଐגࣜձࣾ"NB[JB
w #-&ͰJ04"OESPJEؒͰͦͦ͜͜ େ͖ͳαΠζͷσʔλ௨৴Λ࣮ݱ͢Δ -$"1͋ΔΑ w ͋ͳͨͷΒͳ͍࿈བྷઌͷੈք w ৄղ4UPSZCPBSE
झຯύϯ८Γ
ϦετΞͷςετ ϗʔϜը໘ʹͬͨޙɺ࠶9DPEF3VO
ը໘ભҠอͨΕ͍ͯΔ͕ɺೖ ྗͨ͠σʔλ͕ফ͍͑ͯΔ
/4$PEFS
7JFX$POUSPMMFSͷσʔλ෮ݩͷΈ w ϦετΞͰ෮ݩ͞ΕΔͷ4UPSZCPBSE্ʹઃఆͯ͋͠ΔσʔλͷΈ w ͭ·Γɺ4UPSZCPBSEͷσʔλҎ֎͍࣋ͬͯͳ͍ͷͰɺޙ͔Βೖྗ ͨ͠ςΩετσʔλ͍࣋ͬͯͳ͍ w 4UPSZCPBSEҎ֎ͷσʔλΛ࣋ͨͤΔ͜ͱ͕ඞཁ w ͦͷσʔλͷอ࣋ઌ͕/4$PEFS
$PEFSͷσʔλՃ w 6*7JFX$POUSPMMFSFODPEF3FTUPSBCMF4UBUF w ϗʔϜը໘ʹભҠ͢Δͱ͖ͳͲʹݺΕΔ w $PEFSʹର͠ɺ֤छFODPEF ͰύϥϝʔλΛอଘ͓ͯ͘͠ w 6*7JFX$POUSPMMFSEFDPEF3FTUPSBCMF4UBUF
w ֤छEFDPEF ͰɺFODPEF3FTUPSBCMF4UBUFͰอଘ͓͍ͯͨ͠σʔλΛ औಘ͢Δ
$PEFSͷσʔλՃɺ෮ݩ class HobbyViewController: UIViewController { @IBOutlet weak var textField: UITextField!
override func encodeRestorableState(with coder: NSCoder) { super.encodeRestorableState(with: coder) coder.encode(textField.text, forKey: "textFieldText") } override func decodeRestorableState(with coder: NSCoder) { super.decodeRestorableState(with: coder) textField.text = coder.decodeObject(forKey: "textFieldText") as? String } }
࠶֬ೝ
໊લڧ
ॴଐגࣜձࣾ"NB[JB
w #-&ͰJ04"OESPJEؒͰͦͦ͜͜ େ͖ͳαΠζͷσʔλ௨৴Λ࣮ݱ͢Δ -$"1͋ΔΑ w ͋ͳͨͷΒͳ͍࿈བྷઌͷੈք w ৄղ4UPSZCPBSE
झຯύϯ८Γ
ϦετΞͷςετ ϗʔϜը໘ʹͬͨޙɺ࠶9DPEF3VO
w #-&ͰJ04"OESPJEؒͰͦͦ͜͜ େ͖ͳαΠζͷσʔλ௨৴Λ࣮ݱ͢Δ -$"1͋ΔΑ w ͋ͳͨͷΒͳ͍࿈བྷઌͷੈք w ৄղ4UPSZCPBSE
·ͱΊ w 6*"QQMJDBUJPO%FMFHBUFͰঢ়ଶͷอଘͱ෮ݩΛ༗ޮʹ͢Δ w ෮ݩ͍ͨ͠7JFX$POUSPMMFSʹରͯ͠3FTUPSBUJPO*%Λઃఆ͢Δ w /4$PEFSʹɺඞཁͳσʔλΛอଘ͠ɺ෮ݩͷλΠϛϯάͰ/4$PEFS͔Β σʔλΛऔಘ͢Δ
ࠓ·Ͱͷ͜ͱΕ͍ͯͩ͘͞
4UPSZCPBSEͷϦετΞ w ΞϓϦ͕4DFOF%FMFHBUFʹରԠ͍ͯ͠Δ߹͜ͷϦετΞ͕ಈ͔ͳ͍ w ผͳରԠΛ͢Δඞཁ͕͋Δ
/46TFS"DUJWJUZ
ΞϓϦͷঢ়ଶͷอଘͱ෮ݩ w /46TFS"DUJWJUZΛอଘ͢Δ w ىಈ࣌ɺ/46TFS"DUJWJUZ͔ΒσʔλΛ෮ݩ͢Δ
/46TFS"DUJWJUZͷอଘ
*OGPQMJTUͷฤू w *OGPQMJTUʹ/46TFS"DUJWJUZ5ZQFTΛՃ͢Δ w "SSBZ4USJOH
/46TFS"DUJWJUZͷอଘ w /46TFS"DUJWJUZͷอଘͷλΠϛϯάɺ7JFX$POUSPMMFSͷ WJFX%JE"QQFBSҎ߱ʹߦ͏
func updateUserActivity() { // ݱࡏͷγʔϯͷUserActivityͷऔಘ ͳ͚Ε࡞Δ var currentUserActivity = view.window?.windowScene?.userActivity
if currentUserActivity == nil { currentUserActivity = NSUserActivity(activityType: "com.example.staterestore.mainActivity") } // UserActivityʹσʔλΛ٧ΊΔ currentUserActivity?.title = "λΠτϧ" currentUserActivity?.targetContentIdentifier = "unique id" currentUserActivity?.addUserInfoEntries(from: ["key1": "value1"]) currentUserActivity?.addUserInfoEntries(from: ["key2": 2]) // ݱࡏͷγʔϯʹUserActivityΛ͢ view.window?.windowScene?.userActivity = currentUserActivity }
/46TFS"DUJWJUZͷอଘ w ݱࡏͷγʔϯ͔Β/46TFS"DUJWJUZΛऔΓग़͢ w WJFXXJOEPX XJOEPX4DFOF VTFS"DUJWJUZ͔Βݱࡏͷ/46TFS"DUJWJUZΛऔΓग़͢ w OJMͷ߹ɺ/46TFS"DUJWJUZΛ࡞͢Δ w
BDUJWJUZ5ZQFʹઌఔ*OGPQMJTUͰઃఆͨ͠ͷΛ͏ w /46TFS"DUJWJUZʹର͠ɺ෮ݩʹඞཁͳใΛ٧ΊΔʢޙड़ʣ w ใΛ٧ΊͨޙɺWJFXXJOEPX XJOEPX4DFOF VTFS"DUJWJUZʹ/46TFS"DUJWJUZΛฦ ͢
/46TFS"DUJWJUZʹઃఆ͢Δใ w UJUMF w UBSHFU$POUFOU*EFOUJ fi FS w VTFS*OGP BEE6TFS*OGP&OUSJFT
w ෮ݩʹඞཁͳΛ٧ΊΔ
/46TFS"DUJWJUZΛอଘ͢ΔλΠϛϯά VQEBUF6TFS"DUJWJUZ Λ࣮ߦ͢ΔλΠϛϯάྫ w WJFX%JE"QQFBS w ֤छσʔλ͕มΘͬͨͱ͖ w ฤू͞ΕͨςΩετ w
Ϣʔβʔ͕બதͷΞΠςϜͷมߋ
ϗʔϜը໘ભҠ࣌ʹ/46TFS"DUJWJUZΛอଘ w 4DFOF%FMFHBUFʹTUBUF3FTUPSBUJPO"DUJWJUZ GPS Λ࣮͢Δ w 7JFX$POUSPMMFSͰઃఆ͍ͯͨ͠6TFS"DUJWJUZΛฦ͢ w લड़ͷॲཧΛߦͳ͍ͬͯΕɺTDFOFVTFS"DUJWJUZΛฦ͚ͩ͢Ͱ0,
func stateRestorationActivity(for scene: UIScene) -> NSUserActivity? { scene.userActivity }
ΞϓϦͷ෮ݩ
ΞϓϦͷ෮ݩ w TDFOF @TDFOF6*4DFOF XJMM$POOFDU5PTFTTJPO6*4DFOF4FTTJPO PQUJPOTDPOOFDUJPO0QUJPOT6*4DFOF$POOFDUJPO0QUJPOT w ΞϓϦىಈͷλΠϛϯάͰɺTFTTJPOTUBUF3FTUPSBUJPO"DUJWJUZΛ֬ೝ͢
Δ w TUBUF3FTUPSBUJPO"DUJWJUZͰอଘ͍ͯͨ͠/46TFS"DUJWJUZ͕औಘͰ͖Δ w ը໘ભҠͳͲࣗͰߏங͢Δඞཁ͕͋Δ w 6TFS*OGPͷઃܭ͕ඞཁ
guard let activity = session.stateRestorationActivity else { return } if
activity.activityType == "com.example.staterestore.mainActivity" { let storyboard = UIStoryboard(name: "Main", bundle: .main) if let userInfo = activity.userInfo { // userInfoͷ༰ͰతͷViewControllerΛ෮ݩ͢Δ let detailParentViewController = storyboard.instantiateViewController(withIdentifier: "DetailParentViewController") detailParentViewController.hoge = userInfo[“detailParentViewControllerValue"] // ը໘ભҠΛ෮ݩ͢Δ(ྫͱͯ͠NavigationControllerͷ߹) if let navigationController = window?.rootViewController as? UINavigationController { navigationController.pushViewController(detailParentViewController, animated: false) } } }
4XJGU6*ͰͷϦετΞ
4DFOF4UPSBHF
4DFOF4UPSBHF struct ContentView: View { @State private var isPresented: Bool
= false var body: some View { VStack { Button(action: { isPresented.toggle() }) { Text("Button") } } .sheet(isPresented: $isPresented, content: { Text("present") }) } } 4IFFUද੍ࣔޚΛߦ͏JT1SFTFOUFEΛϦετΞରʹؚΊͯɺ࣍ճىಈ࣌ʹγʔτͷ 1SFTFOUঢ়ଶΛอͭʹʁ
4DFOF4UPSBHF struct ContentView: View { @SceneStorage("ContentView.isPresented") private var isPresented: Bool
= false var body: some View { VStack { Button(action: { isPresented.toggle() }) { Text("Button") } } .sheet(isPresented: $isPresented, content: { Text("present") }) } } !4UBUFΛ!4DFOF4UPSBHFʹม͑Δͱɺ࣍ճىಈ͕࣌อͨΕΔ Ωʔ໊ϢχʔΫʹ͢Δ
4XJGU6* /46TFS"DUJWJUZ
struct ContentView: View { @State private var selectedTitle: Book? =
nil var body: some View { NavigationView { List(bookList) { book in NavigationLink(destination: SwiftUIView(book: $selectedTitle), tag: book, selection: $selectedTitle, label: { Text(book.title) }) } .navigationTitle(Text("Նᕸੴ")) } .onContinueUserActivity("app.hyuga.SwiftUIActivity.restore", perform: { userActivity in selectedTitle = try! userActivity.typedPayload(Book.self) }) } } struct Book: Identifiable, Codable, Hashable { var id: String { title } let title: String let contents: String } τοϓϖʔδͷ7JFXʹPO$POUJOVF6TFS"DUJWJUZΛ࣮ VTFS"DUJWJUZ͔ΒΛΒͬͯ4UBUFΛߋ৽͢ΔΑ͏ʹ͓ͯ͘͜͠ͱͰɺ"DUJWJUZىಈ࣌ʹ/BWJHBUJPO-JOL͕࡞ಈ͢Δ
struct SwiftUIView: View { @Binding var book: Book? var body:
some View { Text(book?.contents ?? "") .userActivity("app.hyuga.SwiftUIActivity.restore", { activity in let returnBook: Book if let activityBook = try? activity.typedPayload(Book.self) { returnBook = activityBook } else { returnBook = book! } activity.title = returnBook.title activity.targetContentIdentifier = returnBook.id activity.isEligibleForSearch = true activity.userInfo = ["title":returnBook.title, "contents": returnBook.contents] }) .navigationTitle(book?.title ?? "") } } VTFS"DUJWJUZΛ࣮ͯ͠ɺBDUJWJUZ͕͋Δ͜ͱΛΒͤΔ JT&MJHJCMF'PS4FBSDIΛUSVFʹͯ͠ɺ4QPUMJHIUݕࡧ͔Β"DUJWJUZ͕ىಈͰ͖ΔΑ͏ʹ͓ͯ͘͠
4XJGU6* /46TFS"DUJWJUZ εϙοτϥΠτݕࡧͰɺຊ Λ։͘͜ͱ͕ՄೳʹͳΔ
ࢀߟϦϯΫ w 3FTUPSJOH:PVS"QQ`T4UBUF w IUUQTEFWFMPQFSBQQMFDPNEPDVNFOUBUJPOVJLJU VJWJFXDPOUSPMMFSSFTUPSJOH@ZPVS@BQQ@T@TUBUF w 3FTUPSJOH:PVS"QQ`T4UBUFXJUI4XJGU6* w IUUQTEFWFMPQFSBQQMFDPNEPDVNFOUBUJPOVJLJU
WJFX@DPOUSPMMFSTSFTUPSJOH@ZPVS@BQQ@T@TUBUF@XJUI@TXJGUVJ