wade-watt wade-watt - 3 months ago 12
Swift Question

Json Values Append Array but ViewDidLoad it seem Empty

I am working in iOS and when I take JSON datas , I print it with no error in the function and append it a String array ( I did it correctly )

But if I want to reach to String array later the json Function it seem empty array . For testing I printed the array in a Button Action then it worked for me but I want to use in String Datas in other Function when Json Function ends.

The Codes:

func getAllDataFromURL()
{
var i : Int = 0;
var urlDatas : [String] = allJsonDatas.getAllTours();
for(i = 0 ; i < allJsonDatas.getAllTours().count ; i += 1)
{
Alamofire.request(.GET, urlDatas[i]).responseJSON
{(response) -> Void in

if let arrivedData = response.result.value
{
print("********")
print(arrivedData["generalTourDistrict"] as! String);
print(arrivedData["otherTourDistrict"] as! String);
print(arrivedData["photoURLS"] as! [String]);
print(arrivedData["subTourDistrict"] as! String);
print(arrivedData["tourCalendar"] as! String);
print(arrivedData["tourDistrict"] as! String);
print(arrivedData["tourName"] as! String);
self.tryingSomething.appendContentsOf(arrivedData["photoURLS"] as! [String]);
print("********\n")

}
}
}
}


And viewDidLoad is

override func viewDidLoad() {
super.viewDidLoad()
Alamofire.Request.addAcceptableImageContentTypes(acceptableContentTypes);


self.getAllDataFromURL();
self.printTheJsonDatas();

}


For Example , in getAllDataFromURL() function I can print it correctly.

This is the result for url data from the json:

["https://acenta.dominant.com.tr//dominant/webout/R12/php/product/img.php?path=L2QvMS9jcmkvc295a3VsL3VydW4vMDAvMjIvMTIvaW1hZ2UvL3VfMDAyMjEyLjAwMDAxLmpwZWc=&rx=650&ry=400", "https://acenta.dominant.com.tr//dominant/webout/R12/php/product/img.php?path=L2QvMS9jcmkvc295a3VsL3VydW4vMDAvMjIvMTIvaW1hZ2UvL3VfMDAyMjEyLjAwMDA2LmpwZWc=&rx=650&ry=400"]


But
printTheJsonDatas()
prints an empty array like -> [ ]

func printTheJsonDatas()
{
print(tryingSomething)
//tryingSomething : [String]
}


Surprisingly , when I put
printTheJsonDatas()
into
buttonClickedAction
, then it worked as I said before.

I think the problem is about threads but I can not say anything clearly .

Answer

getAllDataFromURL() runs asynchronously with a completion block (known as a closure in swift, or callback on other languages). The order of events is:

  1. getAllDataFromURL()
  2. printTheJsonDatas()
  3. Alamofire.request()
  4. (wait for AF response)
  5. self.tryingSomething.appendContentsOf(...)

If you want the print function to work correctly, you'll need to call it inside the completion block of the AF request, e.g.:

func getAllDataFromURL()
{
    var i : Int = 0;
    var urlDatas : [String] = allJsonDatas.getAllTours();
    for(i = 0 ; i < allJsonDatas.getAllTours().count ; i += 1)
    {
        Alamofire.request(.GET, urlDatas[i]).responseJSON
        {(response) -> Void in

            if let arrivedData = response.result.value
            {
                self.tryingSomething.appendContentsOf(arrivedData["photoURLS"] as! [String]);
                //
                self.printTheJsonDatas();
                // ^
            }
        }
    }
}

You could also rewrite getAllDataFromURL() with a closure to be asynchronous (the more appropriate way to write this, I'd say):

func getAllDataFromURL(completion: (result: Array) -> Void) {
    ...
    var returnArray = []
    // ^ here this is a local variable, doesn't need to be global anymore
    returnArray.appendContentsOf(arrivedData["photoURLS"] as! [String]);
    completion(returnArray)
}