Почему я не могу получить доступ к своему классу модели в проекте Swift?

#ios #json #swift #uitableview #nsdictionary

Вопрос:

Как получить доступ к моей модели из ViewController и использовать данные модели для загрузки в табличном представлении????

Ссылка на Исходный Код

Мой ViewController выглядит так

 import UIKit

class ViewController: UIViewController {
    var cclm: CountryCodeListModel?

    override func viewDidLoad() {
        super.viewDidLoad()
        Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(hello), userInfo: nil, repeats: true)
        readLocalJSONFile(forName: "countryList")

        // Do any additional setup after loading the view.
    }

    override func viewDidAppear(_ animated: Bool) {
        
    }
    
    @objc func hello()
     {
        print(cclm?.data?[0].flag)
     }

}
 

и мой класс моделей выглядит так

 struct CountryCodeList : Decodable {
    var alpha2Code: String?
    var alpha3Code: String?
    var flag      : String?
    var name      : String?
    var code      : String?
}

public struct CountryCodeListModel : Decodable {
    var data      : [CountryCodeList]?
}

var cclm: CountryCodeListModel?


//Method to load json

func readLocalJSONFile(forName name: String) {
    do {
        if let filePath = Bundle.main.path(forResource: name, ofType: "json") {
            let fileUrl = URL(fileURLWithPath: filePath)
            let data = try Data(contentsOf: fileUrl)
            if let countryCodeObject = parse(jsonData: data) {
                cclm = countryCodeObject
                print(cclm?.data?[1].alpha2Code ?? "")  //Printing Correct Value
            }
        }
    } catch {
        print("error: (error)")
    }
}



func parse(jsonData: Data) -> CountryCodeListModel?{
    var dataArray : [Dictionary<String,Any>] = [[:]]
    var country = Dictionary<String,Any>()
    var modelData = Dictionary<String,Any>()
    do {
        // make sure this JSON is in the format we expect
        if let json = try JSONSerialization.jsonObject(with: jsonData, options: []) as? Dictionary<String,Any> {
            dataArray.removeAll()
            for item  in json["data"] as! [Dictionary<String, Any>] {
                country = item
                
                let url = URL(string: country["flag"] as? String ?? "")
                let data = try? Data(contentsOf: url!) //make sure your image in this url does exist, otherwise unwrap in a if let check / try-catch
                let image = UIImage(data: data!)
                let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
                let fileName = url?.lastPathComponent // name of the image to be saved
                let fileURL = documentsDirectory.appendingPathComponent(fileName ?? "")
                if let data = image?.jpegData(compressionQuality: 1.0){
                    do {
                        try data.write(to: fileURL)
                        country["flag"] = fileURL.absoluteString
                        //print("file saved")
                        //urlAsString = fileURL.absoluteString
                    } catch {
                        print("error saving file:", error)
                    }
                }
                
                dataArray.append(country)
                country.removeAll()
                
                    
                
            }
            modelData["data"] = dataArray
            //print(modelData)
            let jsonData1 = try JSONSerialization.data(withJSONObject: modelData, options: [])
            
            do {
                    let decodedData = try JSONDecoder().decode(CountryCodeListModel.self, from: jsonData1)
                
                    return decodedData
                } catch {
                    print("error: (error)")
                }
            
        }
    } catch let error as NSError {
        print("Failed to load: (error.localizedDescription)")
    }
    return nil
}
 

Постановка проблемы:

Я читаю локальный json, беру значение URL-адреса ключа флага и загружаю соответствующие изображения в локальный. Как только я скачаю, я беру localpath и обновляю в словаре, а затем создаю объект JSON и обновляю свой класс модели.

Теперь я пытаюсь получить доступ к своему классу модели из ViewController, как показано ниже

 print(CountryCodeListModel?.data?[0].name) //check screenshot for error
 print(cclm?.data?[0].flag)                 // this prints nil always
 

Пожалуйста, проверьте скриншоты ошибок, прилагаемые 2

Мой JSON выглядит так

 {
   "meta":{
      "success":true,
      "message":"Successfully retrieved country details",
      "code":"200"
   },
   "data":[
      {
         "alpha2Code":"AF",
         "alpha3Code":"AFG",
         "flag":"https://raw.githubusercontent.com/DevTides/countries/master/afg.png",
         "name":"Afghanistan",
         "code":" 93"
      },
      {
         "alpha2Code":"AX",
         "alpha3Code":"ALA",
         "flag":"https://raw.githubusercontent.com/DevTides/countries/master/ala.png",
         "name":"Aland Islands",
         "code":" 358"
      },
      {
         "alpha2Code":"AL",
         "alpha3Code":"ALB",
         "flag":"https://raw.githubusercontent.com/DevTides/countries/master/alb.png",
         "name":"Albania",
         "code":" 355"
      },
      {
         "alpha2Code":"DZ",
         "alpha3Code":"DZA",
         "flag":"https://raw.githubusercontent.com/DevTides/countries/master/dza.png",
         "name":"Algeria",
         "code":" 213"
      },
      {
         "alpha2Code":"AS",
         "alpha3Code":"ASM",
         "flag":"https://raw.githubusercontent.com/DevTides/countries/master/asm.png",
         "name":"American Samoa",
         "code":" 1684"
      }
]
}
 

