How do I check app connectivity correctly?

2019-06-10 02:18发布

问题:

I'm trying to create a function to check the Connectivity when the App loads. If a internet connection is detected, the app should download the JSON data and save the array in UserDefaults, then proceed to the UITableView methods. However, if the internet connection is not found, the app should recover the array on USerDefault to populate another array, then proceed to UItableView methods.

The problem I'm facing, is that when the compiler goes trough UserDefault line to be able to save the array, the app crashes immediately. What I'm doing wrong?

Compiler Error:

) 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)

[FIXED]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()

   }


}

Model:

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

回答1:

The array should be endcoded to Data before saving , as it's array of custom objects

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)
}

//

Since now you encode & decode

struct Cerveja:Codable {--}

//

Also I don't vote for saving in userDefaults consider CoreData