Быстрая фатальная ошибка: "попробуй!" В выражении неожиданно возникла ошибка: Ошибка 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. Этот пост является хорошим примером:
Ваш код полон проблем.
"Попробуй!" выражение вылетает, если код, который вы вызываете, выдает исключение. Вот почему вы терпите крах. Не делайте этого, особенно при обработке данных из внешнего источника. использование do { try.. } catch { }
вместо. Есть множество примеров быстрых блоков try/catch в документации Apple и онлайн.
Сообщение об ошибке, которое вы получаете, говорит вам, что не так. Вы получаете мусорные символы в конце вашего потока данных JSON. Преобразуйте ваш поток данных в строку и зарегистрируйте ее.
Не использовать as!
либо, если вы не уверены, что объект может быть приведен к нужному типу. (Силовые броски терпят крах при неудаче.)
Как говорит @OOPer в своем комментарии, вы не должны загружать данные из URL в основной теме. Это блокирует пользовательский интерфейс до тех пор, пока загрузка не будет завершена, и может привести к остановке приложения, если загрузка займет слишком много времени. Вы должны использовать асинхронный метод, как URLSession
,