Demandes d'URL iOS Problèmes de sémaphore

J'entre dans la programmation de concurrency avec quelques problèmes de sémaphore. Ma fonction charge d'abord datatables du server, parsing les informations reçues et, si nécessaire, effectue une deuxième requête au server.

J'ai essayé différentes façons de le faire fonctionner, aucun d'eux ne l'a bien fait. Mon code actuel pour ME semble être correct, mais à la deuxième request, il se verrouille juste (peut-être comme un DeadLock) et le dernier journal est "<__ NSCFLocalDataTask: 0x7ff470c58c90> {taskIdentifier: 2} {suspendu}"

S'il te plaît, dis-moi ce que je ne sais pas. Peut-être qu'il existe une façon plus élégante de travailler avec des finitions à ces fins?

Merci d'avance!

var users = [Int]() let linkURL = URL.init(ssortingng: "https://bla bla") let session = URLSession.shared() let semaphore = DispatchSemaphore.init(value: 0) let dataRequest = session.dataTask(with:linkURL!) { (data, response, error) in let json = JSON (data: data!) if (json["queue"]["numbers"].intValue>999) { for i in 0...999 { users.append(json["queue"]["values"][i].intValue) } for i in 1...lround(json["queue"]["numbers"].doubleValue/1000) { let session2 = URLSession.shared() let semaphore2 = DispatchSemaphore.init(value: 0) let linkURL = URL.init(ssortingng: "https://bla bla") let dataRequest2 = session2.dataTask(with:linkURL!) { (data, response, error) in let json = JSON (data: data!) print(i) semaphore2.signal() } dataRequest2.resume() semaphore2.wait(timeout: DispatchTime.distantFuture) } } semaphore.signal() } dataRequest.resume() semaphore.wait(timeout: DispatchTime.distantFuture) 

PS Pourquoi je le fais. Le server renvoie un nombre limité de données. Pour en avoir plus, je dois utiliser offset.

    Ceci est une supercherie parce que vous attendez un sémaphore sur la URLSession attente de l' URLSession . La queue déléguée par défaut n'est pas la queue principale, mais il s'agit d'une queue d'arrière-plan série (c'est-à-dire une list OperationQueue avec une valeur maxConcurrentOperationCount de 1 ). Votre code attend donc un sémaphore sur la même queue série censée signaler le sémaphore.

    Le correctif tactique consiste à s'assurer que vous n'appelez pas d' wait sur la même queue série que les gestionnaires d'exécution de la session. Il y a deux corrections évidentes:

    1. N'utilisez pas de session shared (dont la propriété delegateQueue est une queue série), mais instanciez plutôt votre propre URLSession et spécifiez son delegateQueue comme une OperationQueue simultanée que vous créez:

       let queue = OperationQueue() queue.name = "com.domain.app.networkqueue" let configuration = URLSessionConfiguration.default() let session = URLSession(configuration: configuration, delegate: nil, delegateQueue: queue) 
    2. Vous pouvez également résoudre ce problème en envoyant le code avec le sémaphore à une autre queue, par exemple

       let mainRequest = session.dataTask(with: mainUrl) { data, response, error in // ... DispatchQueue.global(atsortingbutes: .qosUserInitiated).async { let semaphore = DispatchSemaphore(value: 0) for i in 1 ... n { let childUrl = URL(ssortingng: "https://blabla/\(i)")! let childRequest = session.dataTask(with: childUrl) { data, response, error in // ... semaphore.signal() } childRequest.resume() _ = semaphore.wait(timeout: .distantFuture) } } } mainRequest.resume() 

    Par souci d'exhaustivité, je noterai que vous ne devriez probablement pas utiliser de sémaphores pour émettre ces requêtes, car vous finirez par payer une pénalité de performance importante pour l'émission d'une série de requêtes consécutives (plus vous bloquez un fil, qui est généralement découragé).

    Le refactoring de ce code pour le faire est un peu plus important. Cela implique essentiellement l'émission d'une série de requêtes simultanées, peut-être utiliser des tâches de "téléchargement" plutôt que des tâches de "données" pour minimiser l'impact de la memory, et quand toutes les requêtes sont terminées, une Operation «achèvement» ou une notification de groupe d'expédition).