简体   繁体   English

快速致命的错误:'试试!' 表达式意外地引发了一个错误:错误Domain = NSCocoaErrorDomain Code = 3840“垃圾结束时”。

[英]Swift fatal error: 'try!' expression unexpectedly raised an error: Error Domain=NSCocoaErrorDomain Code=3840 “Garbage at end.”

I have been having this error with my swift program, I am using PHP and MySQL as database. 我的swift程序出现了这个错误,我使用PHP和MySQL作为数据库。 I am to display the data from database to tableview. 我将数据从数据库显示到tableview。 it was working before but after a few times of running it to the emulator, I've been having the same error 它以前工作但经过几次运行到模拟器后,我一直有同样的错误

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

As some of the other answers have noted, the issue is that you are forcing the JSON deserialization and assuming that it will always, 100% of the time, work. 正如其他一些答案所指出的那样,问题在于您正在强制进行JSON反序列化,并假设它始终在100%的时间内正常工作。 This is almost always not a good choice. 这几乎总是不太好的选择。 There are two options to solve this: 有两种方法可以解决这个问题:

1) Use try? 1)使用试试? instead 代替

This can be a good choice if the statement that you are trying to perform fails, then you will obtain nil and then can do something based off of that. 如果您尝试执行的语句失败,那么这将是一个很好的选择,然后您将获得nil然后可以基于此做一些事情。 For example, you can change your get() function to: 例如,您可以将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()
}

Notice that each of the guard statements gives you an opportunity to perform some action and return. 请注意,每个保护语句都为您提供了执行某些操作并返回的机会。 Maybe you want to display a message stating there was a network error. 也许您想显示一条消息,指出存在网络错误。

2) Use a do try catch block. 2)使用do try catch块。

I think using try? 我想用try? is more appropriate for your case but a do try catch block can be appropriate in some cases. 更适合你的情况但是在某些情况下尝试catch块是合适的。 For example: 例如:

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

There are other improvements that can be made to your overall approach but since you are a beginner (as you noted), it is best to learn one thing at a time. 您可以对整体方法进行其他改进,但由于您是初学者(如您所述),最好一次学习一件事。

Also, as others have mentioned, you should not get the data from the main thread. 此外,正如其他人所提到的,您不应该从主线程获取数据。 Use URLSession instead. 请改用URLSession。 This post is a good example: 这篇文章就是一个很好的例子:

Correctly Parsing JSON in Swift 3 正确解析Swift 3中的JSON

1.Don't use NS... classes in Swift3. 1.不要在Swift3中使用NS...类。 For example: 例如:

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

2.Use do-try-catch for exception. 2.使用do-try-catch进行异常处理。

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

3.Don't use as! 3.不要as! unless you're sure which class it is. 除非你确定它是哪一堂课。 Use this: 用这个:

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

Your code is full of problems. 你的代码充满了问题。

The "try!" “试试!” expression crashes if the code you are calling throws an exception. 如果您正在调用的代码抛出异常,表达式将崩溃。 That is why you are crashing. 这就是你崩溃的原因。 Don't do that, especially in the handling of data from an external source. 不要这样做,尤其是在处理来自外部源的数据时。 Use do { try.. } catch { } instead. 请改用do { try.. } catch { } There are tons of examples of swift try/catch blocks in Apple's documentation and online. 在Apple的文档和在线中有很多swift try / catch块的例子。

The error message you are getting is telling you what's wrong. 你得到的错误信息是告诉你什么是错的。 You're getting garbage characters at the end of your JSON data stream. 您在JSON数据流的末尾获得了垃圾字符。 Convert your data stream to a string and log it. 将数据流转换为字符串并进行记录。

Don't use as! 不要as! either, unless you're positive that the object can be cast to the desired type. 要么,除非你肯定对象可以被强制转换为所需的类型。 (Force-casts crash when they fail.) (强制转换失败后会崩溃。)

As @OOPer says in their comment, you should not be loading data from an URL on the main thread. 正如@OOPer在评论中所说,您不应该从主线程上的URL加载数据。 That locks up the UI until the load is done, and may cause your app to be killed if the load takes too long. 这会锁定UI直到加载完成,如果加载时间过长,可能会导致应用程序被杀死。 You should use an async method like URLSession . 您应该使用像URLSession这样的异步方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 错误 = 错误域 = NSCocoaErrorDomain 代码 = 3840 “垃圾结束。” - error = Error Domain=NSCocoaErrorDomain Code=3840 "Garbage at end." SWIFT - JSON 错误 NSCocoaErrorDomain 代码 = 3840“最后是垃圾。” - SWIFT - JSON Error NSCocoaErrorDomain Code=3840 "Garbage at end." 错误域= NSCocoaErrorDomain代码= 3840在iOS迅速? - Error Domain=NSCocoaErrorDomain Code=3840 in iOS swift? 错误域= NSCocoaErrorDomain代码= 3840 - Error Domain=NSCocoaErrorDomain Code=3840 致命错误错误域= NSCocoaErrorDomain代码= 3840“迅速上传图像时,字符0周围的值无效 - Fatal error Error Domain=NSCocoaErrorDomain Code=3840 "Invalid value around character 0 while uploading image in swift 在 Swift5 中解析 JsonString 时出现错误 Domain=NSCocoaErrorDomain Code=3840 - Error Domain=NSCocoaErrorDomain Code=3840 When JsonString parsing in Swift5 错误域=NSCocoaErrorDomain 代码=3840 JSONObject - Error Domain=NSCocoaErrorDomain Code=3840 JSONObject AFNetworking 2.0中的Domain = NSCocoaErrorDomain代码= 3840错误 - Domain=NSCocoaErrorDomain Code=3840 error in afnetworking 2.0 APNS:错误域= NSCocoaErrorDomain代码= 3840 - APNS :Error Domain = NSCocoaErrorDomain Code=3840 错误域= NSCocoaErrorDomain代码= 3840“字符周围的无效值 - Error Domain=NSCocoaErrorDomain Code=3840 "Invalid value around character
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM