Быстрая фатальная ошибка: "попробуй!" В выражении неожиданно возникла ошибка: Ошибка Domain=NSCocoaErrorDomain Code=3840 "Мусор в конце".

У меня была эта ошибка с моей быстрой программой, я использую 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()
}
}

3 ответа

Решение

1. Не используйте NS... занятия в Swift3. Например:

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
}

Как уже отмечалось в некоторых других ответах, проблема в том, что вы заставляете десериализацию JSON и предполагаете, что она всегда будет работать 100% времени. Это почти всегда не хороший выбор. Есть два варианта решения этой проблемы:

1) Использовать попробовать? вместо

Это может быть хорошим выбором, если утверждение, которое вы пытаетесь выполнить, терпит неудачу, тогда вы получите ноль, а затем сможете сделать что-то на основе этого. Например, вы можете изменить функцию 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()
}

Обратите внимание, что каждое из охранных утверждений дает вам возможность выполнить какое-то действие и вернуться. Возможно, вы хотите отобразить сообщение о том, что произошла ошибка сети.

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. Этот пост является хорошим примером:

Правильно разбор JSON в Swift 3

Ваш код полон проблем.

"Попробуй!" выражение вылетает, если код, который вы вызываете, выдает исключение. Вот почему вы терпите крах. Не делайте этого, особенно при обработке данных из внешнего источника. использование do { try.. } catch { } вместо. Есть множество примеров быстрых блоков try/catch в документации Apple и онлайн.

Сообщение об ошибке, которое вы получаете, говорит вам, что не так. Вы получаете мусорные символы в конце вашего потока данных JSON. Преобразуйте ваш поток данных в строку и зарегистрируйте ее.

Не использовать as! либо, если вы не уверены, что объект может быть приведен к нужному типу. (Силовые броски терпят крах при неудаче.)

Как говорит @OOPer в своем комментарии, вы не должны загружать данные из URL в основной теме. Это блокирует пользовательский интерфейс до тех пор, пока загрузка не будет завершена, и может привести к остановке приложения, если загрузка займет слишком много времени. Вы должны использовать асинхронный метод, как URLSession,

Другие вопросы по тегам