Комментарии:

1. CountryCodeListModel это класс. Вы можете думать об этом как о плане. Он определяет свойства flag и name … но это всего лишь чертеж. Это не настоящая вещь.

2. cclm?.data?[0].flag это правильный путь. Но он равен нулю, потому что вы никогда его не инициализировали (инициализация похожа на создание реального объекта из этого чертежа. Вам нужно сделать cclm = CountryCodeListModel() )

3. Но вы расшифровываете из JSON. if let countryCodeObject = parse(jsonData: data) { cclm = countryCodeObject } инициализируется cclm , но только в том случае, если parse() метод не возвращает ноль. Похоже, что это возвращает ноль… что означает, что с вашим JSON может быть что-то не так.

4. Почему вы загружаете одни и те же данные из пакета каждые 3 секунды? И почему вы преобразуете данные три раза туда и обратно (с JSONSerialization помощью и JSONDecoder )? Это довольно запутанно.

5. @aheze CountryCodeListModel-это структура, а не класс.

Ответ №1:

Вы пытаетесь расшифровать то, чего не существует.

 print(CountryCodeListModel?.data?[0].name) //check screenshot for error
 print(cclm?.data?[0].flag)                 // this prints nil always
 

В приведенном выше коде указано, что вы хотите:

  1. имя
  2. переменные данные в позиции 0
  3. структура CountryCodeListModel .

То, что ты хочешь сделать, это:

  1. имя
  2. переменная в положении 0
  3. ЭКЗЕМПЛЯР структуры CountryCodeListModel .

Например…

 func readLocalJSONFile(forName name: String) {
    do {
        if let filePath = Bundle.main.path(forResource: name, ofType: "json") {
            let fileUrl = URL(fileURLWithPath: filePath)
            let data = try Data(contentsOf: fileUrl)
            if let countryCodeObject = parse(jsonData: data) {
                cclm = countryCodeObject
                print(cclm?.data?[1].alpha2Code ?? "")  //Printing Correct Value
                print(cclm?.data?[0].flag ?? "")
                print(countryCodeObject?.data[0].flag ?? "") // Same as the line above
            }
        }
    } catch {
        print("error: (error)")
    }
}
 

Если вы не пытаетесь использовать static переменную (в которой вы бы использовали CountryCodeListModel.data ), вам необходимо убедиться, что вы действительно используете экземпляр структуры или объект класса для ссылки на свои свойства.

предостережение

CountryCodeListModel это структура. CountryCodeListModel() является экземпляром структуры CountryCodeListModel . Поскольку у вас может быть несколько экземпляров структуры, вам необходимо ссылаться на определенную структуру при доступе к данным. Таким образом, CountryCodeListModel.data ничего не получится, и это нужно сделать CountryCodeListModel().data . В данном случае у вас есть cclm.data .

Комментарии:

1. Вы когда-нибудь читали мой вопрос ??? я также могу получить правильный результат печати в файле readlocaljson, который я знаю. Все, что я спрашиваю, это почему мое заявление о печати всегда равно нулю в ViewController

2. Все, что я пытаюсь сделать, это распечатать это в viewcontroller и попытаться получить правильное значение вместо нуля. Так у тебя есть какие-нибудь идеи на этот счет ?

3. Из моего заявления о печати я вижу, что я правильно добавил данные в модель внутри readLocalJSONFile (), и после этого, когда я пытался распечатать, это всегда было равно нулю. Это и есть моя точная проблема

4. 1. Я прочитал ваш вопрос. 2. Я пытаюсь помочь, не будь идиотом. 3. print(CountryCodeListModel?.data?[0].name) не мог бы быть дальше от работы, если бы у вас не было static переменной, которая не является тем, что у вас есть. Вот почему print(cclm?.data?[1].alpha2Code ?? "") работает и print(CountryCodeListModel?.data?[0].name) не работает. Ваш print(CountryCodeListModel?.data?[0].name) всегда равен нулю, потому что вы не ссылаетесь ни на какие данные, как указано в моем ответе. Вам нужно сослаться на КОНКРЕТНЫЙ ЭКЗЕМПЛЯР вашей структуры. например print(cclm?.data?[0].flag ?? "")

5. Я вижу одну из твоих проблем… У вас есть print(cclm?.data?[0].flag ?? "") внутри вашей hello функции, которая ссылается на вашу cclm внутреннюю часть вашего класса ViewController . Конечно, в нем не будет никаких данных, вы не установили cclm ничего равного. Так что в нынешнем cclm виде БУДЕТ что-то, но в настоящее время это НИЧТО. Вам придется это сделать cclm = SOMETHING , тогда у него будут данные.