“ , also known as paging, is the process of dividing a document into discrete pages, either electronic pages or printed pages.” Pagination It is most common technique to manage large data set at server/client side to distribute in chunks called as pages. In today’s time, Social media client apps improvised this by inventing “Infinite scroll”. Infinite scrolling allows users to load content continuously, eliminating the need for user’s explicit actions. App loads some initial data and then load the rest of the data when the user reaches the bottom of the visible content. This data is divided in pages. A framework for Infinite scrolling? As apps size and content, are increasing day by day, we need to implement infinite scroll in more than one places in our app. Although implementing infinite scroll is not very tricky but it is a repetitive job and create redundant code inside TableView/CollectionView and yes it breaks the “DRY” principal too. Whenever we have repeated code, there is always a chance of introducing a bug. I lately implemented infinite scroll in some of apps and I felt that at times you need to implement this in quite a few places, typically if you are working on a large e-commerce app. I was looking for a solution, a framework which does this job for me. I was not able to find a non-intrusive and easy to integrate solution where I don’t need to sub-class my ViewController or use a special kind of tableView/collectionView for this and It can work with my network stack. In short, I don’t want to create direct dependency of a framework/library all over in my project code. So I thought of giving it a try. Initial, I was not clear on and part. My refactored efforts were scattered all over the place. While I ended up having a non-intrusive solution (what I played out as a requirement), I learned an important lesson after making mistakes. what how Zoom out as far as you can until you are clear who is playing what role. Initially I was relentlessly trying to decouple/refactored code without identifying my interface and participant objects or classes. You can only do “ ” when you identify class is going to do . Separation of Concern which what What it takes to use your framework/Library When I started refactoring my code for library, I had not laid out my interfaces well. Generally this is a common problem. We usually don’t developed solutions which are being designed for larger audience but used within few use cases. It really open our eyes when we start thinking in this direction. And yes, this should be second step when we develop a framework. What part: 1. We need an Inter-actor/ Controller which Maintains number of visible rows Load next page at the end of scroll if required Maintain current page count and update all of these when it gets next page data array from the network. 2. To accomplish all of this, It needs some supporting function on top of tableView/collectionView 3. An interface between network stack. How Part: The trickiest part was the interfacing with network. It took some time to figure out how to separate it from the dependency of network stack. Most of pagination responses have the common structure which comprises of total Page count, current page and an array of elements. With this assumption, A can be defined for all responses over generic parameter Type. struct { types: [ ] page: totalPageCount: (types: [ ], page: , totalPageCount: ) { .types = types .page = page .totalPageCount = totalPageCount } } public < > struct PageInfo T var T var Int var Int public init T Int Int self self self Now with this PageInfo struct in place, We have a generic way of giving data back to Inter-actor/Controller for updating the results after getting it from web service. This solves one problem of puzzle, another piece of puzzle is to indicate Network stack to download next pages data as and when required. So I designed an interface between Pageable and network stack which has two methods. { -> } public : protocol PageableService class /// Indicates when to load next page func load (pageInteractor: PageInteractor, page: Int) Void /// Cancel request if required func cancelAllRequests () Function is called by when it figure out that there is more data to load. A typical implementation can be LoadPage PageInteractor -> { resource: < <[ ]>> = ? prepareResource(page: page, pageSize: pageSize, pathForREST: ) { } info: < >? networkManager.fetch(res: resource) { (res) res { .success(result): info = (types: result.types, page: result.page, totalPageCount: result.totalPageCount) .failure(err): (err) } pgInteractor.returnedResponse(info) } } func load (pageInteractor: PageInteractor, page: Int) Void guard let Resourse PagedResponse User try "/api/users" else return // Construct PageInfo to be returned var PageInfo User in switch case let PageInfo case let print // Require to call method on PageInteractor for updating result. First method indicates to request page. As It loads next set of data, the loaded data needs to be sent to PageInteractor for updating result. func loadPage( _ page: Int) -> Void when which Now calling , is a requirement which can be missed as API is not enforcing it. PageInteractor Completion blocks are here! Completion block helps in situations like this. So we can update an interface with completion block. As operates on generic parameter, This requires to create a generic interface to adopt by. PageInfo<T> { -> ) } public : protocol PageableService class <Item: Decodable> func loadPage ( page: Int, completion: @escaping _ (PageInfo<Item>?) Void func cancelAllRequests () This create a clear requirement for user to send data back to Page Interactor as well as gives a clean way to separate library from your networking code. Pageable Power of KeyPath: gives a feature where duplicate entries from server can be avoided at client side if somehow new entries are being added dynamically at server end. More can be found . Pageable here To use this feature your pagination data should have a unique Id in response array so that duplicates can be identified. To make this feature usable, It requires a user to give a power to provide a generic way to identify that field. Earlier due to inability to provide this information to , User needs to implement interface methods which checks items in dictionary and then add in final array to avoid duplication. This is very redundant task for user and ideally handled by only. PageInteractor PageDataSource PageInteractor { -> < > { startIndex = pgInteractor. () items = items ? [ ] { new items { pgInteractor.dict[ (new.id)] == { pgInteractor.dict[ (new.id)] = (new.id) pgInteractor.array.append(new) } } } startIndex..<pgInteractor. () } { items = items ? [ ] { pgInteractor.array = items new items { pgInteractor.dict[ (new.id)] = (new.id) } } } } : extension UserView PageDataSource func addUniqueItems ( items: [AnyObject]) for Range Int let count if let as User for in if String nil String String // adding items in array to be displayed return count func addAll (items: [AnyObject]) if let as User for in String String KeyPath are a way to reference properties without invoking them. It can be composed to make different path and used to get/set underlying properties. With the KeyPath passed in the initialiser of , implementation of both methods can move entirely in . This will relive user from not implementing . PageInteractor PageInteractor PageDataSource { -> < > { startIndex = () keypath = keypath { new items { key = new[keyPath: keypath] dict[key] == { dict[key] = key array.append(new) } } } startIndex..< () } { array = items keypath = keypath { } new items { key = new[keyPath: keypath] dict[key] = key } } } extension PageInteractor /** Server can add/remove items dynamically so it might be a case that an item which appears in previous request can come again due to certain element below got removed. This could result as duplicate items appearing in the list. To mitigate it, we would be creating a parallel dictionary which can be checked for duplicate items - Parameter items: items to be added - Parameter keypath: In case if duplicate entries has to be filter out, It requires keypath of unique items in model data. */ open func addUniqueFrom (items: [Element], keypath: KeyPath<Element, KeyType>?) Range Int let count if let for in let if nil return count /** Add all items, If there is empty list in table view - Parameter items: items to be added - Parameter keypath: In case if duplicate entries has to be filter out, It requires keypath of unique items in model data. */ open func addAll (items: [Element], keypath: KeyPath<Element, KeyType>?) guard let else return for in let With default implementation embedded in , All it takes is to provide KeyPath of unique data type to to use this feature. PageInteractor PageInteractor pageInteractor: < , > = (firstPage: firstReqIndex, service: service, keyPath: \UserModel.id) let PageInteractor UserModel Int PageInteractor Conclusion While developing infinite scrolling as a framework, was fun and turned out to be an easy solution to integrate with few steps to follow. I learned an important lesson on part. There is always a room of improvement when you look back to your solution. I did a few iterations while finalising interface for Pageable and now I feel next time I can avoid few of those. what You can find library at Github, feel free to give it a try/feedback ! here