DZone
Mobile Zone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
  • Refcardz
  • Trend Reports
  • Webinars
  • Zones
  • |
    • Agile
    • AI
    • Big Data
    • Cloud
    • Database
    • DevOps
    • Integration
    • IoT
    • Java
    • Microservices
    • Open Source
    • Performance
    • Security
    • Web Dev
DZone > Mobile Zone > Dynamically Loading Table View Images in iOS

Dynamically Loading Table View Images in iOS

Learn how thumbnail images in the table views of iOS mobile apps can be loaded dynamically as needed to populate table view cells.

Greg Brown user avatar by
Greg Brown
·
Jul. 10, 17 · Mobile Zone · Tutorial
Like (4)
Save
Tweet
15.48K Views

Join the DZone community and get the full member experience.

Join For Free

ios applications often display thumbnail images in table views alongside other text-based content such as contact names or product descriptions. however, these images are not usually delivered with the initial request, but must instead be retrieved separately afterward. they are typically downloaded in the background as needed to avoid blocking the main thread, which would temporarily render the user interface unresponsive.

for example, consider this rest service , which returns a list of simulated photo data:

[
  {
    "albumid": 1,
    "id": 1,
    "title": "accusamus beatae ad facilis cum similique qui sunt",
    "url": "http://placehold.it/600/92c952",
    "thumbnailurl": "http://placehold.it/150/92c952"
  },
  {
    "albumid": 1,
    "id": 2,
    "title": "reprehenderit est deserunt velit ipsam",
    "url": "http://placehold.it/600/771796",
    "thumbnailurl": "http://placehold.it/150/771796"
  },
  {
    "albumid": 1,
    "id": 3,
    "title": "officia porro iure quia iusto qui ipsa ut modi",
    "url": "http://placehold.it/600/24f355",
    "thumbnailurl": "http://placehold.it/150/24f355"
  },
  ...
]

each record contains a photo id, album id, and title, as well as urls for both thumbnail and full-size images; for example:

photo class

a class representing this data might be defined as follows:

class photo: nsobject {
    var id: int = 0
    var albumid: int = 0
    var title: string?
    var url: url?
    var thumbnailurl: url?

    init(dictionary: [string: any]) {
        super.init()

        setvaluesforkeys(dictionary)
    }

    override func setvalue(_ value: any?, forkey key: string) {
        switch key {
        case #keypath(url):
            url = url(string: value as! string)

        case #keypath(thumbnailurl):
            thumbnailurl = url(string: value as! string)

        default:
            super.setvalue(value, forkey: key)
        }
    }
}

since instances of this class will be populated using dictionary values returned by the web service, an initializer that takes a dictionary argument is provided. the setvaluesforkeys(_:) method of nsobject is used to map dictionary entries to property values. the id and title properties are handled automatically by this method; the class overrides setvalue(_:forkey:) to convert the urls from strings into actual url instances.

view controller class

a basic user interface for displaying service results in a table view is shown below:

row data is stored in an array of photo instances. previously loaded thumbnail images are stored in a dictionary that associates uiimage instances with photo ids:

class viewcontroller: uitableviewcontroller {
    // row data
    var photos: [photo]!

    // image cache
    var thumbnailimages: [int: uiimage] = [:]

    ...    
}

the photo list is loaded the first time the view appears. the wswebserviceproxy class of the open-source http-rpc library is used to retrieve the data. if the call succeeds, the response data (an array of dictionary objects) is transformed into an array of photo objects and the table view is refreshed. otherwise, an error message is displayed:

override func viewwillappear(_ animated: bool) {
    super.viewwillappear(animated)

    // load photo data
    if (photos == nil) {
        let serviceproxy = wswebserviceproxy(session: urlsession.shared, serverurl: url(string: "https://jsonplaceholder.typicode.com")!)

        serviceproxy.invoke("get", path: "/photos") { result, error in
            if (error == nil) {
                let photos = result as! [[string: any]]

                self.photos = photos.map({
                    return photo(dictionary: $0)
                })

                self.tableview.reloaddata()
            } else {
                let alertcontroller = uialertcontroller(title: "error", message: error!.localizeddescription, preferredstyle: .alert)

                alertcontroller.addaction(uialertaction(title: "ok", style: .default))

                self.present(alertcontroller, animated: true)
            }
        }
    }
}

cell content is generated as follows. the corresponding photo instance is retrieved from the photos array and used to configure the cell:

override func tableview(_ tableview: uitableview, numberofrowsinsection section: int) -> int {
    return (photos == nil) ? 0 : photos.count
}

override func tableview(_ tableview: uitableview, cellforrowat indexpath: indexpath) -> uitableviewcell {
    var cell = tableview.dequeuereusablecell(withidentifier: cellidentifier)

    if (cell == nil) {
        cell = uitableviewcell(style: .default, reuseidentifier: cellidentifier)
    }

    let photo = photos[indexpath.row];

    cell!.textlabel!.text = photo.title

    // attempt to load image from cache
    cell!.imageview!.image = thumbnailimages[photo.id]

    if (cell!.imageview!.image == nil && photo.thumbnailurl != nil) {
        // image was not found in cache; load it from the server

        ...
    }

    return cell!
}

if the thumbnail image is already available in the cache, it is used to populate the cell's image view. otherwise, it is loaded from the server and added to the cache as shown below. if the cell is still visible when the image request returns, it is updated immediately and reloaded:

let serverurl = url(string: string(format: "%@://%@", photo.thumbnailurl!.scheme!, photo.thumbnailurl!.host!))!

let serviceproxy = wswebserviceproxy(session: urlsession.shared, serverurl: serverurl)

serviceproxy.invoke("get", path: photo.thumbnailurl!.path) { result, error in
    if (error == nil) {
        // if cell is still visible, update image and reload row
        let cell = tableview.cellforrow(at: indexpath)

        if (cell != nil) {
            if let thumbnailimage = result as? uiimage {
                self.thumbnailimages[photo.id] = thumbnailimage

                cell!.imageview!.image = thumbnailimage

                tableview.reloadrows(at: [indexpath], with: .none)
            }
        }
    } else {
        print(error!.localizeddescription)
    }
}

finally, if the system is running low on memory, the image cache is cleared:

override func didreceivememorywarning() {
    super.didreceivememorywarning()

    // clear image cache
    thumbnailimages.removeall()
}

summary

this article provided an overview of how images can be dynamically loaded as needed to populate table view cells in ios. for more ways to simplify ios app development, please see my projects on github:

  • markupkit
  • http-rpc
Database

Published at DZone with permission of Greg Brown, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • Observability Tools Help Catch Application Failures — But Automating the Observer Is Becoming Crucial
  • No Sprint Goal, No Cohesion, No Collaboration
  • A Concise Guide to DevSecOps and Their Importance in CI/CD Pipeline
  • Querydsl vs. JPA Criteria - Introduction

Comments

Mobile Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • MVB Program
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends:

DZone.com is powered by 

AnswerHub logo