【问题标题】:How to save data from Json with Alamofire and SwiftyJSON?如何使用 Alamofire 和 SwiftyJSON 从 Json 中保存数据?
【发布时间】:2019-10-22 04:46:34
【问题描述】:

我正在尝试使用这两个库从 json(Link:"https://learnappmaking.com/ex/books.json") 将“作者”数据保存到名为“作者”的全局变量中。但它只适用于func Alamofire.request(url).responseJSON 的尾随关闭。当我从尾随闭包之外的某个地方访问名为“authors”的全局变量时,我得到的是一个空的字符串数组。

有人能解释一下这种奇怪情况背后的原因吗? 非常感谢。

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("-------------")
    }
}

实际输出为:


更新: 我调整了我的代码:

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("-------------")
    }
}

但是为什么func getAuthorsCount()(不是self.version)仍然打印一个空的字符串数组?我认为结果应该与结果相同 func self.getAuthorsCount() 已打印。 我现在很迷茫... 同样,我想使用保存在名为“authors”的变量中的数据,但我只得到一个空字符串数组。

【问题讨论】:

  • 确保在获得结果后访问 getAuthorsCount。从您的示例中不清楚
  • 您在请求从服务器返回之前调用了getAuthorsCount()。将它移到回调中,在for 语句之后,它将起作用。
  • @Lirik 嗨,我是 swift 的 iOS 开发新手。您能否给我一些提示,告诉我如何确保在获得代码结果后访问 getAuthorsCount()?
  • @SunsetWan 现在工作了吗?
  • @SunsetWan 您添加的行正是答案。其他 getAuthorsCount() 和 print() 语句不相关。

标签: ios json swift alamofire swifty-json


【解决方案1】:

我会尽力回答你所有的问题:

  • 数据是持久的

  • 您正在执行以下操作:Alamo.request(网络调用)-> getAuthors(打印结果-空)-> response(接收响应)-> self.authors.append(保存响应)-> self.authors(打印结果)

  • 你需要做:Alamo.request (网络调用) -> response (接收响应) -> self.authors.append(save response) -> self.getAuthors or getAuthors(same) (在响应内{})

一旦得到结果,您需要在响应回调中调用 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 


                }
            }
        }

然后你就可以使用保存的数据了:

  • 要将数据发送到另一个 ViewController,您可以使用各种方法(present/push、closure/callback,...)
  • 通常你会有一个加载微调器来等待网络 回答然后你会展示你的下一个控制器

【讨论】:

  • 但是我使用 func print() 来显示 "var authors = [String]() " 的内容,我仍然得到一个空的字符串数组。如何使数据在“var authors = [String]()”中持久化?因为我想在另一个视图控制器中使用它。
  • 我应该使用 func prepare(for segue: UIStoryboardSegue, sender: Any?) 来满足我的需要吗?
  • @SunsetWan,我编辑了我的答案以涵盖您的所有问题。希望这可以帮助。这应该回答“如何保存数据”的问题;-)
【解决方案2】:

根据直接消息的要求:仅 Swift 的方法。只需将其粘贴到空白 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)
  }

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-11-12
    • 1970-01-01
    • 1970-01-01
    • 2016-07-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-27
    • 1970-01-01
    相关资源
    最近更新 更多