2016-03-19 2 views
0

En général, il est nécessaire d'implémenter une classe pour le réseau. C'est une classe qui prendra une URL et donnera des données. Tout ceci est fait afin de ne pas marquer de contrôleurs logiques supplémentaires. J'ai rencontré un tel problème que lorsque vous créez une vue, les données ne viennent pas. C'est classe réseau:NSURLSession ne renvoie pas de données dans le premier appel

private static var dataTask: NSURLSessionDataTask? 

private static var dataJSON: NSData? 

private static var sessionConfig: NSURLSessionConfiguration = { 
    var configuration = NSURLSessionConfiguration.defaultSessionConfiguration() 
    configuration.allowsCellularAccess = false 
    configuration.HTTPMaximumConnectionsPerHost = 2 
    configuration.HTTPAdditionalHeaders = ["Accept": "application/json"] 
    configuration.timeoutIntervalForRequest = 30.0 
    configuration.timeoutIntervalForResource = 60.0 
    return configuration 
}() 


static func getListObjectsBy(url: String?) -> NSData? { 
    let session = NSURLSession(configuration: sessionConfig) 
    log.debug("DataTask start") 
    dataTask = session.dataTaskWithURL(NSURL(string: url!)!) { (data, response, error) in 
     log.debug("if error = error") 
     if let error = error { 
      print(error.localizedDescription) 
     } else if let httpResponse = response as? NSHTTPURLResponse { 
      log.debug("if httpResponse") 
      if httpResponse.statusCode == 200 { 
       dataJSON = data 
      } else { 
       print("Bad request") 
      } 
     } 
    } 
    dataTask?.resume() 
    log.debug("DataTask Resume") 
    return dataJSON 
} 

Méthode viewDidLoad dans mon contrôleur principal:

let response = Network.getListObjectsBy("http://lb.rmc.su/api-dev/v2/wc/5") 
print(String(response)) 

Mon journal me dit, que nul de retour de données. Notes, je suis passer entre les contrôleurs avec l'aide SWRevealViewController. Lors du rechargement du contrôleur de la vue principale, les données sont renvoyées. Qu'est-ce que je fais?

enter image description here

Répondre

1

Vous semblez être que ce malentendu est un appel asynchrone.

static func getListObjectsBy(url: String?) -> NSData? { 
    let session = NSURLSession(configuration: sessionConfig) 
    log.debug("DataTask start") 
    dataTask = session.dataTaskWithURL(NSURL(string: url!)!) { (data, response, error) in 
     // Everything in this block is happening on a separate thread. 
     log.debug("if error = error") 
     if let error = error { 
      print(error.localizedDescription) 
     } else if let httpResponse = response as? NSHTTPURLResponse { 
      log.debug("if httpResponse") 
      if httpResponse.statusCode == 200 { 
       // this won't happen until the data comes back from the remote call. 
       dataJSON = data 
      } else { 
       print("Bad request") 
      } 
     } 
    } 
    // This code here does not wait for the response from the remote. 
    // The call to the remote is sent then this code 
    // is immediately executed WITHOUT WAITING 
    dataTask?.resume() 
    log.debug("DataTask Resume") 
    // dataJSON will be nil until the remote answers. 
    return dataJSON 
} 

Lorsque vous faites ceci:

let response = Network.getListObjectsBy("http://lb.rmc.su/api-dev/v2/wc/5") 
print(String(response)) 

La télécommande n'a pas encore répondu et vous obtiendrez nulle.

Votre prochaine question pourrait être "qu'est-ce que je fais à ce sujet?". La réponse n'est pas claire sans savoir tout ce que vous faites.

Threads

Plusieurs threads d'exécution est en cours d'exécution comme deux programmes en même temps. Pensez à 2 personnes qui travaillent sur deux tâches différentes en même temps. Afin de garder l'interface très réactive, iOS utilise un fil d'exécution pour la mise à jour de l'écran. Si un processus doit durer longtemps, nous ne voulons pas que l'écran attende jusqu'à ce que cela soit fait. Supposons que vous deviez extraire des données d'un système distant et que le système distant soit lent, votre appareil resterait figé jusqu'à ce que la réponse revienne. Pour éviter cela, les activités telles que les appels aux systèmes distants sont effectuées dans un autre thread. La demande est envoyée au système d'exploitation lui-même et le système d'exploitation est invité à rappeler lorsque l'opération est terminée.

Voici ce qui se passe ici.
Configure la demande d'envoi au système d'exploitation.

dataTask = session.dataTaskWithURL(NSURL(string: url!)!) 

Indique au système d'exploitation de commencer le travail.

dataTask?.resume() 

Ce bloc est le rappel AKA la fermeture. iOS exécutera ce code lorsque l'appel à distance sera terminé.

dataTask = session.dataTaskWithURL(NSURL(string: url!)!) { 
    // Closure starts here 
    // Gets called when the remote has sent a response. 
    (data, response, error) in 
    // Everything in this block is happening on a separate thread. 
    log.debug("if error = error") 
    etc 
} 

Cela signifie que vous devez attendre que la réponse soit revenue avant d'imprimer votre sortie. Vous pouvez utiliser une fermeture dans votre fonction pour le faire.

public typealias CompletionHandler = (data: NSData?, error: NSError?) -> Void 

static func getListObjectsBy(url: String?, completion: CompletionHandler) { 
    let session = NSURLSession(configuration: sessionConfig) 
    log.debug("DataTask start") 
    dataTask = session.dataTaskWithURL(NSURL(string: url!)!) { 
     (data, response, error) in 
     // Everything in this block is happening on a separate thread. 
     log.debug("if error = error") 
     if let error = error { 
      print(error.localizedDescription) 
     } else if let httpResponse = response as? NSHTTPURLResponse { 
      log.debug("if httpResponse") 
      if httpResponse.statusCode == 200 { 
       // this won't happen until the data comes back from the remote call. 
      } else { 
       print("Bad request") 
      } 
     } 
     // Call your closure 
     completion(data, error) 
    } 
    // This code here does not wait for the response from the remote. 
    // The call to the remote is sent then this code 
    // is immediately executed WITHOUT WAITING 
    dataTask?.resume() 
    log.debug("DataTask Resume") 
} 

Dans votre code d'appel que vous feriez ceci:

Network.getListObjectsBy("http://lb.rmc.su/api-dev/v2/wc/5") { 
    (data, error) in 
    if let data == data { 
     print(data) 
    } 
} 
+0

Je ne fais rien d'autre :) Il est tout le code. Malheureusement, je ne comprends pas vraiment quand utiliser la répartition asynchrone. Qu'est-ce que je fais à ce sujet? –

+0

Je pense que votre réponse est correcte, néanmoins vous pouvez expliquer un peu plus sur la façon d'utiliser les fermetures pour transmettre les données dans l'appel asynchrone pour aider plus à la question –

+0

Merci! Maintenant je comprends tout! :) –