简体   繁体   中英

Populating TableView with images from CoreData efficiently | Swift

I'm trying to populate my UITableView with images that were uploaded before by the user. An Image is stored as Binary Data on the users device using CoreData (external storage is enabled).

First the App fetches the data from CoreData in the contactsArray. This function gets called in viewDidLoad

    func loadContacts() {
    let request : NSFetchRequest<ProfileData> = ProfileData.fetchRequest()
    do {
    contactsArray = try context.fetch(request)
    } catch {
        print("Error fetching data from context: \(error)")
    }
}

Then it populates the TableView-Cells.

     cell.contactNameLabel?.text = contactsArray[indexPath.row].contactsName

    if let data = self.contactsArray[indexPath.row].photo {
        cell.contactImageView.image = UIImage(data:data)
    }
    if cell.contactImageView.image == nil {
        cell.contactImageView.image = UIImage(named: "blank_Profile.jpg")
    }

By doing it this way the TableView is lagging more than everything I have ever seen before. So I tried to load the images outside of the "cellForRowAt indexPath" function.

getImages() gets called right after loadContacts() in viewDidLoad. It converts the binary Data into UIImages and puts them in an Array which I then use in cellForRowAt indexPath.

    func getImages(){
    var i = 0
    while i < contactsArray.count {
        print(i)
        if let data = contactsArray[i].photo {
            imageArray.append(UIImage(data:data)!)
        }
        if contactsArray[i].photo == nil {
            imageArray.append(UIImage(named: "blank_Profile.jpg")!)
        }
        i += 1
    }
}

...

    cell.contactImageView.image = imageArray[indexPath.row]

Now the problem is at a different spot. The App now takes more than 15 seconds to launch. I would be very happy if someone could tell me what to do to make the App run fast and in an efficient way.

So I am wondering what your fetch request looks like, that could be a pain point. I would probably suggest using a NSFetchedResultsController it is hard to get more optimized than that. Tutorials aren't tough to find for NSFetchedResultsController but this is the last one I used.

Also I would probably do away with getImages() all together. and just handle that logic wherever you are configuring your cell at.

if let contact = contactsArray[indexPath.row] {
    cell.contactNameLabel?.text = contact.contactsName
    if let imageData = contact.data, let contactImage = UIImage(data: imageData)  {
    cell.contactImageView.image = contactImage
        } else {
        cell.contactImageView.image = // #imageLiteral(resourceName: "blank_Profile.jpg")
    }
}

I would probably just pass the cell the contact and let the cell do the configuration but that is largely a matter of design choice. There are a lot of options and opinions on that.

Another approach you might try if you decide to keep the getImages() might be:

func getImages() {
    for (_, contact) in contactsArray.enumerated() {
        if let data = contact.photo, let image = UIImage(data:data) {
            imageArray.append(image)
            continue
        }
        let profilePlaceholder = // #imageLiteral(resourceName: "blank_Profile.jpg")
            imageArray.append(profilePlaceholder)
    }
}

But again there a lot of different approaches to choose from.

You need to store images on cache in document directory and the path of that cache store in the core data. Loading an image from core data is laggy task.

cell.contactNameLabel?.text = contactsArray[indexPath.row].contactsName

if let data = self.contactsArray[indexPath.row].photo {

    DispatchQueue.global(qos: .background).async {
        // fetch the image data
        // if data fetched, the update the image
        if fetched {
            DispatchQueue.main.async {
                // update the fetched data. this way you can load more faster. and image
                // pulling happens in the background.
                // NOTE: Additionally you can cache this image in memory to load more faster when scrolling
            }
        } else {
            DispatchQueue.main.async {
                // If something went wrong while fetching image
                // show the placeholder in the here
            }
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM