2017-04-13 2 views
0

J'ai besoin de l'indicateur d'activité pour démarrer chaque fois qu'une requête Web est effectuée et qu'elle s'arrête une fois l'opération terminée. À l'heure actuelle, l'indicateur s'affiche, mais le .stopAnimation s'exécute même immédiatement et n'attend pas la fin de la requête Web.Impossible d'arrêter l'indicateur d'activité après une requête Web asynchrone

import UIKit 


class ViewController: 
UIViewController,UIPickerViewDelegate,UIPickerViewDataSource { 

@IBOutlet weak var locationPickerOutlet: UIPickerView! 
@IBOutlet weak var theProgressOutlet: UIActivityIndicatorView! 

var locationspickerData: [String] = [String]() 

override func viewDidLoad() { 
    super.viewDidLoad() 

    populateLocations() 

} 


func populateLocations() { 

    self.locationspickerData = ["All Locations"] 
    let url:URL = URL(string: "http://<web address>")! 
    let session = URLSession.shared 
    let request = NSMutableURLRequest(url: url) 
    request.httpMethod = "GET" 
    //request.cachePolicy = NSURLRequest.CachePolicy.reloadIgnoringCacheData 
    let task = session.dataTask(with: request as URLRequest, completionHandler: { 
     (data, response, error) in 
     guard let _:Data = data, let _:URLResponse = response , error == nil else { 
      return 
     } 

     let json: Any? 
     do 
     { 
      json = try JSONSerialization.jsonObject(with: data!, options: []) 
     } 
     catch 
     { 
      return 
     } 
     guard let data_list = json as? NSArray else 
     { 
      return 
     } 
     if let locations_list = json as? NSArray 
     { 

      for i in 0 ..< data_list.count 
      { 
       if let locations_obj = locations_list[i] as? NSDictionary 
       { 
        if let location_name = locations_obj["name"] as? String 
        { 
         self.locationspickerData.append(location_name) 
        } 
       } 
      } 


      self.locationPickerOutlet.delegate = self 
      self.locationPickerOutlet.dataSource = self 
      DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) { 
       self.theProgressOutlet.stopAnimating() 
      } 

     } 

    }) 

    task.resume() 

} 



override func didReceiveMemoryWarning() { 
    super.didReceiveMemoryWarning() 
} 


func numberOfComponents(in pickerView: UIPickerView) -> Int { 
    return 1 
} 

func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { 
    return locationspickerData.count 
} 


func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? { 
    return locationspickerData[row] 
} 

func pickerView(_ pickerView: UIPickerView, attributedTitleForRow row: Int, forComponent component: Int) -> NSAttributedString? { 
    let titleData = locationspickerData[row] 
    let myTitle = NSAttributedString(string: titleData, attributes: [NSFontAttributeName:UIFont(name: "Georgia", size: 15.0)!,NSForegroundColorAttributeName:UIColor.blue]) 
    return myTitle 
} 
+1

Peut-être que votre requête Web est que rapide ;-). Btw: Considérez que l'indicateur ne s'arrêtera pas en cas d'erreur. Ce serait un bon exemple pour l'instruction 'defer'. – vadian

+0

PS: ... et le conseil habituel: N'utilisez pas de 'NSMutable ...' s'il y a une contrepartie natif Swift et non pas 'NSArray',' NSDictionary' dans Swift non plus. – vadian

+0

quelle alternative existe-t-il pour NSDictionary? – t2nator

Répondre

0

Ajoutez le code self.theProgressOutlet.stopAnimating() après DispatchQueue. Essayez ceci

DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) { 
//Your code  
      } 
self.theProgressOutlet.stopAnimating() 

Essayez ceci et voyez si cela fonctionne.

+0

Vous avez probablement voulu dire à l'intérieur et non après ... –

+0

essayez après. Cela a fonctionné pour moi –

+0

cela a fonctionné pour moi aussi! Merci – t2nator

0

Je ne vois pas le code qui démarre votre UIActivityIndicatior. Instancez juste UIActivityIndicator dans votre viewDidLoad et appelez theProgressOutlet.startAnimating() avant task.resume(). N'oubliez pas que cela résout le problème pour votre code actuel. Des situations se produisent lorsque vous avez plusieurs demandes asynchrones dans une scène et que activityIndicator doit commencer au début du processus et se terminer une fois tous les appels terminés avec succès. Pour gérer votre situation actuelle et celle que j'ai mentionnée, je vous suggère de créer une classe wrapper avec une file d'attente interne implémentée. Vous pouvez également créer une classe de gestionnaire http pour faire toutes vos demandes afin que vous puissiez gérer ce processus à un seul endroit et apporter des modifications et un débogage plus facile plus tard.

0

Vous devez définir la propriété hidesWhenStopped sur true et commencer à animer le theProgressOutlet avant de reprendre le dataTask.

theProgressOutlet.hidesWhenStopped = true 
theProgressOutlet.startAnimating() 

let task = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) in 
    // YOUR CODE HERE 
} 
0
DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) { 
//Your code  
     } 
self.theProgressOutlet.stopAnimating() 

il nicher dans ce qui précède :)

travaillé