0

Basically I want to loop through 4 web pages, obtaining 6 data from each page, having a total of 24 data in an array at the end of the loop, then display the last added data of that array (the 24th object in the array) / (the 6th data of the 4th web page) on message.text label.

Information:

i) The 4 web pages I want to loop through:

http://apims.doe.gov.my/apims/hourly1.php

http://apims.doe.gov.my/apims/hourly2.php

http://apims.doe.gov.my/apims/hourly3.php

http://apims.doe.gov.my/apims/hourly4.php

ii) The NSURLSession task to obtain the 6 data ("AQI1", "AQI2", "AQI3", "AQI4", "AQI5", "AQI6") from a page, and add into empty [String] array ("AQI"):

var urlContent = NSString(data: data, encoding: NSUTF8StringEncoding) as NSString!
var cutCut = urlContent.componentsSeparatedByString("<td>Kota Tinggi</td>")
var cut = cutCut[1].componentsSeparatedByString("<b>")
var arr1 = cut[1].componentsSeparatedByString("</b>")
var AQI1 = arr1[0] as! String
var arr2 = cut[2].componentsSeparatedByString("</b>")
var AQI2 = arr2[0] as! String
var arr3 = cut[3].componentsSeparatedByString("</b>")
var AQI3 = arr3[0] as! String
var arr4 = cut[4].componentsSeparatedByString("</b>")
var AQI4 = arr4[0] as! String
var arr5 = cut[5].componentsSeparatedByString("</b>")
var AQI5 = arr5[0] as! String
var arr6 = cut[6].componentsSeparatedByString("</b>")
var AQI6 = arr6[0] as! String

self.AQI.extend([AQI1, AQI2, AQI3, AQI4, AQI5, AQI6])

iii) Var "taskerror" was created as a Boolean to check for unwanted errors in the task, and a Func ERROR( ) was created earlier to run if Var "taskerror" = true at the end.



Here is the whole code, which I've put under a IBAction button (I've created var AQI = [String] ( ) before the button):

AQI.removeAll(keepCapacity: true)

var pages = ["1", "2", "3", "4"]

    for object in pages {

        var url = NSURL(string: "http://apims.doe.gov.my/apims/hourly" + object + ".php")

        var task = NSURLSession.sharedSession().dataTaskWithURL(url!, completionHandler: { (data, response, error) -> Void in

            var taskerror = false

            if error == nil {

                var urlContent = NSString(data: data, encoding: NSUTF8StringEncoding) as NSString!
                var cutCut = urlContent.componentsSeparatedByString("<td>Kota Tinggi</td>")
                var cut = cutCut[1].componentsSeparatedByString("<b>")
                var arr1 = cut[1].componentsSeparatedByString("</b>")
                var AQI1 = arr1[0] as! String
                var arr2 = cut[2].componentsSeparatedByString("</b>")
                var AQI2 = arr2[0] as! String
                var arr3 = cut[3].componentsSeparatedByString("</b>")
                var AQI3 = arr3[0] as! String
                var arr4 = cut[4].componentsSeparatedByString("</b>")
                var AQI4 = arr4[0] as! String
                var arr5 = cut[5].componentsSeparatedByString("</b>")
                var AQI5 = arr5[0] as! String
                var arr6 = cut[6].componentsSeparatedByString("</b>")
                var AQI6 = arr6[0] as! String

                self.AQI.extend([AQI1, AQI2, AQI3, AQI4, AQI5, AQI6])

            } else {
                taskerror = true
            }

            dispatch_async(dispatch_get_main_queue()) {
                if taskerror {
                    self.ERROR()
                } else {
                    if self.AQI.count == 24 {
                        self.message.text = self.AQI[23]
                    }
                }
            }

        })

        task.resume()

    }

My problem is:

1) The sequence of running the task on the 4 URL is random, resulting in a random sequence of displaying the sets of 6 data in the array AQI, therefore the last (24th) object in the array AQI is not fixed, even though the last data from the 4th URL has not changed.

2) Using println(self.AQI) just before displaying AQI[23] on message.text, I can see that the set of 6 data is randomly sequenced.

3) Using println(object) just before var task shows that the loop is running through the URL "1", "2", "3", "4" accordingly. But if placed inside var task, it shows how the loop runs randomly (e.g. "2", "4", "3", "1"), resulting in the corresponding randomly arranged array AQI mentioned in (2).

My question is:

1) Why is the loop running randomly when in the task? (Not according to the set var pages = ["1", "2", "3", "4"] )

2) How do I make the task run orderly through the loop, so that the last object (24th) in the array AQI is always the same?

Note: I know I could just run the 4th URL if I want the last data, but I want to add some more code later on requiring all 24 data.

p.s. Is there a better way of doing what I want to do?

Allister Bah
  • 1,134
  • 3
  • 13
  • 19
  • [Like most networking APIs, the NSURLSession API is highly asynchronous.](https://developer.apple.com/library/ios/documentation/Foundation/Reference/NSURLSession_class/). So nothing is *random* here. – Eric Aya May 21 '15 at 10:34
  • @EricD. But how is it I got problem (1), (2), and (3) then? – Allister Bah May 22 '15 at 02:31

1 Answers1

0

My answer below is not a direct solution to your problem, it's a follow-up to my comment, explaining why you get your responses in random order. I believe nonetheless it will very quickly allow you to find your solution. :)

Open the debug console, launch this code (adapted from yours) several times and watch the printed results.

var results = [Int:[String]]()

for index in 1...4 {
    println("Loop index: \(index)")

    var url = NSURL(string: "http://apims.doe.gov.my/apims/hourly\(index).php")

    var task = NSURLSession.sharedSession().dataTaskWithURL(url!, completionHandler: { (data, response, error) -> Void in

        var taskerror = false

        if error == nil {

            var urlContent = NSString(data: data, encoding: NSUTF8StringEncoding) as NSString!
            var cutCut = urlContent.componentsSeparatedByString("<td>Kota Tinggi</td>")
            var cut = cutCut[1].componentsSeparatedByString("<b>")
            var arr1 = cut[1].componentsSeparatedByString("</b>")
            var AQI1 = arr1[0] as! String
            var arr2 = cut[2].componentsSeparatedByString("</b>")
            var AQI2 = arr2[0] as! String
            var arr3 = cut[3].componentsSeparatedByString("</b>")
            var AQI3 = arr3[0] as! String
            var arr4 = cut[4].componentsSeparatedByString("</b>")
            var AQI4 = arr4[0] as! String
            var arr5 = cut[5].componentsSeparatedByString("</b>")
            var AQI5 = arr5[0] as! String
            var arr6 = cut[6].componentsSeparatedByString("</b>")
            var AQI6 = arr6[0] as! String

            results[index] = [AQI1, AQI2, AQI3, AQI4, AQI5, AQI6]

        } else {
            taskerror = true
        }

        dispatch_async(dispatch_get_main_queue()) {
            if taskerror {
                println(taskerror)
            } else {
                println("Result index: \(index) - Content: \(results[index]!)")
            }
        }

    })

    task.resume()
}
  • 1:

enter image description here

  • 2:

enter image description here

Now you see that each task is indeed launched according to the loop index, in order, but the results are coming back asynchronously, depending on the time each task takes to get the data from the network. And it's not the same each time you launch your sequence, because of course the network speed is not constant.

In my example I used a Dictionary instead of an Array to store the results, it allowed me to show you that you get the right response for the right request, it's just that you get the results in random order, due to asynchronous nature of the tasks.

Eric Aya
  • 69,473
  • 35
  • 181
  • 253
  • Thanks for the clear demonstration! Is this asynchronous nature always present/built in to all NSURLSession task? Or is it due to the dispatch_sync I've added at the end of the task? Because I've tried removing dispatch_async and it is still asynchronous.. – Allister Bah May 25 '15 at 05:29
  • @AllisterBah The network operations are asynchronous. The dispatch to the main queue is on the contrary to execute on the main thread (for UI operations like, here, println). – Eric Aya May 25 '15 at 10:12