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

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

Важные примечания:

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

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

Получите данные с помощью NSURLSession — DataTask. После этого «разбор» его и проверка, существует ли каждый объект (в цикле for) в базе данных Core Data, а затем добавление его переменных в массив источника данных TableView и перезагрузка данных

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()

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

 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

Есть предложения, в чем причина проблемы?


person Jackky White    schedule 11.04.2015    source источник
comment
Непонятно, как код, который вы показываете, связан с прокруткой таблицы. Вряд ли вам следует вызывать reloadData внутри цикла.   -  person Wain    schedule 11.04.2015
comment
@Wain, я удалил его до конца цикла, все еще идет медленно .. есть предложения?   -  person Jackky White    schedule 12.04.2015
comment
Я добавил метод cellForRowAtIndexPath @Wain   -  person Jackky White    schedule 12.04.2015


Ответы (1)


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

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

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

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

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

person Wain    schedule 12.04.2015
comment
звучит интересно, не могли бы вы поддержать пример с моим методом выше? :( - person Jackky White; 12.04.2015
comment
попробуйте, вы учитесь, обдумывая и решая проблему ;-) - person Wain; 12.04.2015
comment
пытался в течение последних 3 часов .. безрезультатно, я думаю, что нашел проблему. каждый раз, когда я прокручиваю его, перезагружаю его из локального каталога, это должно быть так? - person Jackky White; 12.04.2015
comment
Вот почему я говорю о кэшировании после загрузки с диска. - person Wain; 12.04.2015
comment
так ты имеешь в виду, что каждый раз, когда я загружаю его, перемещаю его в nscache? - person Jackky White; 12.04.2015
comment
да, но это означает, что вы загружаете его только один раз, а затем получаете из кеша (загружаете только в том случае, если кеш пуст для этого изображения) - person Wain; 12.04.2015
comment
Я попробую это, другими словами, медлительность возникает из-за загрузки изображения из каталога кеша? - person Jackky White; 12.04.2015
comment
Это так расстраивает, я не могу найти хорошего объяснения, как хранить и получать данные с помощью NSCache с использованием swfit, лол, у вас есть хороший ресурс? - person Jackky White; 12.04.2015
comment
Нет, сейчас я не пишу быстро. Это не обязательно должно быть NSCache, NSDictionary отлично подойдет с ключом в качестве пути и значением в качестве изображения. - person Wain; 12.04.2015
comment
Уэйн, я действительно не могу понять, как сохранить что-то локально, а затем загрузить его медленнее, чем использовать NSDictionary, приложение FB сохраняет все данные локально, как, черт возьми, они анализируют их так быстро? - person Jackky White; 12.04.2015
comment
Давайте продолжим это обсуждение в чате. - person Wain; 12.04.2015