2

I'm trying to update a struct with multi-level nested async callback, Since each level callback provides info for next batch of requests till everything is done. It's like a tree structure. And each time I can only get to one level below.

However, the first attempt with inout parameter failed. I now learned the reason, thanks to great answers here: Inout parameter in async callback does not work as expected

My quest is still there to be solved. The only way I can think of is to store the value to a local file or persistent store and modify it directly each time. And after writing the sample code, I think a global var can help me out on this as well. But I guess the best way is to have a struct instance for this job. And for each round of requests, I store info for this round in one place to avoid the mess created by different rounds working on the same time.

With sample code below, only the global var update works. And I believe the reason the other two fail is the same as the question I mentioned above.

func testThis() {
    var d = Data()
    d.getData()
}

let uriBase = "https://hacker-news.firebaseio.com/v0/"
let u: [String] = ["bane", "LiweiZ", "rdtsc", "ssivark", "sparkzilla", "Wogef"]
var successfulRequestCounter = 0

struct A {}

struct Data {
    var dataOkRequestCounter = 0
    var dataArray = [A]()

    mutating func getData() {
        for s in u {
            let p = uriBase + "user/" + s + ".json"
            getAnApiData(p)
        }
    }

    mutating func getAnApiData(path: String) {
        var req = NSURLRequest(URL: NSURL(string: path)!)
        var config = NSURLSessionConfiguration.ephemeralSessionConfiguration()
        var session = NSURLSession(configuration: config)
        println("p: \(path)")
        var task = session.dataTaskWithRequest(req) {
            (data: NSData!, res: NSURLResponse!, err: NSError!) in
            if let e = err {
                // Handle error
            } else if let d = data {
                // Successfully got data. Based on this data, I need to further get more data by sending requests accordingly.
                self.handleSuccessfulResponse()
            }
        }
        task.resume()
    }

    mutating func handleSuccessfulResponse() {
        println("successfulRequestCounter before: \(successfulRequestCounter)")
        successfulRequestCounter++
        println("successfulRequestCounter after: \(successfulRequestCounter)")
        println("dataOkRequestCounter before: \(dataOkRequestCounter)")
        dataOkRequestCounter++
        println("dataOkRequestCounter after: \(dataOkRequestCounter)")
        println("dataArray count before: \(dataArray.count)")
        dataArray.append(A())
        println("dataArray count after: \(dataArray.count)")
        if successfulRequestCounter == 6 {
            println("Proceeded")
            getData()
        }
    }
}

func getAllApiData() {
    for s in u {
        let p = uriBase + "user/" + s + ".json"
        getOneApiData(p)
    }
}

Well, in my actual project, I successfully append a var in the struct in the first batch of callbacks and it failed in the second one. But I failed to make it work in the sample code. I tried many times so that it took me so long to update my question with sample code. Anyway, I think the main issue is to learn appropriate approach for this task. So I just put it aside for now.

I guess there is no way to do it with closure, given how closure works. But still want to ask and learn the best way.

Thanks.

Community
  • 1
  • 1
LiweiZ
  • 1,921
  • 1
  • 15
  • 13

1 Answers1

0

What I did was use an inout NSMutableDictionary.

func myAsyncFunc(inout result: NSMutableDictionary){
    let priority = DISPATCH_QUEUE_PRIORITY_DEFAULT
    dispatch_async(dispatch_get_global_queue(priority, 0)) {
        let intValue = result.valueForKey("intValue")
        if intValue as! Int > 0 {
            //Do Work 
        }
    }
    dispatch_async(dispatch_get_main_queue()) {
        result.setValue(0, forKey: "intValue")
    }
}

I know you already tried using inout, but NSMutableDictionary worked for me when no other object did.