[英]Best way to keep JSONSerialization from crashing my app when there is no internet?
Okay so I found a few different answers to very similar questions but most suggest using an if statement or a try/catch block and my code has both. 好的,所以我找到了几个非常相似的问题的不同答案,但大多数建议使用if语句或try / catch块,我的代码都有。 I'm making a call to my web service which returns JSON, which I use JSONSerialization to pull it out for parsing.
我正在调用我的Web服务,该服务返回JSON,我使用JSONSerialization将其拉出来进行解析。 As the title suggests my app crashes and burns when there is no internet and I was hoping someone could tell me the best way to handle this issue.
由于标题表明我的应用程序在没有互联网时崩溃和烧伤,我希望有人能告诉我处理这个问题的最佳方法。 I'll put my method below:
我将把我的方法放在下面:
func getCategories() {
activityIndicator?.startAnimating()
tableView.isUserInteractionEnabled = false
categoryArray = []
let configuration = URLSessionConfiguration.default
configuration.requestCachePolicy = NSURLRequest.CachePolicy.reloadIgnoringLocalCacheData
let getQuizTitlesURL = URL(string: "https://myservice.com/my/directory/selectcategories.php")
URLSession.shared.dataTask(with: getQuizTitlesURL! as URL, completionHandler: {(data, response, error) in
do{
if let parsedData = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? NSArray {
var name:String
var categoryId:Int
var quizCount:Int
for index in 0...parsedData.count-1 {
let aObject = parsedData[index] as! [String : AnyObject]
name = (aObject["Name"] as? String)!
quizCount = Int(aObject["Count"] as! String)!
categoryId = (Int((aObject["ID"] as? String)!)!)
let category:Category = Category(name: name, quizCount: quizCount, categoryId: categoryId)
self.categoryArray.append(category)
}
}
if let HTTPResponse = response as? HTTPURLResponse {
print(HTTPResponse)
let statusCode = HTTPResponse.statusCode
if statusCode == 200 {
print("Success")
}
}
}catch let error as NSError {
print(error)
}
DispatchQueue.main.async {
self.tableView.reloadData()
self.activityIndicator?.stopAnimating()
self.tableView.isUserInteractionEnabled = true
}
}).resume()
}
I personally use Reachability and I check if the connection is available before making the call 我个人使用Reachability ,我在拨打电话之前检查连接是否可用
var reachability = Reachability()! // I declare this in the appDelegate as global variable
func getCategories() {
if reachability.isReachable {
// your code
} else {
let alertViewController = UIAlertController(title: "No Connection" , message: "There is something wrong with your internet Connection. Please check and try again", preferredStyle: .alert)
let okAction = UIAlertAction(title: okTitle, style: .default) { (uialertAction) in
alertViewController.dismiss(animated: true, completion: nil)
}
alertViewController.addAction(okAction)
self.present(alertViewController, animated: true, completion: nil)
}
}
Do not use force unwrapping ever. 不要使用力量展开。
guard let data = data else {
// no data
return
}
do {
if let parsedData = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as? NSArray {
. . .
Also, as @joaofs said, check network availability before you request. 另外,正如@joaofs所说,请在请求之前检查网络可用性。 Even you check this, everything is possible during request-response.
即使你检查这一点,在请求 - 响应期间一切皆有可能。 Like network disconnected just after request.
就像请求后网络断开一样。
I wouldn't try to make an API call if there is no network available check this library . 如果没有可用的网络,我不会尝试进行API调用检查此库 。
On the other hand, you should make sure you get an HTTP status code indicating a successful response before you try to serialize the payload. 另一方面,在尝试序列化有效负载之前,应确保获得指示响应成功的HTTP状态代码。
Make a new swift file (Cocoa class) and add name it Reachability.swift. 创建一个新的swift文件(Cocoa类)并将其命名为Reachability.swift。 In this file add this code:
在此文件中添加以下代码:
import UIKit
import SystemConfiguration
protocol Utilities {
}
extension NSObject:Utilities{
enum ReachabilityStatus {
case notReachable
case reachableViaWWAN
case reachableViaWiFi
}
var currentReachabilityStatus: ReachabilityStatus {
var zeroAddress = sockaddr_in()
zeroAddress.sin_len = UInt8(MemoryLayout<sockaddr_in>.size)
zeroAddress.sin_family = sa_family_t(AF_INET)
guard let defaultRouteReachability = withUnsafePointer(to: &zeroAddress, {
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
SCNetworkReachabilityCreateWithAddress(nil,$0)
}
}) else {
return .notReachable
}
var flags: SCNetworkReachabilityFlags = []
if !SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) {
return .notReachable
}
if flags.contains(.reachable) == false {
// The target host is not reachable.
return .notReachable
}
else if flags.contains(.isWWAN) == true {
// WWAN connections are OK if the calling application is using the CFNetwork APIs.
return .reachableViaWWAN
}
else if flags.contains(.connectionRequired) == false {
// If the target host is reachable and no connection is required then we'll assume that you're on Wi-Fi...
return .reachableViaWiFi
}
else if (flags.contains(.connectionOnDemand) == true || flags.contains(.connectionOnTraffic) == true) && flags.contains(.interventionRequired) == false {
// The connection is on-demand (or on-traffic) if the calling application is using the CFSocketStream or higher APIs and no [user] intervention is needed
return .reachableViaWiFi
}
else {
return .notReachable
}
}
}
Now implement this where you want to implement your web service and stuff like this. 现在实现这个,你想要实现你的Web服务和这样的东西。
func checkReachability(){
if (currentReachabilityStatus == .reachableViaWiFi) || (currentReachabilityStatus == .reachableViaWWAN) {
// if wifi-connection or mobile-network-connection
// YOUR_CODE
} else {
print("There is no internet connection")
// make an alert to go to settings and enable mobile data/wifi.
let alertController = UIAlertController (title: "Connectivity error!", message: "Go to Settings -> Enable Wi-Fi/Mobile Data", preferredStyle: .alert)
let settingsAction = UIAlertAction(title: "Settings", style: .default) { (_) -> Void in
guard let settingsUrl = URL(string: "App-Prefs:root") else {
return
}
if UIApplication.shared.canOpenURL(settingsUrl) {
UIApplication.shared.open(settingsUrl, completionHandler: { (success) in
print("Settings opened: \(success)") // Prints true
})
}
}
alertController.addAction(settingsAction)
present(alertController, animated: true, completion: nil)
}
}
Ok don't thank me. 好的,不要谢谢我。 Good luck!!!!
祝好运!!!! :D
:d
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.