#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
В приведенном выше коде указано, что вы хотите:
- имя
- переменные данные в позиции 0
- структура
CountryCodeListModel
.
То, что ты хочешь сделать, это:
- имя
- переменная в положении 0
- ЭКЗЕМПЛЯР структуры
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
, тогда у него будут данные.