0

I'm new in Swift and I have issue with adding an element to an Array

I'm trying to store 6 objects from JSON to Array. But the Array is nil.

I see it add to Array when I debug it, I have no idea why it's nil after finished request JSON?

JSON:

[
    {
        "amount": "20.0",
        "date": "10/07/2016"
    },
    {
        "amount": "21.0",
        "date": "11/07/2016"
    },
    {
        "amount": "16.0",
        "date": "12/07/2016"
    },
    {
        "amount": "30.0",
        "date": "13/07/2016"
    },
    {
        "amount": "50.0",
        "date": "14/07/2016"
    },
    {
        "amount": "33.0",
        "date": "15/07/2016"
    }
]

Service:

    class DownloadService {
    static let instance = DownloadService()
    //static var goldArray = [Gold]()
    var goldArray = [Gold]()
    func getData() {
        Alamofire.request("https://rth-recruitment.herokuapp.com/api/prices/chart_data", headers: headers).responseJSON { response in
            if let objJson = response.result.value as! NSArray?{
                for element in objJson {
                    let data = element as! NSDictionary
                    let amount = data["amount"] as! String
                    let date = data["date"] as! String
                    let gold = Gold(amount: amount, date: date)
                    self.goldArray.append(gold)
                    print(self.goldArray.count)//print 1 to 6
                }
            }
        }
        printGoldArray()
    }

    func printGoldArray(){
        for element in self.goldArray {
            print(element)//print nothing
        }
    }
}

Gold class:

    class Gold{
    let amount:String
    let date: String

    init(amount: String, date: String) {
        self.amount = amount
        self.date = date
    }

}

ViewController:

    class ViewController: UIViewController {
    //var dataArray = [Gold]()
    override func viewDidLoad() {
        super.viewDidLoad()
        DownloadService.instance.getData()

    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}
2
  • It's because you are missing the asynchronous concept. If you add print("in alamofire closure") before print(self.goldArray.count) and print("calling print") just before printGoldArray(), you'll see that the order of the print is no the one you expect. Look for "Swift + Closure + Async". Commented Jul 6, 2017 at 10:36
  • 1
    Why do you forced unwrap an optional to an optional (as! NSArray?) ?? Commented Jul 6, 2017 at 10:41

3 Answers 3

1

Here printGoldArray function is being called from outside the closure which means when printGoldArray is called the goldArray may not be having any values.

Try calling printGoldArray function from inside the closure after adding the values. Try the below code

func getData() {
    Alamofire.request("https://rth-recruitment.herokuapp.com/api/prices/chart_data", headers: headers).responseJSON { response in
        if let objJson = response.result.value as! NSArray?{
            for element in objJson {
                let data = element as! NSDictionary
                let amount = data["amount"] as! String
                let date = data["date"] as! String
                let gold = Gold(amount: amount, date: date)
                self.goldArray.append(gold)
                print(self.goldArray.count)//print 1 to 6
            }
        }
     printGoldArray()
    }

}
Sign up to request clarification or add additional context in comments.

6 Comments

Actually, my purpose is use goldArray[] at other method, so I declared it as global var but till cannot get data. So is there any way to use it?
You can use closure in the func getData() also and on its completion closure you can use the goldArray
Can I use outside of func getData()?
Yup you can use goldArray outside getData but only after the execution of the alamofire's completion block/closure
is it why my goldArray[] nil at that time? How can I know the execution of the Alamofire closure is completed?
|
0

You need to parse your JSON data first before getting value out

do{
    let json = try JSONSerialization.jsonObject(with: response.result.value, options: []) as? [Any]
    let firstObj = json?[0] as! [String: String]
    let amount = firstObj["amount"]
    dump(amount)
}catch let error{

}

Then, your HTTP call will not get you the return value until the closure is executed. So to print your array, you need to do it inside your closure. For example, you can do so right after the json parsing, by calling printGoldArray()

Comments

0

First, your array is not print array element because you print it directly after closure. closure uses async paradigm. so put the print function inside closure.

and Second thing is why use to much force full unwrap. instead you can use if let or guard statement

you can see below code.

func getData() {
        Alamofire.request("https://rth-recruitment.herokuapp.com/api/prices/chart_data", headers: headers).responseJSON { response in
            if let objJson = response.result.value as? NSArray {
                for element in objJson {
                    if let data = element as? NSDictionary {
                        let amount = data["amount"] as! String
                        let date = data["date"] as! String
                        let gold = Gold(amount: amount, date: date)
                        self.goldArray.append(gold)
                        print(self.goldArray.count)
                    }
                }
            }
            printGoldArray()
        }
    }

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.