如何正确检查应用程序连接?

How do I check app connectivity correctly?

我正在尝试创建一个函数来在应用程序加载时检查连接。如果检测到互联网连接,应用程序应下载 JSON 数据并将数组保存在 UserDefaults 中,然后继续执行 UITableView 方法。但是,如果未找到互联网连接,应用程序应恢复 USerDefault 上的数组以填充另一个数组,然后继续使用 UItableView 方法。

我面临的问题是,当编译器通过 UserDefault 行来保存数组时,应用程序会立即崩溃。我做错了什么?

编译器错误:

) for key backupSaved' *** First throw call stack: (0x18257ad8c 0x1817345ec 0x18257ac6c 0x1825b1d08 0x1824e730c 0x1824e5a60 0x1825b2080 0x182515cec 0x1825b2080 0x1825b2304 0x182518d6c 0x182518588 0x182518c54 0x1825bc218 0x1825bf8a0 0x182edaaf4 0x102a794c0 0x102a7452c 0x102e8d314 0x102e45b7c 0x103da11dc 0x103da119c 0x103da5d2c 0x182523070 0x182520bc8 0x182440da8 0x184425020 0x18c45d758 0x102a756b0 0x181ed1fc0) libc++abi.dylib: terminating with uncaught exception of type NSException (lldb)

[固定]ViewController:

import UIKit
import Kingfisher
import Alamofire

var arrCerveja = [Cerveja]()
var arrBackup = [Cerveja]()

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    @IBOutlet weak var tableView: UITableView!

    //TableView DataSource

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if Connectivity.isConnectedToInternet {
            return arrCerveja.count
        } else {
            return arrBackup.count
        }

    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cellID") as! TableViewCell


        if Connectivity.isConnectedToInternet {
            let model = arrCerveja[indexPath.row]

            cell.labelName.text = model.name
            cell.labelDetail.text = "Teor alcoólico: \(model.abv)"
            let resource = ImageResource(downloadURL: URL(string: "\(model.image_url)")!, cacheKey: model.image_url)

            cell.imageViewCell.kf.setImage(with: resource, placeholder: UIImage(named: "icons8-hourglass-48"), options: nil, progressBlock: nil, completionHandler: nil)


            return cell

        } else {
            let model = arrBackup[indexPath.row]

            cell.labelName.text = model.name
            cell.labelDetail.text = "Teor alcoólico: \(model.abv)"
            let resource = ImageResource(downloadURL: URL(string: "\(model.image_url)")!, cacheKey: model.image_url)

            cell.imageViewCell.kf.setImage(with: resource, placeholder: UIImage(named: "icons8-hourglass-48"), options: nil, progressBlock: nil, completionHandler: nil)


            return cell

        }



    }
    //TableView Delegate
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        if Connectivity.isConnectedToInternet {
            performSegue(withIdentifier: "segueId", sender:arrCerveja[indexPath.row])
        } else {
            performSegue(withIdentifier: "segueId", sender:arrBackup[indexPath.row])
        }


    }
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {

        if segue.identifier == "segueId" {

            let des = segue.destination as? TableViewDetalhes

            //.item possui uma propriedade instanciada na TelaDetalheProdutos
            des?.item = (sender as? Cerveja)
            //Segue para CollectionView Categorias
        }
    }

    struct Connectivity {
        static let sharedInstance = NetworkReachabilityManager()!
        static var isConnectedToInternet:Bool {
            return self.sharedInstance.isReachable
        }
    }

    override func viewDidAppear(_ animated: Bool) {
        if Connectivity.isConnectedToInternet {
            print("Connected")
            getApiData { (cerveja) in
                arrCerveja = cerveja
                //Backup
                do{
                    let data = try JSONEncoder().encode(arrCerveja)

                    UserDefaults.standard.set(data, forKey: "backupSaved")
                    //
                    self.tableView.reloadData()
                }catch{print(error)
                }
            }
        } else {
            print("No Internet")
            do{
                if let savedData = UserDefaults.standard.value(forKey: "backupSaved") as? Data {
                    arrBackup = try JSONDecoder().decode([Cerveja].self, from: savedData)
                    self.tableView.reloadData()
                }
            }catch{
                print(error)
            }
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        //SetupNavBarCustom
        navigationController?.navigationBar.setupNavigationBar()

   }


}

型号:

struct Cerveja:Decodable{
    let name:String
    let image_url:String
    let description:String
    let tagline:String
    let abv:Double
    let ibu:Double?
}

数组在保存之前应该被编码为数据,因为它是自定义对象的数组

do {

       ....... write 

       let data = try JSONEncoder().encode(arr)

       UserDefaults.standard.set(data, forKey: "backupSaved")

       // save as data 

       ....... read

        if let  savedData = UserDefaults.standard.value(forKey: "backupSaved") as? Data {
          let savedArr = try JSONDecoder().decode([Cerveja].self, from: savedData)
          // use the array here 
        }

}
catch {
  print(error)
}

//

从现在开始编码和解码

struct Cerveja:Codable {--}

//

此外,我不赞成在 userDefaults 中保存,考虑 CoreData