0

How can the function findMediaLimit return the highest i, received from cURL ?

class func findMediaLimit(IgBusinessAccount: String, token: String) {
    let igBId = IgBusinessAccount
        
    for i in 1...12 {
        guard let encodedUrl = self.buildURLAPIGraph(IgBusinessAccount: igBId, token: token, i: i) else { return }
            
        //Async function that returns different i's in random order
        self.cURL(urlT: encodedUrl) { (result) in
        print(i)   
        //return the highest i             
        }
    }
}

I have created this function in order to filter media that have been posted after conversion to a business Instagram account.

that's my cURL function

class func cURL (urlT: String,Completion block: @escaping ((OfficialProfile) -> ())) {
    
    //visuJson (urlT: urlT)
    
    GetJson.loadJson(fromURLString: urlT) { (result) in
        switch result {
        case .success(let data):
            //Parse
            do {
                let decodedData = try JSONDecoder().decode(OfficialProfile.self, from: data)
                if decodedData.username != nil {
                    block(decodedData)
                }
            } catch {
                print("decode error: ",error)
            }
        case .failure(let error):
            print("loadJson error:", error)
        }
    }
}

and that is my loadJson func

class func loadJson(fromURLString urlString: String,
                          completion: @escaping (Result<Data, Error>) -> Void) {
        if let url = URL(string: urlString) {
            let urlSession = URLSession(configuration: .default).dataTask(with: url) { (data, response, error) in
                if let error = error {
                    completion(.failure(error))
                }
                
                if let data = data {
                    completion(.success(data))
                }
            }
            urlSession.resume()
        }
    }
6
  • 2
    What do you really mean? The highest i is obviously 12 so there must be something else you are asking about? Commented Jun 5, 2021 at 17:26
  • 1
    You cannot return a value from an asynchronous task. You need DispatchGroup to get notified when all network requests are completed and filter the data in the notify method. Commented Jun 5, 2021 at 17:56
  • @Joakim Danielson there are 12 urls that are sent to cURL, cURL will escape if the url is valid. So if theres for example 3 valid urls print i will display 123 or 312 or 213 231 ,321... Commented Jun 5, 2021 at 20:14
  • Identical to your stackoverflow.com/questions/67844429/…. Please don't do that. The key is to get the idea about asynchronous. The loop has no order and you cannot return anything. You cannot even be sure that all 12 network calls will give a result! What if the network fails? The best you can do is pair each outgoing and incoming value and wait until all have arrived or some timeout is reached, then examine your pairs. But it's a very poor use of networking. Commented Jun 5, 2021 at 21:32
  • @matt Oh sorry, I had deleted the other post and I thought it was deleted for good. Why you could still see it? I edited my question with the other functions to see what is going on inside. Commented Jun 5, 2021 at 21:52

1 Answer 1

1

To see what the issue is with what you're apparently trying to do, let's simulate it in a simpler way. I'll use an asynchronous random number generator. Try this in a playground:

func delay(_ delay:Double, closure:@escaping ()->()) {
    let when = DispatchTime.now() + delay
    DispatchQueue.main.asyncAfter(deadline: when, execute: closure)
}
func asyncRand(_ completion: @escaping (Int) -> ()) {
    let d = Double.random(in: 1...3)
    delay(d) {
        let i = Int.random(in: 1...100)
        completion(i)
    }
}
func go() {
    for i in 1...12 {
        asyncRand() { result in
            print(i, result)
        }
    }
    print("finished")
}
go()

The result in a typical run might be:

finished
8 13
1 15
9 9
10 56
7 57
3 87
2 70
11 88
6 82
12 16
4 81
5 46

So there are two issues here, because of the asynchronous nature of the central asyncRand call: the results come back in no order, over time, and the go method itself (the loop) finishes before any results come back, so there is no opportunity to find out which result is the maximum.

To straighten that out, while we are waiting for async/await to appear in Swift (possibly as soon as next week), you can use a dispatch group. Ignoring any threading issues, we might do this:

func go() {
    let group = DispatchGroup()
    var pairs = [[Int]]()
    for i in 1...12 {
        group.enter()
        asyncRand() { result in
            print(i, result)
            pairs.append([i,result])
            group.leave()
        }
    }
    group.notify(queue: DispatchQueue.main) {
        print("finished")
        if let maximum = pairs.max(by: {$0[1] < $1[1]}) {
            print(maximum)
        }
    }
}

Now the result is (for example):

11 52
8 6
2 1
4 6
12 77
1 88
7 45
9 36
6 25
3 22
10 78
5 33
finished
[1, 88]

So you see we have "waited" until all the results have come back, and we have picked out the pair where the largest value was returned.

So you could do something along those lines. But whether that's a good idea is another question.

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.