快速致命错误:'try!'表达式意外引发错误:错误域=NSCocoa错误域代码=3840 "Garbage at end."



我的swift程序一直有这个错误,我使用PHP和MySQL作为数据库。我将把数据从数据库显示到表视图。它以前是工作的,但在运行它到模拟器几次之后,我一直有同样的错误

class Home: UIViewController, UITableViewDelegate, UITableViewDataSource {
@IBOutlet weak var btnaddclass: UIButton!
@IBOutlet var tableView: UITableView!
var values: NSArray = []
func get(){
let url = NSURL(string: "http://localhost/show_db.php")
let data = NSData(contentsOf: url! as URL)
values = try! JSONSerialization.jsonObject(with: data! as Data, options:JSONSerialization.ReadingOptions.mutableContainers)as! NSArray
tableView.reloadData()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return values.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! SpecialCell
let maindata = values[indexPath.row] as! [String:AnyObject]
cell.Lblclasstitle.text = maindata["class_title"] as? String
cell.Lblschool.text = maindata["school"] as? String
cell.Lblsubject.text = maindata["subject"] as? String
return cell
}
override func viewDidLoad() {
self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
get()

}
override func viewWillAppear(_ animated: Bool) {
self.tableView.reloadData()
}
}

正如其他一些答案所指出的,问题是您正在强制JSON反序列化,并假设它在100%的情况下始终有效。这几乎总是不是一个好的选择。有两种解决方案:

1) 使用try?相反

如果您试图执行的语句失败,那么这可能是一个不错的选择,然后您将获得nil,然后可以在此基础上执行某些操作。例如,您可以将get()函数更改为:

func get(){
//remove NS prefix and unwrap optional
guard let url = URL(string: "http://localhost/show_db.php") else { return }
//remove ! from url and unwrap optional
guard let data = try? Data(contentsOf: url) else { return }
//try to deserialize. The return value is of type Any
guard let deserializedValues = try? JSONSerialization.jsonObject(with: data) else { return }
//Convert to array of dictionaries
guard let arrayOfDictionaryValues = deserializedValues as? [[String:String]] else { return }
//If you make it here, that means everything is ok
values = arrayOfDictionaryValues

tableView.reloadData()
}

请注意,每个guard语句都为您提供了执行某些操作并返回的机会。也许您想显示一条消息,说明存在网络错误。

2) 使用"尝试接球"挡块

我想用try?更适合您的情况,但在某些情况下,尝试捕获块可能是合适的。例如:

func getWithErrorHandling() {
guard let url = URL(string: "http://localhost/show_db.php") else { return }
do {
let data = try Data(contentsOf: url)
let deserializedValues = try JSONSerialization.jsonObject(with: data)
guard let arrayOfDictionaryValues = deserializedValues as? [[String:String]] else { return }
values = arrayOfDictionaryValues
} catch {
//You should separate the different catch blocks to handle the different types of errors that occur
print("There was an error")
}
}

你的整体方法还有其他改进,但由于你是初学者(正如你所指出的),最好一次学一件事。

此外,正如其他人所提到的,您不应该从主线程获取数据。请改用URLSession。这篇文章就是一个很好的例子:

Swift 3 中JSON的正确解析

1.不要在Swift3中使用NS...类。例如:

let url = URL(string: "http://localhost/show_db.php")
let data = Data(contentsOf: url!)

2.对异常使用do try catch。

do {
try ...
} catch {
// handle exception
}

3.除非你确定它是哪一类,否则不要使用as!。使用这个:

if let array = some as? Array {
// use array now
}

您的代码充满了问题。

如果您正在调用的代码引发异常,则"try!"表达式将崩溃。这就是你崩溃的原因。不要这样做,尤其是在处理来自外部源的数据时。请改用do { try.. } catch { }。在苹果的文档和网上,有很多快速尝试/捕获块的例子。

你收到的错误信息告诉你出了什么问题。您在JSON数据流的末尾得到了垃圾字符。将您的数据流转换为字符串并记录。

也不要使用as!,除非您确信对象可以转换为所需的类型。(强制施放失败时会崩溃。)

正如@OOPer在他们的评论中所说,你不应该从主线程上的URL加载数据。这会锁定UI,直到加载完成,如果加载时间过长,可能会导致您的应用程序被终止。您应该使用类似URLSession的异步方法。

相关内容

最新更新