UIPickerView won't display the data loaded fro

2019-07-24 11:12发布

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")
    }
}

}

2条回答
乱世女痞
2楼-- · 2019-07-24 12:03

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:

override  func viewDidLoad() {
    super.viewDidLoad()
    let pickers = [pickerView1,pickerView2,pickerView3]
    for i in 0...2 {
        let pickerView : UIPickerView = pickers[i]
        pickerView.dataSource = self
        pickerView.delegate = self
    }
}

update (part 3)

exercisesList is an array of dictionaries. Here for example you are adding a new item to exercisesList:

 newMutableList.addObject(dataSet)

where dataSet is created/defined as follows:

 var dataSet:NSMutableDictionary = NSMutableDictionary()
 dataSet.setObject(textField.text, forKey: "exercises")

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:

return exercises[row] as String

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 lines

 (ObjectiveC.UIPickerView, titleForRow : Swift.Int, forComponent:     
 Swift.Int) => Swift.ImplicitlyUnwrappedOptional<Swift.String>

It will work if you correctly extract the string as a value from the dictionary key "exercises":

        return exercises[row]["exercises"] as String

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!

查看更多
Viruses.
3楼-- · 2019-07-24 12:04

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:

screenshot

Or you can set them in viewDidLoad like this:

self.pickerView1.dataSource = self
self.pickerView2.delegate = self

Update

You are crashing in the titleForRow method. I would guess your exercises array doesn't have any data when that method fires. Override viewDidLoad and move your code from viewDidAppear 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 like super.viewDidAppear(animated) before your own code. Likewise, you must first call super.viewDidLoad() in viewDidLoad.

Update 2

In your switch statements, make pickerView3 the default case and get rid of those assertionFailure lines. The pickerView delegate methods are expecting return values, so this is probably throwing things off as well.

查看更多
登录 后发表回答