2017-02-08 5 views
0

Im Folgenden werde ich meine vorhandene Abfrage herunterladen und Zelle für Tabellenzeile Code haben ...Verlangsamen CloudKit-Tabellendurchlauf - bestehenden Code ändern?

publicDB.perform(query, inZoneWith: nil) 
    { 
     (results, error) -> Void in 
     if (error != nil) 
     { 
      self.present(alert, animated: true, completion: nil) 
     } 
     else 
     { 
      for result in results! 
      { 
       self.restaurantArray.append(result) 
      } 
      OperationQueue.main.addOperation({() -> Void in 
       self.tableView.reloadData() 
      }) } }} 
downloadRestaurants() 
} 

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
    let cell = tableView.dequeueReusableCell(withIdentifier: "restaurantcell") as? RestaurantTableCell 
    let restaurant: CKRecord = restaurantArray[indexPath.row] 
    cell?.name?.text = restaurant.value(forKey: "Name") as? String 
    let asset = restaurant.value(forKey: "Picture") as! CKAsset 
    let data = try! Data(contentsOf: asset.fileURL) 
    _ = UIImage(data: data) 
    cell?.picture?.image = UIImage(data: data) 
    return cell! 
} 

Wenn ich diesen Code ausführen, die App bleibt funktionsfähig, aber Scrollen durch die 10 oder so Tabellenzellen ist unglaublich abgehackt. Ich bin mir nicht sicher, was das verursacht - alle Datensätze, die jeweils ein Bild enthalten, werden während des Abfrage-Download-Teils der obersten Funktion heruntergeladen. Ein Problem oder ein Konzept, das ich vermisse, ist jedoch während der Laufzeit immer vorhanden. Was fehlt mir hier? Faules Laden? Zwischenspeicher? etwas anderes? Ich bin zu diesem Zeitpunkt nicht sicher, also wäre jede Hilfe unglaublich hilfreich.

Update 1:

Ich habe meinen Code mit einem großen aktualisiert danke zu Pierce gehen. Ich musste meinen Code ein wenig von seiner Antwort aktualisieren, um ein ckrecord-Array zu pflegen, um über - restaurantArray zu einem anderen Controller zu wechseln, aber auch ein neues Array für den NSObject-Klassen-Tablerestaurantarray zu erstellen, der im aktuellen Tabellen-Controller angezeigt wird.

var restaurantArray: Array<CKRecord> = [] 
    var tablerestaurantarray: [Restaurant] = [] 

for result in results! 
      { 
       let tablerestaurant = Restaurant() 

       if let name = result.value(forKey: "Name") as! String? { 
        tablerestaurant.name = name 
       } 
       // Do same for image 
       if let imageAsset = result.object(forKey: "Picture") as! CKAsset? { 

        if let data = try? Data(contentsOf: imageAsset.fileURL) { 
         tablerestaurant.image = UIImage(data: data) 
        } 
       } 
       self.tablerestaurantarray.append(tablerestaurant) 

       self.restaurantArray.append(result) 
      } 
      OperationQueue.main.addOperation({() -> Void in 
       self.tableView.reloadData()  
      }) 
     } 
    } 
} 
downloadRestaurants() 
} 
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 
    return restaurantArray.count 
} 
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
    let cell = tableView.dequeueReusableCell(withIdentifier: "restaurantcell") as? RestaurantTableCell 

    let restaurant: Restaurant = tablerestaurantarray[indexPath.row] 
    cell?.name?.text = restaurant.name 

    cell?.picture?.image = restaurant.image 
    return cell! 
} 
+1

Jedes Mal, wenn Sie in Ihrem TableView blättern, muss Ihre App einen 'CKAsset' in' Data' umwandeln und diesen in einen 'UIImage' konvertieren.Ich würde empfehlen, eine Art 'NSObject' namens 'Restaurant' oder so etwas zu erstellen, dann, wenn Sie Ihre Abfrage durchführen, nehmen Sie jeden Datensatz aus dem Array von' CKRecords' und parsen ihn in ein 'Restaurant'-Objekt, das ein' UIImage' hat property, verwenden Sie dann die Bilder dieser Objekte, um die Zellen zu füllen. Auf diese Weise muss es nur ein UIImagage greifen, anstatt es jedes Mal umzuwandeln. – Pierce

