0

Mein Problem teilweise auf meine andere Frage hier Strange behavior when user scrolls the list of UIViewCollectionCells in my app (the data in each cell changes randomly)Abrufen von Daten asynchron und in UICollectionView setzen versagt - Sammlung lädt, bevor die Daten und aktualisiert nicht

In meiner app zusammenhängt ich UICollectionView bin mit. Jede Zelle enthält ein Foto und einen Benutzernamen.

Aber die ersten Dinge zuerst - Ich hole eine JSON-Datei von meinem Webservice mit diesem Benutzernamen und einem Link zu einem Foto. Ich speichere beide Werte in einem Objekt namens SingleUser. Es sieht wie folgt aus:

class SingleUser: NSObject { 

let username: String 
let photo: String 

var image: UIImage? = UIImage() 

init(username: String, photo: String) { 
    self.username = username 
    self.photo = photo 
} 

class func fromJSON(json: JSON) -> SingleUser? { 
    let username = json["username"].string 
    let photo = json["photo"].string 

    return SingleUser(username: username!, photo: photo!) 
} 
} 

Auf Anraten meiner vorherigen Frage, die ich meinen Code und meine Hauptklasse mit UICollectionView geändert sieht wie folgt aus:

class UserList: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate { 

@IBOutlet weak var tview: UICollectionView! 
let reuseIdentifier = "cell" 
var items = NSMutableArray() 

override func viewWillAppear(animated: Bool) { 
    super.viewWillAppear(animated) 

    fetchAllUsers() 
    tview.delegate = self 
    tview.dataSource = self 
} 


func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell { 

    let cell = tview.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as! MyCollectionViewCell 

    let user:SingleUser = self.items[indexPath.item] as! SingleUser 

    cell.username.text = user.name 

    if user.image == nil{ 

     if let checkedUrl = NSURL(string: user.photo) { 
      cell.userImg.contentMode = .ScaleAspectFit 

      getDataFromUrl(checkedUrl) { (data, response, error) in 
       dispatch_async(dispatch_get_main_queue()) {() -> Void in 
        guard let data = data where error == nil else { return } 

        let image = UIImage(data: data) 
        user.image = image 

        if collectionView.cellForItemAtIndexPath(indexPath) == cell 
        { 
         cell.userImg.image = image 
        } 

       } 
      } 

     }else{ 
      cell.userImg.image = user.image 
     } 

    return cell 
} 

so jetzt - hoffentlich - die Daten nicht ändert jeder Der Zeitbenutzer scrollt die Ansicht. Aber es gibt ein großes Problem hier - wenn Benutzer das Panel betritt, wird CollectionView sichtbar, aber alle Fotos nicht so schnell laden. So sieht der Benutzer nur Benutzernamen und Orte für Fotos sind leer.

Es wird verursacht, weil ich in viewWillAppear Daten asynchron mit einem Verfahren fetchAllUsers genannt laden:

func fetchAllUsers(){ 

    Alamofire.request(.GET, "http://mywebservice") 
     .responseJSON { response in 

      switch response.result { 
      case .Success: 
       dispatch_async(dispatch_get_main_queue(),{ 
        self.items.removeAllObjects() 
        if let jsonData = response.result.value as? [[String: AnyObject]] { 
         for requestJSON in jsonData { 
          if let request = SingleUser.fromJSON(JSON(requestJSON)){ 
           self.items.addObject(request) 
           self.tview.reloadData() 


          } 
         } 
        } 
        self.tview.reloadData() 
       }) 

      case .Failure(let error): 
       print("SWITCH ERROR") 
       print(error) 

      } 

    } 
} 

Auch die anderen async Methode, die ich oben ist mit bin:

func getDataFromUrl(url:NSURL, completion: ((data: NSData?, response: NSURLResponse?, error: NSError?) -> Void)) { 
    NSURLSession.sharedSession().dataTaskWithURL(url) { (data, response, error) in 
     completion(data: data, response: response, error: error) 
     }.resume() 
} 

es ist also Hier gibt es viele Async-Aufrufe, die Probleme beim Anzeigen von Datenmangel verursachen, bevor die Ansicht angezeigt wird.

Ich möchte diese Situation vermeiden und stattdessen - zum Beispiel wenn jedes Foto noch nicht geladen ist - zeigen zum Beispiel Ladeanzeige, die verschwindet, wenn das Foto abgerufen wird. Ich bin mir bewusst, dass es notwendig sein könnte, viele Änderungen in meinem Code vorzunehmen, aber könnte ich Sie hier um Rat fragen? Vielen Dank!

Antwort

1

Effektiv müssen Sie die Sammlungsdaten jedes Mal neu laden, wenn neue Daten heruntergeladen werden.

Der beste Ort, dies zu tun, wahrscheinlich in der Schließung der „getDataFromURL“ sein würde, in diesem Verschluss folgenden tun:

dispatch_async(dispatch_get_main_queue()) { 
    tview.reloadData() 
} 

einfach in eine Lade Bild zu haben, das Bild, das Sie in den benötigen setzen Prototypzelle hinter dem Benutzerbild. Dies wird sichtbar sein, bis das Benutzerbild angezeigt wird.

+0

hm ich nicht ganz sicher über die Stelle im Code bin, meinen Sie dies hier setzen: 'Abschluss (Daten: Daten, Antwort: Antwort, Fehler: Fehler) dispatch_async (dispatch_get_main_queue()) { self.tview.ReloadData() } } .resume() '? – user3766930

+0

Es sollte dort arbeiten, aber natürlich wollen Sie sicherstellen, dass Sie zuerst auf Fehler überprüfen –

+0

ok, ich tat es, aber ich habe gerade festgestellt, dass ich in meinem Code nur diese Aussage eingeben: 'else { cell.userImg.image = user.image } 'und niemals das' if user.image == nil {'block, obwohl ich den UIImage in' SingleUser' als leeres 'var image definiert habe: UIImage? = UIImage() '. Hast du eine Ahnung, warum gehe ich überhaupt nicht in die 'if'-Erklärung und gehe immer zum' else'? – user3766930