ios - swift fatal error : 'try!' expression unexpectedly raised an error: Error Domain=NSCocoaErrorDomain Code=3840 "Garbage at end."

标签 ios swift swift3

我的 swift 程序一直有这个错误,我正在使用 PHP 和 MySQL 作为数据库。我要将数据从数据库显示到 TableView 。之前是可以的,但是在模拟器上运行了几次之后,我一直遇到同样的错误

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) 使用尝试?相反

如果您尝试执行的语句失败,这可能是一个不错的选择,那么您将获得 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) 使用 do try catch block 。

我想试试?更适合您的情况,但在某些情况下 do try catch block 可能更合适。例如:

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。这篇文章就是一个很好的例子:

Correctly Parsing JSON in Swift 3

关于ios - swift fatal error : 'try!' expression unexpectedly raised an error: Error Domain=NSCocoaErrorDomain Code=3840 "Garbage at end.",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41661298/

相关文章:

python - 是否可以使用 Python 为 iOS 和 Android 编写跨平台应用程序?

ios - iOS 5和iOS 6中UITabbar的区别

swift - 使用 NSKeyedArchiver 将对象传递给 WatchKit

ios - 不允许 Xcode 位置访问

swift - 将 NSMenuItem 的状态设置为 On

ios - OpenGL 透明背景 Xamarin

ios - 无法下标任何对象类型的值

swift - 使用 Locksmith 和 Swift 4 删除 token

xcode - 如何在可以打开和关闭的循环中添加 SKnode

跨步快速控制流程