+0

Wären Sie in der Lage, ein Codebeispiel zu liefern, Pierce? Ich musste nie zuvor mit NSObjects in meinen Projekten arbeiten, daher bin ich ein bisschen zurück. – Jon

+0

Bitte sehen Sie meine Antwort unter – Pierce

Antwort

1

Die Art und Weise Ihr Code-Setup ist, wenn Sie in Ihrem UITableView bewegen, wird Ihr Programm eines CKAsset in Data, Konvertieren und dann, dass in eine UIImage Umwandlung, und das ist in jeder Zelle! Das ist ein ziemlich ineffizienter Prozess. Versuchen Sie also, ein NSObject mit dem Namen Restaurant zu erstellen, das über eine image-Eigenschaft verfügt. Wenn Sie alle von CKQuery zurückgegebenen Datensätze durchlaufen, analysieren Sie jeden Datensatz in einem neuen Restaurant-Objekt. Um einen neuen NSObject zu erstellen, gehen Sie zu Datei -> Neu -> Datei -> wählen Sie 'Swift Datei' und fügen Sie etwas wie folgt aus:

import UIKit 

class Restaurant: NSObject { 

    // Create a UIImage property 
    var image: UIImage? 

    // Add any other properties, i.e. name, address, etc. 
    var name: String = "" 
} 

Jetzt für Ihre Anfrage:

// Create an empty array of Restaurant objects 
var restaurantArray: [Restaurant] = [] 

publicDB.perform(query, inZoneWith: nil) { (results, error) -> Void in 
    if (error != nil) { 
     self.present(alert, animated: true, completion: nil) 
    } else { 
     for result in results! { 

      // Create a new instance of Restaurant 
      let restaurant = Restaurant() 

      // Use optional binding to check if value exists 
      if let name = result.value(forKey: "Name") as! String? { 
       restaurant.name = name 
      } 
      // Do same for image 
      if let imageAsset = result.object(forKey: "Picture") as! CKAsset? { 

       if let data = try? Data(contentsOf: imageAsset.fileURL) { 
        restaurant.image = UIImage(data: data) 
       } 
      } 

      // Append the new Restaurant to the Restaurants array (which is now an array of Restaurant objects, NOT CKRecords) 
      self.restaurantArray.append(restaurant) 
     } 
     OperationQueue.main.addOperation({() -> Void in 
      self.tableView.reloadData() 
     }) 
    } 
} 

Jetzt Ihr Handy Setup ist viel einfacher:

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

    let cell = tableView.dequeueReusableCell(withIdentifier: "restaurantcell") as? RestaurantTableCell 

    let restaurant: Restaurant = restaurantArray[indexPath.row] 
    cell?.name?.text = restaurant.name 

    cell?.picture?.image = restaurant.image 
    return cell! 
} 
0

Sie CKQueryOperation um verwenden sollten Paginierung für Ihre UITableView implementiert.

Sie haben die resultLimit Eigenschaft auf eine Zahl gesetzt ist gleich zu der Zelle Menge visiable zu einer Zeit auf Sie Tisch plus 3 oder 4

Set recordFetchedBlock Hotel, in dem Sie den Code zu implementieren, die auf eine CKRecord gelten

Set queryCompletionBlock Eigenschaft. Dies ist der wichtigste Teil Ihres Paginierungscodes, da dieser Abschluss einen optionalen CKQueryCursor-Parameter erhält. Wenn dieser CKQueryCursor gleich Null ist, haben Sie den letzten verfügbaren Datensatz für Ihre Abfrage erreicht, aber wenn es sich um einen Nicht-Null-Wert handelt, müssen Sie mehr Datensätze abrufen, die diesen CKQueryCursor als Indikator für Ihren nächsten Abruf verwenden.

Wenn Benutzer auf Ihrem TableView blättern und das letzte Element erreichen, sollten Sie einen weiteren Abruf mit CKQueryCursor durchführen.

Weitere Leistungsempfehlung ist CKASsets sollten auf getrennten Ausführungswarteschlangen behandelt werden.