2017-04-13 7 views
0

Ich brauche den Aktivitätsindikator, um zu starten, wenn eine Webanforderung erstellt wird, und zu stoppen, sobald sie beendet ist. Im Moment wird die Anzeige angezeigt, aber die .stopAnimation wird gerade ausgeführt und wartet nicht auf die Beendigung der Web-Anfrage.kann Aktivitätsanzeige nicht nach asynchroner Webanforderung stoppen

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

Vielleicht ist Ihre Web-Anfrage so schnell ;-). Btw: Beachten Sie, dass der Indikator im Falle eines Fehlers nicht stoppt. Das wäre ein gutes Beispiel für die "Defer" -Anweisung. – vadian

+0

PS: ... und der übliche Hinweis: Verwenden Sie kein 'NSMutable ...', wenn es in Swift entweder ein natives Swift-Pendant gibt und nicht 'NSArray',' NSDictionary'. – vadian

+0

Welche Alternative gibt es für NSDictionary? – t2nator

Antwort

0

Fügen Sie nach der DispatchQueue den Code self.theProgressOutlet.stopAnimating() hinzu. Versuchen Sie diese

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

versuchen Sie dies und sehen, ob es funktioniert.

+0

Sie wollten wahrscheinlich sagen, innen und nicht nach ... –

+0

versuchen nach. Es funktionierte für mich –

+0

das funktionierte auch für mich! Vielen Dank – t2nator

0

Ich sehe nicht den Code, der Ihre UIActivityIndicatior startet. Instantiieren Sie UIActivityIndicator in Ihrem viewDidLoad und rufen Sie theProgressOutlet.startAnimating() vor task.resume() auf.

Denken Sie daran, dass dies das Problem für Ihren aktuellen Code löst. Situationen treten auf, wenn Sie mehrere asynchrone Anforderungen in einer Szene haben und activityIndicator am Anfang des Prozesses beginnen und nach dem erfolgreichen Abschluss aller Aufrufe enden muss. Um Ihre aktuelle Situation und die, die ich erwähnt habe, zu behandeln, schlage ich vor, dass Sie eine Wrapper-Klasse mit einer internen Queue implementieren. Sie können auch eine http-Handler-Klasse erstellen, um alle Ihre Anfragen zu bearbeiten, sodass Sie diesen Prozess nur an einer Stelle bearbeiten und spätere Änderungen und das Debugging vereinfachen können.

0

Sie sollten die hidesWhenStopped-Eigenschaft auf true setzen und mit der Animation der theProgressOutlet beginnen, bevor Sie die dataTask fortsetzen.

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() 

es in der bearbeiteten oben nisten :)