Ios 如何解析本地Json,从Json对象url下载图像,并将图像路径更新到模型类?
我的本地版本中有以下JsonIos 如何解析本地Json,从Json对象url下载图像,并将图像路径更新到模型类?,ios,json,swift,url,uiimage,Ios,Json,Swift,Url,Uiimage,我的本地版本中有以下Json { "country":[ { "alpha2Code":"AF", "alpha3Code":"AFG", "flag":"https://raw.githubusercontent.com/DevTides/countries/master/afg.png",
{
"country":[
{
"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"
}
]
}
在本文中,我尝试加载此文件名并使用下面的代码解析Json
func readLocalJSONFile(forName name: String) -> Data? {
do {
if let filePath = Bundle.main.path(forResource: name, ofType: "json") {
let fileUrl = URL(fileURLWithPath: filePath)
let data = try Data(contentsOf: fileUrl)
return data
}
} catch {
print("error: \(error)")
}
return nil
}
func parseJson(jsonData: Data) -> countryCode? {
do {
let decodedData = try JSONDecoder().decode(sampleModel.self, from: jsonData)
return decodedData
} catch {
print("error: \(error)")
}
return nil
}
但这里它也更新了我的sampleModel类
问题陈述:
解析之后(更新模型之前),我需要将“flag”键url图像下载到本地,然后使用本地图像路径而不是该键“flag”中的url
之后,我想将这些数据添加到我的模型中
知道我需要做哪些更改吗?我刚刚在您的
parseJson
函数中做了一些更改,请检查并告知我
class SOViewController: UIViewController {
//MARK:- Outlets
//MARK:- Variables
var arrImagesUrls = [URL]()
var arrCountries = [Country]()
var dictMainJson = [String:Any]()
//MARK:- UIViewController Methods
override func viewDidLoad() {
super.viewDidLoad()
let data = readLocalJSONFile(forName: "Country")
let response = parseCodableJson(jsonData: data!)
arrCountries = (response?.country)!
print(arrCountries)
arrImagesUrls.removeAll()
for i in 0...arrCountries.count - 1{
downloadFromServer(url: URL(string: arrCountries[i].flag!)!)
}
print(arrImagesUrls)
changeFlagProperty(arrLocalUrls: arrImagesUrls)
}
//MARK:- Helpers
func readLocalJSONFile(forName name: String) -> Data? {
do {
if let filePath = Bundle.main.path(forResource: name, ofType: "json") {
let fileUrl = URL(fileURLWithPath: filePath)
let data = try Data(contentsOf: fileUrl)
return data
}
} catch {
print("error: \(error)")
}
return nil
}
func parseCodableJson(jsonData: Data) -> Response? {
do {
let decodedData = try JSONDecoder().decode(Response.self, from: jsonData)
let jsonResult = try JSONSerialization.jsonObject(with: jsonData, options: .mutableLeaves)
let result = jsonResult as! [String : Any]
dictMainJson = result
return decodedData
} catch {
print("error: \(error)")
}
return nil
}
//MARK:- Get Directory Path
func getDocumentsDirectory() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let documentsDirectory = paths[0]
let appURL = documentsDirectory.appendingPathComponent("APP_NAME")
if !FileManager.default.fileExists(atPath: appURL.path) {
try! FileManager.default.createDirectory(at: appURL, withIntermediateDirectories: true, attributes: nil)
}
return appURL
}
//MARK:- Download Zip From Server
func downloadFromServer(url:URL) {
let zipFileName = url.lastPathComponent
let downloadPath = self.getDocumentsDirectory()
let newFolder = downloadPath.appendingPathComponent("Flag")
if !FileManager.default.fileExists(atPath: newFolder.path) {
do {
try FileManager.default.createDirectory(atPath: newFolder.path, withIntermediateDirectories: true, attributes: nil)
} catch let error {
print(error.localizedDescription)
}
}
let fileUrl = newFolder.appendingPathComponent(zipFileName)
if FileManager.default.fileExists(atPath: fileUrl.path) {
print("FILE AVAILABLE")
//get images from local folder
arrImagesUrls.append(fileUrl)
} else {
print("FILE NOT AVAILABLE")
let urlSession = URLSession(configuration: .default, delegate: self, delegateQueue: OperationQueue())
let downloadTask = urlSession.downloadTask(with: url)
downloadTask.resume()
}
}
func changeFlagProperty(arrLocalUrls:[URL]) {
let arrDict : [[String:Any]] = (dictMainJson["country"] as? [[String:Any]])!
var arrDicts = [[String:Any]]()
for (i,dict) in arrDict.enumerated() {
var dictData = dict
dictData.updateValue("\(arrLocalUrls[i])", forKey: "flag")
arrDicts.append(dictData)
}
dictMainJson["country"] = arrDicts
if let jsonData = try? JSONSerialization.data(withJSONObject: dictMainJson,options: []) {
print(jsonData)
let response = parseCodableJson(jsonData: jsonData)
arrCountries = (response?.country)!
print(arrCountries)
}
}
}
extension SOViewController : URLSessionDownloadDelegate {
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
print("File Downloaded Location- ", location)
guard let url = downloadTask.originalRequest?.url else {
return
}
let downloadPath = self.getDocumentsDirectory()
let newFolder = downloadPath.appendingPathComponent("Flag")
if !FileManager.default.fileExists(atPath: newFolder.path) {
do {
try FileManager.default.createDirectory(atPath: newFolder.path, withIntermediateDirectories: true, attributes: nil)
} catch let error {
print(error.localizedDescription)
return
}
}
let fileUrl = newFolder.appendingPathComponent(url.lastPathComponent)
if !FileManager.default.fileExists(atPath: fileUrl.path) {
do{
try FileManager.default.copyItem(at: location, to: fileUrl)
print("File Downloaded Location- \(fileUrl)" )
arrImagesUrls.append(fileUrl)
}catch let error {
print("Copy Error: \(error.localizedDescription)")
}
}else {
print("File Downloaded Location- \(fileUrl)" )
arrImagesUrls.append(fileUrl)
}
}
}
响应。swift
import Foundation
struct Response : Codable {
let country : [Country]?
enum CodingKeys: String, CodingKey {
case country = "country"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
country = try values.decodeIfPresent([Country].self, forKey: .country)
}
}
import Foundation
struct Country : Codable {
let alpha2Code : String?
let alpha3Code : String?
let code : String?
let flag : String?
let name : String?
enum CodingKeys: String, CodingKey {
case alpha2Code = "alpha2Code"
case alpha3Code = "alpha3Code"
case code = "code"
case flag = "flag"
case name = "name"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
alpha2Code = try values.decodeIfPresent(String.self, forKey: .alpha2Code)
alpha3Code = try values.decodeIfPresent(String.self, forKey: .alpha3Code)
code = try values.decodeIfPresent(String.self, forKey: .code)
flag = try values.decodeIfPresent(String.self, forKey: .flag)
name = try values.decodeIfPresent(String.self, forKey: .name)
}
}
国家。swift
import Foundation
struct Response : Codable {
let country : [Country]?
enum CodingKeys: String, CodingKey {
case country = "country"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
country = try values.decodeIfPresent([Country].self, forKey: .country)
}
}
import Foundation
struct Country : Codable {
let alpha2Code : String?
let alpha3Code : String?
let code : String?
let flag : String?
let name : String?
enum CodingKeys: String, CodingKey {
case alpha2Code = "alpha2Code"
case alpha3Code = "alpha3Code"
case code = "code"
case flag = "flag"
case name = "name"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
alpha2Code = try values.decodeIfPresent(String.self, forKey: .alpha2Code)
alpha3Code = try values.decodeIfPresent(String.self, forKey: .alpha3Code)
code = try values.decodeIfPresent(String.self, forKey: .code)
flag = try values.decodeIfPresent(String.self, forKey: .flag)
name = try values.decodeIfPresent(String.self, forKey: .name)
}
}
我尝试过以下方法,现在效果很好
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]?
}
private var completionBlocks: ((String) -> Void)?
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
}
struct countrycode列表:可解码{
var alpha2Code:字符串?
var alpha3Code:字符串?
var标志:字符串?
变量名称:字符串?
变量代码:字符串?
}
公共结构CountryCodeListModel:可解码{
变量数据:[CountryCodeList]?
}
私有变量completionBlocks:((字符串)->Void)?
var cclm:CountryCodeListModel?
//方法来加载json
func readLocalJSONFile(forName:String){
做{
如果让filePath=Bundle.main.path(forResource:name,of type:“json”){
让fileUrl=URL(fileURLWithPath:filePath)
let data=try data(contentsOf:fileUrl)
如果让countryCodeObject=parse(jsonData:data){
cclm=countryCodeObject
打印(cclm?.data?[1].alpha2Code???“”//打印正确的值
}
}
}抓住{
打印(“错误:\(错误)”)
}
}
func parse(jsonData:Data)->CountryCodeListModel{
var dataArray:[字典]=[[:]]
var country=字典()
var modelData=字典()
做{
//确保此JSON采用我们期望的格式
如果让json=try JSONSerialization.jsonObject(使用:jsonData,选项:[])作为字典{
dataArray.removeAll()
对于json[“数据”]中的项作为![字典]{
国家=项目
设url=url(字符串:国家[“标志”]为?字符串??)
let data=try?data(contentsOf:url!)//确保此url中的图像确实存在,否则在if-let-check/try-catch中展开
让image=UIImage(数据:data!)
让documentsDirectory=FileManager.default.URL(对于:.documentDirectory,在:.userDomainMask中)。首先!
让fileName=url?.lastPathComponent//要保存的图像的名称
让fileURL=documentsDirectory.appendingPathComponent(文件名??“”)
如果let data=image?.jpeg数据(压缩质量:1.0){
做{
尝试数据写入(到:fileURL)
国家[“标志”]=fileURL.absoluteString
//打印(“文件已保存”)
//urlAsString=fileURL.absoluteString
}抓住{
打印(“保存文件时出错:”,错误)
}
}
dataArray.append(国家/地区)
country.removeAll()
}
modelData[“数据”]=数据数组
//打印(模型数据)
让jsonData1=尝试JSONSerialization.data(使用jsonObject:modelData,选项:[])
做{
让decodedData=try JSONDecoder().decode(CountryCodeListModel.self,from:jsonData1)
返回解码数据
}抓住{
打印(“错误:\(错误)”)
}
}
}将let错误捕获为NSError{
打印(“未能加载:\(错误。localizedDescription)”)
}
归零
}
将图像保留为url并使用第三方解决方案(如king fisher或nuke)允许将url传递到UIImageView并不复杂。此后,我们不需要任何互联网依赖性,这就是将其保留在localKingFisher、Alamofire+image和SDWebImage中的原因,SDWebImage可以使用缓存。如果需要,您应该能够在本地保存它们。请参阅等。管理您自己如何从“缓存”中检索(如果存在)。我正在尝试减少第三方的使用按如下方式使用https://raw.githubusercontent.com/DevTides/countries/master/afg.png)No,不要使用同步下载(数据(contentOf)),这将需要更长的时间。使用URLSession代替标题我怀疑这是否有效,因为在这里,我们是分开的图像下载部分,稍后我们需要更新模型,所以这将是一个艰难的方式,否则你可以做它以及在细胞等待让我更新这个与model@JoakimDanielson谢谢您的建议:)@JOhnMic我检查了您的新问题,但您将在我的解决方案中获得所有解决方案。让我来引导你。