2017-03-31 4 views
0

J'ai une liste d'environ 8 500 éléments qui se chargent dans un UITableView et il devrait y avoir seulement environ 200 éléments dans lesquels product.isnewitem est vrai. Pour chaque 'nouvel' objet, une image (newicon.png) est supposée charger indiquant qu'il s'agit d'un nouvel élément; Cependant, lorsque je commence à faire défiler la vue de la table, newicon apparaît sur plus de 50% des éléments. Tous les éléments sont chargés via Realm.GCD renvoyant des résultats incorrects dans UITableView

Le chèque de nouveaux éléments se fait dans:

if product.isnewitem { 
     cell.newIconImageView.image = #imageLiteral(resourceName: "newicon.png") 
    } 

est ici toute méthode cellForRowAtIndexPath:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 

    let paths = NSSearchPathForDirectoriesInDomains(documentsDirectory, userDomainMask, true) 

    let cell = tableView.dequeueReusableCell(withIdentifier: "ProductCell") as? OrderFormViewCell 
     ?? UITableViewCell(style: .subtitle, reuseIdentifier: "ProductCell") as! OrderFormViewCell 

    let realm = try! Realm() 
    let allProducts = realm.objects(Product.self).sorted(byKeyPath: "basedescription") 
    let product = allProducts[indexPath.row] 

    cell.productDescriptionLabel.text = product.basedescription 

    queue.async { 
     let realm = try! Realm() 

     let allProducts = realm.objects(Product.self).sorted(byKeyPath: "basedescription") 
     let product = allProducts[indexPath.row] 

     if product.isnewitem { 
      cell.newIconImageView.image = #imageLiteral(resourceName: "newicon.png") 
     } 

     if let dirPath = paths.first { 
      let imageURL = URL(fileURLWithPath: dirPath).appendingPathComponent("T\(product.itemno.replacingOccurrences(of: "-", with: "")).png") 

      if let image = UIImage(contentsOfFile: imageURL.path) { 
       cell.productImageView.image = image 
      } 
      else { 
       cell.productImageView.image = #imageLiteral(resourceName: "image-coming-soon.png") 
      } 
     } 


    } 



    return cell 
} 
+1

Vous ne devriez pas émettre de requêtes de récupération asynchrones dans 'cellForRow (at:)'. Les cellules sont réutilisées de sorte qu'au moment où l'extraction se termine, la cellule aurait pu être réutilisée pour une autre ligne. Assurez-vous également d'effacer explicitement la "nouvelle" image si l'élément n'est pas nouveau. – Paulw11

+0

@ Paulw11 où d'autre devrais-je mettre l'appel asynchrone? J'ai besoin d'utiliser une sorte de thread d'arrière-plan pour que l'interface utilisateur ne soit pas en retard et que j'aie besoin d'accéder à IndexPath car chaque image de produit est unique pour chaque cellule. Est-ce que ce devrait être un appel synchrone à la place? Enfin, qu'entendez-vous par "effacer" la "nouvelle" image? – Sicypher

Répondre

1

Je ne comprends pas pourquoi vous utilisez ce code

let realm = try! Realm() 
let allProducts = realm.objects(Product.self).sorted(byKeyPath: "basedescription") 
let product = allProducts[indexPath.row] 

deux fois dans votre cellForRowAtIndexPath et un dans une file d'attente, je pense que vous devez déplacer ce code sur votre viewControllerviewDidLoad ou viewWillAppear puis utilisez les produits à partir d'un tableau local sur votre déclaration viewController

var allProducts : Results<Product>? 

override func viewWillAppear(_ animated: Bool) { 
    super.viewWillAppear(animated) 
    let realm = try! Realm() 
    self.allProducts = realm.objects(Product.self).sorted(byKeyPath: "basedescription") 
} 

et dans votre cellForRowAtIndexPath vous devriez avoir quelque chose comme ça

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 

let paths = NSSearchPathForDirectoriesInDomains(documentsDirectory, userDomainMask, true) 

let cell = tableView.dequeueReusableCell(withIdentifier: "ProductCell") as? OrderFormViewCell 
    ?? UITableViewCell(style: .subtitle, reuseIdentifier: "ProductCell") as! OrderFormViewCell 

let product = self.allProducts[indexPath.row] 
cell.productDescriptionLabel.text = product.basedescription 
if product.isnewitem { 
     cell.newIconImageView.image = #imageLiteral(resourceName: "newicon.png") 
    } 
else { 
     cell.newIconImageView.image = nil 
    } 

    if let dirPath = paths.first { 
     let imageURL = URL(fileURLWithPath: dirPath).appendingPathComponent("T\(product.itemno.replacingOccurrences(of: "-", with: "")).png") 

     if let image = UIImage(contentsOfFile: imageURL.path) { 
      cell.productImageView.image = image 
     } 
     else { 
      cell.productImageView.image = #imageLiteral(resourceName: "image-coming-soon.png") 
     } 
    } 

return cell 
} 

J'espère que cela vous aide

+0

J'ai deux instances de Realm dans cette méthode car Realm vous oblige à avoir une nouvelle instance dans chaque thread. Une instance de domaine ne peut pas être utilisée sur plusieurs threads. – Sicypher

+0

mais pourquoi avez-vous besoin de 2 threads? –

+0

Les images doivent être chargées sur un thread d'arrière-plan dans une vue de table, car elles affecteront de manière significative l'interface utilisateur si elles sont chargées sur le thread principal. – Sicypher