{"id":341,"date":"2015-10-28T01:37:29","date_gmt":"2015-10-28T01:37:29","guid":{"rendered":"http:\/\/strawberrycode.com\/blog\/?p=341"},"modified":"2015-10-28T01:38:36","modified_gmt":"2015-10-28T01:38:36","slug":"simple-uicollectionview-pagination-with-api-and-realm-database","status":"publish","type":"post","link":"https:\/\/strawberrycode.com\/blog\/simple-uicollectionview-pagination-with-api-and-realm-database\/","title":{"rendered":"Simple UICollectionView pagination with API and Realm database"},"content":{"rendered":"<p>If you&#8217;re using Realm database and a REST API, you may have\u00a0encountered a pagination issue at some point.\u00a0That&#8217;s what happened in the project I&#8217;m working on. Something was wrong with the pagination and I kept adding variables and ifs until I couldn&#8217;t remember what was doing what. Then I realized I needed a clean slate, and I created this little project.<\/p>\n<p>So, this is a mockup to test a minimum viable pagination and preloading of data from a REST API to feed a <code>UITableView<\/code> or <code>UICollectionView<\/code>, using <a href=\"https:\/\/realm.io\" target=\"_blank\">Realm.io<\/a> database.<br \/>\nJust to make things clear, I am not introducing pagination into Realm&#8217;s API, nor am I paginating Realm results themselves.<\/p>\n<h2>A few words about Realm<\/h2>\n<p>Realm is a great database: easy to use, flexible, efficient, cross-platform, fully documented and very well maintained. In one word, it&#8217;s brilliant! For more info, have a look <a href=\"https:\/\/realm.io\/docs\/swift\/latest\/\" target=\"_blank\">here<\/a>.<\/p>\n<p>One thing to know if you worked with other databases before: there is no pagination (or limit) in Realm&#8217;s current API, you always get all the results matching your query. This actually makes sense as you may not want to store all the possible dynamic content of the Earth on your device, but only what&#8217;s useful to you. Also, when there is any changes in the database, your application gets notified and you usually reload the content. It&#8217;s usually the point, right?<\/p>\n<p>So I came across a pagination challenge: how to preload nicely (and quietly) the next batch of content so it would be available when you scroll to it?<\/p>\n<h2>The idea<\/h2>\n<p>The idea is simple: you need to trigger the preload when you reach a certain point (nothing new under the sun, that&#8217;s basic pagination) AND you need to prevent multiple (unwanted) preloads from happening.<\/p>\n<p>If you miss the second point, the waterfall effect can be quite impressive to watch: you load the 1st batch of data that creates the cells, then it reaches the preload point that loads the next set of data that reloads the view and creates the cells, etc. Yep, infinite loop, our favorite!<\/p>\n<h2>The implementation<\/h2>\n<p>Let&#8217;s build a simple pagination mechanism together!<\/p>\n<p>First, initialization:<\/p>\n<pre class=\"lang:swift decode:true \">let pageSize = 20 \/\/ that's up to you, really\r\nlet preloadMargin = 5 \/\/ or whatever number that makes sense with your page size\r\nvar lastLoadedPage = 0<\/pre>\n<p>In <code>viewDidLoad<\/code>, make sure to get your first batch of data, and to reload when the database is updated:<\/p>\n<pre class=\"lang:swift decode:true \">override func viewDidLoad() {\r\n    super.viewDidLoad()\r\n\r\n    \/\/ do stuff here\r\n\r\n    notificationToken = realm.addNotificationBlock { [unowned self] note, realm in\r\n        self.reloadData()\r\n    }\r\n\r\n    getData()\r\n}<\/pre>\n<p>Then make sure you can get and reload data:<\/p>\n<pre class=\"lang:swift decode:true \">func getData(page: Int = 0) {\r\n    lastLoadedPage = page\r\n    \/\/ TODO: do the API call to get data\r\n}\r\n\r\nfunc reloadData() {\r\n    \/\/ TODO: retrieve data from the database\r\n    collectionView?.reloadSections(NSIndexSet(index: 0))\r\n}<\/pre>\n<p>And here is the bit of code that checks if we need to load the next page of data:<\/p>\n<pre class=\"lang:swift decode:true\">override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -&gt; UICollectionViewCell {\r\n\r\n    let nextPage: Int = Int(indexPath.item \/ pageSize) + 1\r\n    let preloadIndex = nextPage * pageSize - preloadMargin\r\n\r\n    \/\/ trigger the preload when you reach a certain point AND prevent multiple loads and updates\r\n    if (indexPath.item &gt;= preloadIndex &amp;&amp; lastLoadedPage &lt; nextPage) {\r\n        getData(nextPage)\r\n    }\r\n\r\n    \/\/ TODO: configure cell\r\n}<\/pre>\n<p>Nothing complicated, I just wanted to keep it clean and simple. The full demo project is on GitHub: <a href=\"https:\/\/github.com\/strawberrycode\/RealmPagination\" target=\"_blank\">RealmPagination<\/a>.<\/p>\n<p>Just one word before we leave: if you have auto-resizing cells, set the default size value as close to the final size as you can get. The reason is simple: when you reload your <code>UITableView<\/code> or <code>UICollectionView<\/code>, the scroll offset will be calculated based on the estimated cell size. So your <code>scrollView<\/code> may be off after the reload, and you may end up landing on the wrong cell.<\/p>\n<p>Any thoughts or feedback on Realm or pagination? Please leave a comment below :)<\/p>\n","protected":false},"excerpt":{"rendered":"<p>If you&#8217;re using Realm database and a REST API, you may have\u00a0encountered a pagination issue at some point.\u00a0That&#8217;s what happened in the project I&#8217;m working on. Something was wrong with the pagination and I kept adding variables and ifs until I couldn&#8217;t remember what was doing what. Then I realized I needed a clean slate, and I created this little project. So, this is a mockup to test a minimum viable pagination and preloading of data from a REST API to feed a UITableView or UICollectionView, using Realm.io database. Just to make things clear, I am not introducing pagination into &hellip; <a href=\"https:\/\/strawberrycode.com\/blog\/simple-uicollectionview-pagination-with-api-and-realm-database\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Simple UICollectionView pagination with API and Realm database<\/span> <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":183,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0},"categories":[40],"tags":[72,71,17,67,70,73,41,69,68],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v16.1.1 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>UICollectionView pagination with Realm - StrawberryCode<\/title>\n<meta name=\"description\" content=\"If you&#039;re using Realm database and a REST API, you may have encountered a pagination issue at some point. Let&#039;s build a simple pagination mechanism together\" \/>\n<link rel=\"canonical\" href=\"http:\/\/strawberrycode.com\/blog\/simple-uicollectionview-pagination-with-api-and-realm-database\/\" \/>\n<meta property=\"og:locale\" content=\"en_GB\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"UICollectionView pagination with Realm - StrawberryCode\" \/>\n<meta property=\"og:description\" content=\"If you&#039;re using Realm database and a REST API, you may have encountered a pagination issue at some point. Let&#039;s build a simple pagination mechanism together\" \/>\n<meta property=\"og:url\" content=\"http:\/\/strawberrycode.com\/blog\/simple-uicollectionview-pagination-with-api-and-realm-database\/\" \/>\n<meta property=\"og:site_name\" content=\"StrawberryCode\" \/>\n<meta property=\"article:published_time\" content=\"2015-10-28T01:37:29+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2015-10-28T01:38:36+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/strawberrycode.com\/blog\/wp-content\/uploads\/2015\/04\/Apple_Swift_Logo-e1430073805246.png\" \/>\n\t<meta property=\"og:image:width\" content=\"200\" \/>\n\t<meta property=\"og:image:height\" content=\"200\" \/>\n<meta name=\"twitter:label1\" content=\"Estimated reading time\">\n\t<meta name=\"twitter:data1\" content=\"3 minutes\">\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebSite\",\"@id\":\"https:\/\/strawberrycode.com\/blog\/#website\",\"url\":\"https:\/\/strawberrycode.com\/blog\/\",\"name\":\"StrawberryCode\",\"description\":\"Fruit for Thought\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":\"https:\/\/strawberrycode.com\/blog\/?s={search_term_string}\",\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-GB\"},{\"@type\":\"ImageObject\",\"@id\":\"http:\/\/strawberrycode.com\/blog\/simple-uicollectionview-pagination-with-api-and-realm-database\/#primaryimage\",\"inLanguage\":\"en-GB\",\"url\":\"https:\/\/strawberrycode.com\/blog\/wp-content\/uploads\/2015\/04\/Apple_Swift_Logo-e1430073805246.png\",\"contentUrl\":\"https:\/\/strawberrycode.com\/blog\/wp-content\/uploads\/2015\/04\/Apple_Swift_Logo-e1430073805246.png\",\"width\":200,\"height\":200,\"caption\":\"Apple Swift Logo\"},{\"@type\":\"WebPage\",\"@id\":\"http:\/\/strawberrycode.com\/blog\/simple-uicollectionview-pagination-with-api-and-realm-database\/#webpage\",\"url\":\"http:\/\/strawberrycode.com\/blog\/simple-uicollectionview-pagination-with-api-and-realm-database\/\",\"name\":\"UICollectionView pagination with Realm - StrawberryCode\",\"isPartOf\":{\"@id\":\"https:\/\/strawberrycode.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"http:\/\/strawberrycode.com\/blog\/simple-uicollectionview-pagination-with-api-and-realm-database\/#primaryimage\"},\"datePublished\":\"2015-10-28T01:37:29+00:00\",\"dateModified\":\"2015-10-28T01:38:36+00:00\",\"author\":{\"@id\":\"https:\/\/strawberrycode.com\/blog\/#\/schema\/person\/c328d959959928f47281d7a0ec779e2a\"},\"description\":\"If you're using Realm database and a REST API, you may have encountered a pagination issue at some point. Let's build a simple pagination mechanism together\",\"breadcrumb\":{\"@id\":\"http:\/\/strawberrycode.com\/blog\/simple-uicollectionview-pagination-with-api-and-realm-database\/#breadcrumb\"},\"inLanguage\":\"en-GB\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"http:\/\/strawberrycode.com\/blog\/simple-uicollectionview-pagination-with-api-and-realm-database\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"http:\/\/strawberrycode.com\/blog\/simple-uicollectionview-pagination-with-api-and-realm-database\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"item\":{\"@type\":\"WebPage\",\"@id\":\"https:\/\/strawberrycode.com\/blog\/\",\"url\":\"https:\/\/strawberrycode.com\/blog\/\",\"name\":\"Home\"}},{\"@type\":\"ListItem\",\"position\":2,\"item\":{\"@type\":\"WebPage\",\"@id\":\"http:\/\/strawberrycode.com\/blog\/simple-uicollectionview-pagination-with-api-and-realm-database\/\",\"url\":\"http:\/\/strawberrycode.com\/blog\/simple-uicollectionview-pagination-with-api-and-realm-database\/\",\"name\":\"Simple UICollectionView pagination with API and Realm database\"}}]},{\"@type\":\"Person\",\"@id\":\"https:\/\/strawberrycode.com\/blog\/#\/schema\/person\/c328d959959928f47281d7a0ec779e2a\",\"name\":\"StrawberryCode\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","_links":{"self":[{"href":"https:\/\/strawberrycode.com\/blog\/wp-json\/wp\/v2\/posts\/341"}],"collection":[{"href":"https:\/\/strawberrycode.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/strawberrycode.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/strawberrycode.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/strawberrycode.com\/blog\/wp-json\/wp\/v2\/comments?post=341"}],"version-history":[{"count":11,"href":"https:\/\/strawberrycode.com\/blog\/wp-json\/wp\/v2\/posts\/341\/revisions"}],"predecessor-version":[{"id":352,"href":"https:\/\/strawberrycode.com\/blog\/wp-json\/wp\/v2\/posts\/341\/revisions\/352"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/strawberrycode.com\/blog\/wp-json\/wp\/v2\/media\/183"}],"wp:attachment":[{"href":"https:\/\/strawberrycode.com\/blog\/wp-json\/wp\/v2\/media?parent=341"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/strawberrycode.com\/blog\/wp-json\/wp\/v2\/categories?post=341"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/strawberrycode.com\/blog\/wp-json\/wp\/v2\/tags?post=341"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}