I made a first try to use NSUserDefaults in an App with UIPickerViews. But the App is crashing while testing / the data isn't displayed in the PickerView. I still try to fix it myself but some help would be great.
ViewController3: Where the user should save data to the NSUserDefault. Therefore there is an textField to write down something and a "Savebutton"
class ViewController3: UIViewController, UITextFieldDelegate {
@IBOutlet weak var textField: UITextField!
...
@IBAction func tappedAddButton(sender: AnyObject) {
var userDefaults:NSUserDefaults = NSUserDefaults.standardUserDefaults()
var exercisesList:NSMutableArray? = userDefaults.objectForKey("exercisesList") as? NSMutableArray
var dataSet:NSMutableDictionary = NSMutableDictionary()
dataSet.setObject(textField.text, forKey: "exercises")
if ((exercisesList) != nil){
var newMutableList:NSMutableArray = NSMutableArray();
for dict:AnyObject in exercisesList!{
newMutableList.addObject(dict as NSDictionary)
}
userDefaults.removeObjectForKey("exercisesList")
newMutableList.addObject(dataSet)
userDefaults.setObject(newMutableList, forKey: "exercisesList")
}else{
userDefaults.removeObjectForKey("exercisesList")
exercisesList = NSMutableArray()
exercisesList!.addObject(dataSet)
userDefaults.setObject(exercisesList, forKey: "exercisesList")
}
userDefaults.synchronize()
self.view.endEditing(true)
textField.text = ""
}
ViewController 1: Where the saved data should be loaded from NSUserDefaults and displayed in pickerView1
class ViewController: UIViewController,UIPickerViewDelegate {
@IBOutlet weak var pickerView1: UIPickerView!
@IBOutlet weak var pickerView2: UIPickerView!
@IBOutlet weak var pickerView3: UIPickerView!
var reps = [["1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24","25"],["x"]]
var weight = [["0","1","2","3","4","5"],["0","1","2","3","4","5","6","7","8","9"],["0","1","2","3","4","5","6","7","8","9"],[","],["0","25","5","75"],["kg","lbs"]]
var exercises:NSMutableArray = NSMutableArray();
override func viewDidLoad() {
super.viewDidLoad()
var userDefaults:NSUserDefaults = NSUserDefaults.standardUserDefaults()
var exercisesListFromUserDefaults:NSMutableArray? = userDefaults.objectForKey("exercisesList") as? NSMutableArray
if ((exercisesListFromUserDefaults) != nil){
exercises = exercisesListFromUserDefaults!
}
self.pickerView1.reloadAllComponents()
}
func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
switch pickerView {
case pickerView1:
return 1
case pickerView2:
return reps.count
case pickerView3:
return weight.count
default:
assertionFailure("Unknown pickerView")
}
}
func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
switch pickerView {
case pickerView1:
return exercises.count
case pickerView2:
return reps[component].count
case pickerView3:
return weight[component].count
default:
assertionFailure("Unknown pickerView")
}
}
func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String! {
switch pickerView {
case pickerView1:
return exercises[row] as String
case pickerView2:
return reps[component][row]
case pickerView3:
return weight[component][row]
default:
assertionFailure("Unknown pickerView")
}
}
}
The reason that your pickerViews are empty is most likely because you have not wired them up to viewController1 as dataSource and delegate. You can do this in the storyboard or in code:
update (part 3)
exercisesList is an array of dictionaries. Here for example you are adding a new item to exercisesList:
where dataSet is created/defined as follows:
so you have a single-item dictionary, with the key "exercises".
Then in viewController1 you are unpacking the array and assuming it is populated with strings, not dictionaries:
Here you are casting a dictionary to a string, which is crashing out.
The clue is in the stack trace line
swift dynamic cast failed
and in these linesIt will work if you correctly extract the string as a value from the dictionary key "exercises":
Alternatively you could populate the array with strings instead of dictionaries (as you only have one entry per entry).
Hopefully you can run this without crashing now!
First, make sure
datasource
&delegate
are set for your pickerViews. You can set them in the storyboard by selecting the pickerView and dragging from dataSource and delegate to your viewController:Or you can set them in
viewDidLoad
like this:Update
You are crashing in the
titleForRow
method. I would guess your exercises array doesn't have any data when that method fires. OverrideviewDidLoad
and move your code fromviewDidAppear
to that method instead. You need to have the data in your exercises array before the picker tries to display it.Another thing I noticed in your
viewDidAppear
method, the first thing you must do in view overrides is call to super likesuper.viewDidAppear(animated)
before your own code. Likewise, you must first callsuper.viewDidLoad()
inviewDidLoad
.Update 2
In your
switch
statements, makepickerView3
the default case and get rid of thoseassertionFailure
lines. The pickerView delegate methods are expecting return values, so this is probably throwing things off as well.