UIPickerView 不会显示从 NSUserDefaults 加载的数据 - 应用程序在加载数据时崩溃

UIPickerView won't display the data loaded from NSUserDefaults - App is crashing while loading data

我第一次尝试在带有 UIPickerView 的应用程序中使用 NSUserDefaults。但是应用程序在测试时崩溃/数据未显示在 PickerView 中。我仍然尝试自己修复它,但有些帮助会很棒。

ViewController3: 用户应将数据保存到 NSUserDefault 的位置。因此,有一个 textField 可以写下一些东西,还有一个 "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: 保存的数据应该从NSUserDefaults加载并显示在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")
    }
}

}

您的 pickerView 为空的原因很可能因为您没有将它们连接到 viewController1 作为数据源和委托。您可以在故事板或代码中执行此操作:

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

更新 ()

exercisesList 是一组字典。例如,您要向 exercisesList 添加一个新项目:

 newMutableList.addObject(dataSet)

其中dataSet是created/defined如下:

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

所以你有一个单项字典,键为 "exercises"。

然后在 viewController1 中解压缩数组并假设它填充了 字符串 ,而不是字典:

return exercises[row] as String

此处您正在将字典转换为字符串,该字符串正在崩溃。

线索在堆栈跟踪行中swift dynamic cast failed 在这些行中

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

如果您从字典键中正确提取字符串作为值,它将起作用 "exercises":

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

或者,您可以用字符串而不是字典填充数组(因为每个条目只有一个条目)。

希望你现在可以 运行 不会崩溃!

首先,确保为您的 pickerView 设置了 datasourcedelegate。您可以通过选择 pickerView 并从 dataSource 拖动并委托到您的 viewController:

来在情节提要中设置它们

或者您可以像这样在 viewDidLoad 中设置它们:

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

更新

您在 titleForRow 方法中崩溃。我猜你的 exercises 数组在该方法触发时没有任何数据。覆盖 viewDidLoad 并将您的代码从 viewDidAppear 移至该方法。在选择器尝试显示数据之前,您需要将数据放入练习数组中。

我在您的 viewDidAppear 方法中注意到的另一件事是,在视图覆盖中您必须做的第一件事是在您自己的代码之前像 super.viewDidAppear(animated) 一样调用 super。同样,您必须先在 viewDidLoad.

中调用 super.viewDidLoad()

更新 2

在您的 switch 语句中,将 pickerView3 设置为默认大小写并删除那些 assertionFailure 行。 pickerView 委托方法需要 return 值,因此这也可能会导致失败。