[英]How to save data from Json with Alamofire and SwiftyJSON?
I am trying to save "author" data to global variable named "authors" from json(Link:" https://learnappmaking.com/ex/books.json ") with these two libraries. 我试图用这两个库将“作者”数据保存到json(链接:“ https://learnappmaking.com/ex/books.json ”)中名为“authors”的全局变量中。 But it only works at the trailing closure of
func Alamofire.request(url).responseJSON
. 但它只适用于
func Alamofire.request(url).responseJSON
的尾随关闭。 When I access the global variable named "authors" from somewhere except the trailing closure, what I get is an empty array of string. 当我从除了尾随闭包之外的某个地方访问名为“authors”的全局变量时,我得到的是一个空字符串数组。
Can someone explain the reason behind this werid situation? Thanks a lot. 有人可以解释这种情况背后的原因吗?非常感谢。
class ViewController: UIViewController {
var authors = [String]()
let url = "https://learnappmaking.com/ex/books.json"
func getAuthorsCount() {
print("the number of authors : \(authors.count)") // I hope that here, the number of authors should be 3 too! actually, it is 0. Why?
// this for loop doesn't get excuted
for author in authors {
print(author)
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
Alamofire.request(url).responseJSON { response in
if let data = response.data {
if let json = try? JSON(data: data) {
for item in json["books"].arrayValue {
var outputString: String
print(item["author"])
outputString = item["author"].stringValue
//urlOfProjectAsset.append(outputString)
self.authors.append(outputString)
print("authors.count: \(self.authors.count)")
}
}
}
}
getAuthorsCount()
print("-------------")
}
}
the actual output is: 实际输出是:
Update : I adjusted my code: 更新 :我调整了我的代码:
class ViewController: UIViewController {
var authors = [String]()
let url = "https://learnappmaking.com/ex/books.json"
func getAuthorsCount() {
print("the number of authors : \(authors.count)")
// this for loop doesn't get excuted
for author in authors {
print(author)
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
Alamofire.request(url).responseJSON { response in
if let data = response.data {
if let json = try? JSON(data: data) {
for item in json["books"].arrayValue {
var outputString: String
//print(item["author"])
outputString = item["author"].stringValue
//urlOfProjectAsset.append(outputString)
self.authors.append(outputString)
//print("authors.count: \(self.authors.count)")
}
self.getAuthorsCount() // I added this line of code.
}
}
}
getAuthorsCount()
print("-------------")
}
}
But why does the func getAuthorsCount()
(not self. version) still print an empty array of strings ? 但为什么
func getAuthorsCount()
(不是自我版本)仍然打印一个空数组的字符串? I think the result should be the same as the result which func self.getAuthorsCount()
printed. 我认为结果应该与
func self.getAuthorsCount()
打印的结果相同。 I am so confused now... Again, I want to use the data kept in the variable named "authors", but what I only got is an empty array of strings. 我现在很困惑...再次,我想使用保存在名为“authors”的变量中的数据,但我只得到一个空数组的字符串。
I'll try to answer all your questions : 我会尽力回答你的所有问题:
The data is persistant 数据是持久的
You are doing the following : Alamo.request (Network call) -> getAuthors(print result - empty) -> response (receive response) -> self.authors.append(save response) -> self.authors (print result) 您正在执行以下操作:Alamo.request(网络调用) - > getAuthors(打印结果 - 空) - >响应(接收响应) - > self.authors.append(保存响应) - > self.authors(打印结果)
You need to do : Alamo.request (Network call) -> response (receive response) -> self.authors.append(save response) -> self.getAuthors or getAuthors(same) (inside the response {}) 您需要这样做:Alamo.request(网络调用) - >响应(接收响应) - > self.authors.append(保存响应) - > self.getAuthors或getAuthors(相同)(在响应{}内)
You need to call getAuthors once you have your result, inside the response callback : 在响应回调中,您需要在获得结果后调用getAuthors:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
Alamofire.request(url).responseJSON { response in
if let data = response.data {
if let json = try? JSON(data: data) {
for item in json["books"].arrayValue {
var outputString: String
print(item["author"])
outputString = item["author"].stringValue
//urlOfProjectAsset.append(outputString)
self.authors.append(outputString)
print("authors.count: \(self.authors.count)")
}
self.getAuthorsCount()
print("-------------")
//Do whatever you want from here : present/push
}
}
}
Then you can use the saved data : 然后你可以使用保存的数据:
As requested via direct message: a Swift-only approach. 根据直接消息的要求:一种仅限Swift的方法。 Just paste this in a blank Playground:
只需将其粘贴在空白的Playground中:
import Foundation
final class NetworkService {
enum ServiceError: LocalizedError {
case invalidUrl
case networkingError(error: Error)
case parsingError
var localizedDescription: String? { return String(describing: self) }
}
func request(completion: @escaping (Result<[UserObject], Error>) -> Void ) {
guard let url = URL(string: "https://jsonplaceholder.typicode.com/users") else {
completion(.failure(ServiceError.invalidUrl))
return
}
let dataTask = URLSession.shared.dataTask(with: url) { (jsonData, response, error) in
if let jsonData = jsonData {
let jsonDecoder = JSONDecoder()
do {
let users = try jsonDecoder.decode([UserObject].self, from: jsonData)
completion(.success(users))
} catch {
completion(.failure(ServiceError.parsingError))
}
} else if let error = error {
completion(.failure(ServiceError.networkingError(error: error)))
}
}
dataTask.resume()
}
}
struct UserObject: Codable {
let id: Int
let name: String
let username: String
let email: String?
let website: String?
}
let networkService = NetworkService()
networkService.request { result in
switch result {
case .success(let users):
debugPrint("Received \(users.count) users from REST API")
debugPrint(users)
case .failure(let error):
debugPrint(error.localizedDescription)
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.