ios - Can't get State Restoration to work with Programmatic Navigation Controller -
i'm unable state restoration working navigation controller. using swift , not want use storyboards (programmatic). i've found online either not in swift or using storyboards.
in demo code below, viewcontroller contains simple pickerview, , selection
variable keeps track of picker selection. appdelegate presented 2 options. option 1, no navigation controller used , state of picker restored fine, not restored navigation controller in option 2. (in code below, option 1 commented out , option 2 active).
you can copy & paste code below fresh singleview application , should reproduce i've described. (i tested it)
appdelegate code:
import uikit @uiapplicationmain class appdelegate: uiresponder, uiapplicationdelegate { var window: uiwindow? func application(_ application: uiapplication, shouldsaveapplicationstate coder: nscoder) -> bool { return true } func application(_ application: uiapplication, shouldrestoreapplicationstate coder: nscoder) -> bool { return true } func application(_ application: uiapplication, willfinishlaunchingwithoptions launchoptions: [uiapplicationlaunchoptionskey : any]? = nil) -> bool { window = uiwindow(frame: uiscreen.main.bounds) window?.makekeyandvisible() let pickervc = viewcontroller() //option 1: no navc used //window?.rootviewcontroller = pickervc //option 2: navc used let navc = uinavigationcontroller(rootviewcontroller: pickervc) navc.restorationidentifier = "pickernav" window?.rootviewcontroller = navc return true } // func application(_ application: uiapplication, viewcontrollerwithrestorationidentifierpath identifiercomponents: [any], coder: nscoder) -> uiviewcontroller? { // let storyboard = uistoryboard(name: "main", bundle: nil) // if let lastitem = identifiercomponents.last as? string { // return storyboard.instantiateviewcontroller(withidentifier: lastitem) // } // return nil // } }
viewcontroller code:
import uikit class viewcontroller: uiviewcontroller, uipickerviewdelegate, uipickerviewdatasource { var pickerview: uipickerview! var selection = 0 let group = ["fruit","vegetable","meat","bread"] override func viewdidload() { super.viewdidload() restorationidentifier = "pickervc" setuppicker() } override func viewdidappear(_ animated: bool) { super.viewdidappear(animated) pickerview.selectrow(selection, incomponent: 0, animated: false) } override func encoderestorablestate(with coder: nscoder) { coder.encode(selection, forkey: "selection") super.encoderestorablestate(with: coder) } override func decoderestorablestate(with coder: nscoder) { selection = coder.decodeinteger(forkey: "selection") super.decoderestorablestate(with: coder) } func setuppicker() { pickerview = uipickerview() pickerview.delegate = self pickerview.datasource = self view.addsubview(pickerview) pickerview.translatesautoresizingmaskintoconstraints = false pickerview.leadinganchor.constraint(equalto: view.layoutmarginsguide.leadinganchor).isactive = true pickerview.trailinganchor.constraint(equalto: view.layoutmarginsguide.trailinganchor).isactive = true pickerview.centeryanchor.constraint(equalto: view.centeryanchor).isactive = true pickerview.heightanchor.constraint(equaltoconstant: 300).isactive = true } func numberofcomponents(in pickerview: uipickerview) -> int { return 1 } func pickerview(_ pickerview: uipickerview, numberofrowsincomponent component: int) -> int { return group.count } func pickerview(_ pickerview: uipickerview, didselectrow row: int, incomponent component: int) { selection = pickerview.selectedrow(incomponent: 0) } func pickerview(_ pickerview: uipickerview, viewforrow row: int, forcomponent component: int, reusing view: uiview?) -> uiview { let pickerlabel = uilabel() pickerlabel.font = uifont.systemfont(ofsize: 26) pickerlabel.textalignment = .center pickerlabel.text = group[row] pickerlabel.textcolor = .white return pickerlabel } }
details of testing: option 1, changing picker followed cmd-shift-h causes selection
variable saved in encoderestorablestate
. click xcode stop button , run again, , selection
variable restored in decoderestorablestate
. contrast, option 2 state restoration not work because decoderestorablestate
never called selection
variable not restored. however, breakpoint @ viewdidappear
shows navigationcontroller?.restorationidentifier
= "pickernav" , restorationidentifier
= "pickervc"
from i've read, suspect may need use viewcontrollerwithrestorationidentifierpath
in appdelegate, didn't know how use correctly. attempt @ bottom of appdelegate (the code commented out) causes app crash.
you can add extension viewcontroller , make conform protocol uiviewcontrollerrestoration
, implement viewcontrollerwithrestorationidentifierpath
method. in viewcontroller
's viewdidload
function add restorationclass
restorationidentifer
like
override func viewdidload() { super.viewdidload() restorationidentifier = "pickervc" restorationclass = viewcontroller.self setuppicker() } extension viewcontroller: uiviewcontrollerrestoration { static func viewcontroller(withrestorationidentifierpath identifiercomponents: [any], coder: nscoder) -> uiviewcontroller? { let vc = viewcontroller() return vc }
}
add code in viewcontroller class , delete viewcontrollerwithrestorationidentifierpath
method have added in appdelegate
Comments
Post a Comment