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 设置了 datasource
和 delegate
。您可以通过选择 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 值,因此这也可能会导致失败。
我第一次尝试在带有 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 设置了 datasource
和 delegate
。您可以通过选择 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 值,因此这也可能会导致失败。