Как сохранить данные из Json с помощью Alamofire и SwiftyJSON? - PullRequest
0 голосов
/ 06 июня 2019

Я пытаюсь сохранить данные об "авторе" в глобальную переменную с именем "авторы" из json (ссылка: "https://learnappmaking.com/ex/books.json") с этими двумя библиотеками. Но это работает только при завершающем закрытии func Alamofire.request(url).responseJSON. Когда Я получаю доступ к глобальной переменной с именем «авторы» откуда-то, кроме замыкающего замыкания, получаю пустой массив строк.

Может ли кто-нибудь объяснить причину этой странной ситуации? Большое спасибо.

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

фактический вывод:

enter image description here


Обновление : Я изменил свой код:

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() напечатано. Я так растерялся сейчас ... Опять же, я хочу использовать данные, хранящиеся в переменной с именем «авторы», но я получил только пустой массив строк.

Ответы [ 2 ]

0 голосов
/ 07 июня 2019

По запросу через прямое сообщение: только Swift.Просто вставьте это в пустую игровую площадку:

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

}
0 голосов
/ 06 июня 2019

Я постараюсь ответить на все ваши вопросы:

  • Данные являются постоянными

  • Вы делаете следующее: Alamo.request (Сетевой вызов) -> getAuthors (результат печати - пусто) -> ответ (получить ответ) -> self.authors.append (сохранить ответ) -> self.authors (результат печати)

  • Необходимо сделать: Alamo.request (Сетевой вызов) -> ответ (получить ответ) -> self.authors.append (сохранить ответ) -> self.getAuthors или getAuthors (то же самое) (внутри ответа {})

Вам нужно вызвать 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 вы можете использовать различные методы (настоящее / push, закрытие / обратный вызов, ...)
  • Обычно у вас будет загрузочный счетчик, чтобы дождаться, пока сеть ответьте тогда вы покажете свой следующий контроллер
...