Search code examples
iosjsonswiftalamofireswifty-json

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. But it only works at the trailing closure of 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.

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:

enter image description here


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 ? I think the result should be the same as the result which func self.getAuthorsCount() printed. 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.


Solution

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

    • You need to do : Alamo.request (Network call) -> response (receive response) -> self.authors.append(save response) -> self.getAuthors or getAuthors(same) (inside the response {})

    You need to call getAuthors once you have your result, inside the response callback :

    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 :

    • To send the data to another ViewController you can use various methods (present/push, closure/callback, ...)
    • Usually you will have a loading spinner to wait for the network to answer then you will show your next controller