Swift fatal error: 'try!' expression unexpectedly raised an error: Error Domain=NSCocoaErrorDomain Code=3840 "Garbage at end."
Swift fatal error: 'try!' expression unexpectedly raised an error: Error Domain=NSCocoaErrorDomain Code=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()
}
}
1.Don不要在 Swift3 中使用 NS...
classes。例如:
let url = URL(string: "http://localhost/show_db.php")
let data = Data(contentsOf: url!)
2.Use do-try-catch 例外。
do {
try ...
} catch {
// handle exception
}
3.Don 除非您确定 class 是哪个,否则不要使用 as!
。使用这个:
if let array = some as? Array {
// use array now
}
你的代码问题多多。
如果您调用的代码抛出异常,"try!" 表达式会崩溃。这就是你崩溃的原因。不要那样做,尤其是在处理来自外部源的数据时。请改用 do { try.. } catch { }
。在 Apple 的文档和在线文档中有大量 swift try/catch 块的示例。
您收到的错误消息告诉您出了什么问题。您的 JSON 数据流末尾出现乱码。将您的数据流转换为字符串并记录下来。
也不要使用 as!
,除非您确定该对象可以转换为所需的类型。 (Force-casts 失败时崩溃。)
正如@OOPer 在他们的评论中所说,您不应该在主线程上从 URL 加载数据。这会锁定 UI 直到加载完成,如果加载时间过长,可能会导致您的应用程序被终止。您应该使用像 URLSession
.
这样的异步方法
正如其他一些答案所指出的那样,问题是您正在强制 JSON 反序列化并假设它将始终在 100% 的时间内工作。这几乎总是不是一个好的选择。有两种选择可以解决这个问题:
1)用试试?相反
如果您尝试执行的语句失败,这可能是一个不错的选择,那么您将获得 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 语句都为您提供了执行某些操作的机会,并且 return。也许您想显示一条消息,指出出现网络错误。
2) 使用 do try catch 块。
我想试试?更适合您的情况,但在某些情况下 do try catch 块可能更合适。例如:
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。这个post就是一个很好的例子:
我的 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()
}
}
1.Don不要在 Swift3 中使用 NS...
classes。例如:
let url = URL(string: "http://localhost/show_db.php")
let data = Data(contentsOf: url!)
2.Use do-try-catch 例外。
do {
try ...
} catch {
// handle exception
}
3.Don 除非您确定 class 是哪个,否则不要使用 as!
。使用这个:
if let array = some as? Array {
// use array now
}
你的代码问题多多。
如果您调用的代码抛出异常,"try!" 表达式会崩溃。这就是你崩溃的原因。不要那样做,尤其是在处理来自外部源的数据时。请改用 do { try.. } catch { }
。在 Apple 的文档和在线文档中有大量 swift try/catch 块的示例。
您收到的错误消息告诉您出了什么问题。您的 JSON 数据流末尾出现乱码。将您的数据流转换为字符串并记录下来。
也不要使用 as!
,除非您确定该对象可以转换为所需的类型。 (Force-casts 失败时崩溃。)
正如@OOPer 在他们的评论中所说,您不应该在主线程上从 URL 加载数据。这会锁定 UI 直到加载完成,如果加载时间过长,可能会导致您的应用程序被终止。您应该使用像 URLSession
.
正如其他一些答案所指出的那样,问题是您正在强制 JSON 反序列化并假设它将始终在 100% 的时间内工作。这几乎总是不是一个好的选择。有两种选择可以解决这个问题:
1)用试试?相反
如果您尝试执行的语句失败,这可能是一个不错的选择,那么您将获得 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 语句都为您提供了执行某些操作的机会,并且 return。也许您想显示一条消息,指出出现网络错误。
2) 使用 do try catch 块。
我想试试?更适合您的情况,但在某些情况下 do try catch 块可能更合适。例如:
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。这个post就是一个很好的例子: