问题描述
我在本地关注 Json
{
"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"
}
]
}
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,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,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)
}
}
}
Response.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)
}
}
Country.swift
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
}