Ошибка и медленная прокрутка при загрузке изображений TableView из CoreData

Проблема: процесс загрузки изображений в табличное представление с использованием их путей, которые хранятся в базе данных Core Data, работает нормально, но пользовательский опыт не идет хорошо. Свиток медленный и глючный.

Примечания импортеров:

  • Для моей локальной базы данных я использую Core Data
  • Я не сохраняю само изображение в Базовых данных, только их путь (имя изображения)
  • Что касается табличного представления DataSource, я использую массив типа Person, который содержит идентификатор и имя Img (строки Table View равны array.Count). -Это URL, из которого я получаю мой Json (Проверьте это) - Json Link
  • Все объекты внутри БД базовых данных
  • Насколько я знаю, я сделал все обновления пользовательского интерфейса в главном журнале
  • После каждой проверки я перезагружаю таблицу.

Это шаги, которые выполняются в правильной последовательности:

Получить данные с помощью NSURLSession - DataTask. После этого он выполняет "синтаксический анализ" и проверяет, существует ли каждый объект (в цикле for) в БД базовых данных, а затем добавляет его переменные в массив источника данных Table View и перезагружает данные.

1)

let request = NSMutableURLRequest(URL: dataSourceURL!)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
    data, response, error in

    if error != nil {
        println("error=\(error)")
        return
    }
    if data != nil {
        let datasourceDictionary = NSJSONSerialization.JSONObjectWithData(data, options: nil, error: nil) as NSDictionary

        var  DataArray =  datasourceDictionary["descisions"] as NSArray

//Convert it to useable array

        for var i = 0 ; i < DataArray.count ; i++ {
            let ID_s = DataArray[i]["ID"]! as Int

//For each Object from the Json array i'm check if he is exisitng in the local DB
            var ConvertetdID = Int32(ID_s)
            let object : Lockdown? =        self.CheckIfObjectExistInDBbyID(ConvertetdID)

//CheckIfExists - if it does , it return an object with the correct values

            if  object != nil  {
                //exists - load file from Core Data
                let imgname = object!.imgPath
                let photoRecord = PhotoRecord(name:"\(ConvertetdID)", url:imgname)
                self.photos.append(photoRecord)

//TableView object array (photos)

                dispatch_async(dispatch_get_main_queue())  {
                self.tableView.reloadData()

//After each check reload the tableView   
            }
        }
    }
}
task.resume()

Метод, который проверяет, существует ли он в основной базе данных или нет (метод получает идентификатор и возвращает объект, если существует, и ноль, если нет:

 func CheckIfObjectExistInDBbyID(id : Int32) -> Lockdown? {
        let appDelegate =
        UIApplication.sharedApplication().delegate as AppDelegate

        let managedContext = appDelegate.managedObjectContext!
        var request : NSFetchRequest = NSFetchRequest(entityName: "Lockdown")
        request.predicate = NSPredicate(format: "id = %d", id)
        var error : NSError?
        request.fetchLimit = 1
        var count : Int = managedContext.countForFetchRequest(request,error: &error)
        if count == 0 {
           // println("Error : \(error?.localizedDescription)")
            println("Object \(id) Dosent exist in CoreData")

            return nil

        }
        println("Object \(id)  exist in CoreData")


        let result = managedContext.executeFetchRequest(request, error: &error) as NSArray!
        let lockdown = result.objectAtIndex(0) as Lockdown
        println(lockdown.id)
        return lockdown




    }

Метод cellForRowAtIndexPath

 let cell = tableView.dequeueReusableCellWithIdentifier("CellIdentifier", forIndexPath: indexPath) as UITableViewCelllet photoDetails = photos[indexPath.row]





  cell.textLabel.text = photoDetails.name as String
      dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)) {
        var myPathList : NSArray = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.CachesDirectory, NSSearchPathDomainMask.UserDomainMask, true)

        var myPath = myPathList[0] as String
        myPath = myPath.stringByAppendingPathComponent("\(photoDetails.name).png")
        var image : UIImage = UIImage(contentsOfFile: myPath)!

        dispatch_async(dispatch_get_main_queue()) {

            cell.imageView.image = image
        }
    }

return cell

Любые предложения, что является причиной проблемы?

1 ответ

Вы не должны всегда загружать образ с диска, это медленно. Вместо этого сначала загрузите образ с диска, а затем сохраните его в кеше (в памяти). Проверьте, кэшировано ли изображение, прежде чем загружать его с диска.

Вам нужно очистить кеш, если он становится слишком большим или вы получаете предупреждение о памяти.

Расширенные версии могут предварительно кэшировать некоторые изображения для ячеек, которые находятся чуть ниже текущей позиции прокрутки.

Вы можете использовать библиотеку для этого, возможно, SDWebImage с URL-адресами файлов (я этого не пробовал).

Ошибка состоит в том, что ваш асинхронный блок не проверяет, что ячейка не была повторно использована до загрузки изображения. Если это так, то в повторно используемой ячейке появится неправильное изображение (пока оно не будет заменено другим изображением). Чтобы исправить, захватить indexPath в блоке и получить клетку для этого indexPath как только изображение загружено - если табличное представление возвращается nil тогда ячейка больше не видна, и вам не нужно ничего делать, кроме как кэшировать изображение для будущего использования.

Другие вопросы по тегам