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!
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
Es sollte dort arbeiten, aber natürlich wollen Sie sicherstellen, dass Sie zuerst auf Fehler überprüfen –
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