Upgrade to Pro — share decks privately, control downloads, hide ads and more …

iOSDC 2021 Restore

coe
September 19, 2021

iOSDC 2021 Restore

iOSDC 2021 バックグラウンドでアプリがキルされても怖くない!アプリの状態を元に戻すリストア機能の全て

coe

September 19, 2021
Tweet

More Decks by coe

Other Decks in Technology

Transcript

  1. 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 } }
  2. $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 } }
  3. 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 }
  4. /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Λฦ ͢
  5. ΞϓϦͷ෮ݩ w TDFOF @TDFOF6*4DFOF XJMM$POOFDU5PTFTTJPO6*4DFOF4FTTJPO  PQUJPOTDPOOFDUJPO0QUJPOT6*4DFOF$POOFDUJPO0QUJPOT  w ΞϓϦىಈͷλΠϛϯάͰɺTFTTJPOTUBUF3FTUPSBUJPO"DUJWJUZΛ֬ೝ͢

    Δ w TUBUF3FTUPSBUJPO"DUJWJUZͰอଘ͍ͯͨ͠/46TFS"DUJWJUZ͕औಘͰ͖Δ w ը໘ભҠͳͲ͸ࣗ෼Ͱߏங͢Δඞཁ͕͋Δ w 6TFS*OGPͷઃܭ͕ඞཁ
  6. 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) } } }
  7. 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ঢ়ଶΛอͭʹ͸ʁ
  8. 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ʹม͑Δͱɺ࣍ճىಈ࣌΋஋͕อͨΕΔ Ωʔ໊͸ϢχʔΫʹ͢Δ
  9. 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͕࡞ಈ͢Δ
  10. 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͕ىಈͰ͖ΔΑ͏ʹ͓ͯ͘͠