Ios 快速致命错误:';试试看';表达式意外引发错误:错误域=nscocaerorDomain代码=3840“;最后是垃圾。”;

Ios 快速致命错误:';试试看';表达式意外引发错误:错误域=nscocaerorDomain代码=3840“;最后是垃圾。”;,ios,swift,swift3.0.2,Ios,Swift,Swift3.0.2,我的swift程序出现了这个错误,我使用PHP和MySQL作为数据库。我将显示从数据库到tableview的数据。它以前可以工作,但是在模拟器上运行了几次之后,我也遇到了同样的错误 class Home: UIViewController, UITableViewDelegate, UITableViewDataSource { @IBOutlet weak var btnaddclass: UIButton! @IBOutlet var tableView: UITableView!

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

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

let url = URL(string: "http://localhost/show_db.php")
let data = Data(contentsOf: url!)
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")
    }
}
2.对异常使用do-try-catch

do {
    try ...
} catch {
    // handle exception
}
3.不要使用
as除非您确定它是哪个类。使用以下命令:

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

你的代码充满了问题

如果调用的代码抛出异常,“try!”表达式将崩溃。这就是你崩溃的原因。不要这样做,尤其是在处理来自外部源的数据时。改用
do{try..}catch{}
。在苹果的文档和在线文档中,有大量的swift-try/catch块示例

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

不要将
用作任意一个,除非确定对象可以转换为所需类型。(强制转换失败时会崩溃。)


正如@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语句都为您提供了执行某些操作并返回的机会。可能您想显示一条消息,说明出现了网络错误

2) 使用do-try捕捉块。 我想试试?更适合您的情况,但do-try-catch块在某些情况下可能更合适。例如:

let url = URL(string: "http://localhost/show_db.php")
let data = Data(contentsOf: url!)
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。这篇文章就是一个很好的例子:


非常类似,请尝试在返回的数据不是有效的JSON时执行此操作。显示返回数据的文本表示形式。还有一点,你不应该在主线程中调用
NSData.init(contentsOf:)
。这么多
-崩溃是您的编码风格的预期行为。太好了!这是一个很大的帮助,因为我刚刚接触这个。我尝试了你的建议,但it输出了这个问题:无法读取数据,因为它的格式不正确。@EnriqueJimmarC.Panti
JSONSerialization.jsonObject(…
仅适用于JSON格式。@EnriqueJimmarC.Panti如果您将试图反序列化的数据打印到控制台,可能会有所帮助。我猜来自服务器的JSON无效。我只是从教程中复制了它。哈哈,谢谢@Duncan C,我对异步方法不太熟悉。我只是不熟悉这个。你能告诉我更多关于它的信息吗它?看看我对这个问题的回答:如果你从一个教程中复制了这段代码,你应该会找到另一个教程。这段代码就像一个雷区,充斥着坏的编码习惯和潜在的崩溃。你能发布一个到教程的链接吗?谢谢@Guillermo Alvarez!巨大的帮助。我会尝试你的建议。