Latest 1.9.2
Homepage https://github.com/EMart86/SwiftDataProvider
License MIT
Platforms ios 8.0
Authors

CI Status
Version
License
Platform

SwiftDataProvider
SwiftDataProvider

Example

Boilerplate code for TableViews and animated updates is history. Design your TableView with your Models instead of keeping track of all the IndexPaths and IndexSets, nice and easy.

To run the example project, clone the repo, and run pod install from the Example directory first.

Requirements

iOS 8.0
XCode 10
Swift 4.1

Installation

SwiftDataProvider is available through CocoaPods. To install
it, simply add the following line to your Podfile:

pod 'SwiftDataProvider'

Author

Martin Eberl, [email protected]

License

SwiftDataProvider is available under the MIT license. See the LICENSE file for more info.

Usage

1) Implement UITableViewController or UITableView with the RecyclerView protocol

2) Hold a strong reference to the SwiftDataProvider

    private var swiftDataProvider: SwiftDataProvider?

3) Create a SwiftDataProvider instance eg in viewDidLoad and assign it as TableViewDataSource to the TableView

override func viewDidLoad() {
    super.viewDidLoad()

    //do assign to the tableviews delegate ALWAY BEFORE creating and assigning
    //the SwiftDataProvider to the UITableView or UITableViewController, otherwhise
    //the section header and footer view won't appear, when you handle them within the SwiftDataProvider
    self.tableViewDelegate = self 

    self.swiftDataProvider = SwiftDataProvider(recyclerView: self)

    //step 4
}

4) Register cells for reusing and mapping to the content it requires, eg below the initialization of the SwiftDataProvider. Use unique names for your data models!

    swiftDataProvider?.register(cell: UITableViewCell.self, for: String.self) { cell, content in
        cell.textLabel?.text = content
    }

    swiftDataProvider?.register(cell: UITableViewCell.self, for: /*Your data model*/.self) { cell, content in
        cell.textLabel?.text = content.formattedDate
    }

    swiftDataProvider?.register(cellReuseIdentifier: "TestCell", as: TestCell.self, for: TestCell.Content.self) { cell, content in
        cell.content = content
    }

//step 5

5) Assign a content adapter. The example uses the MVVM pattern but you can also implement the ContentAdapter in the ViewController.

    swiftDataProvider?.contentAdapter = viewModel.contentAdapter

6) a) Use a ContentProviderAdapter for self-controlled content and add sections and rows or update the section header and footer:

// in the ViewModel

struct ViewModel {
    let contentAdapter = ContentProviderAdapter()
    let section = Section()
    ...

    init() {
        //Use a string or a model, the string uses the default header view, the
        //model requires you to provide a section header view
        section.set(header: "") 
        contentAdapter.add(section: section)

        //use automatically update if you'd like the table view 
        //to be updated every time, something is being inserted, deleted or triggered a reload.
        //Default is false, so you can do multiple updates at a time
        //contentAdapter.isAutoCommitEnabled = true
    }

    func addContent() {
        section.add(row: /*Your data model*/)
        // .. insert, remove models, cells ..

        //find a specific instance of a model in the section
        let content: <Model Type> = section.content {
            //return true or false
        }

        //if you didn't enable the autocommit, you'll have to trigger the update manually
        contentAdapter.commit()
    }

    func uödate
}

6) b) or use a DynamicContentProviderAdapter for automatic-controlled content:

// in the ViewModel

struct ViewModel {
    let contentAdapter = DynamicContentProviderAdapter</*Your data model*/>()

    ...

    init() {
        contentAdapter.sort = { $0 < $1 }
        contentAdapter.sectionContentUpdate = { section in
            //Update sectin content whenever a new row has been added
            //use string to show the default section header view or a model, to use a custom view
            section.set(header: "(section.rows.count) Items")

            //action to be used after a section update has performed (.none or .reload)
            return .reload 
        }

        //use automatically update if you'd like the table view 
        //to be updated every time, something is being inserted, deleted or triggered a reload.
        //Default is false, so you can do multiple updates at a time
        //contentAdapter.isAutoCommitEnabled = true

        contentAdapter.sectionInitializer = { section in
            //Initialize sectin content the first time, a new Section has been created
            //use string to show the default section header view or a model, to use a custom view
            section.set(header: "(section.rows.count) Items")
        }

        contentAdapter.contentSectionizer = { content, sections in
            //Sectionize the content
            //return .new or .use(index of the section) to create a new section or use the given section
            guard let last = sections?.last else {
                return .new
            }

            //Here i'm filtering the row
            //if the model to be added into a section is "older" than a minute, a new section will be created, otherwhise use the latest section
            let rows = last.rows.compactMap { $0 as? TimeModel }
            if let timeInterval = rows.first?.date.timeIntervalSince(content.date), timeInterval < -60 {
                return .new
            }
            return .use((sections?.count ?? 1) - 1)
        }
    }

    func addContent() {
        contentAdapter.add(/*Your data model*/)

        //if you didn't enable the autocommit, you'll have to trigger the update manually
        contentAdapter.commit()
    }
}

What is the difference between the ContentProviderAdapter and the DynamicContentProviderAdapter?

The ContentProviderAdapter is a class in which you can controll the sections and the rows within the sections. This is mainly used when you know, how the content structure should look like. So you add several sections and rows to the sections.

The DynamicContentProviderAdapter is a class in which you only provide content and based on a provided logic, the content is ordered into the section. However since the DynamicContentProviderAdapter is derived from ContentProviderAdapter, you can also provide custom sections.

Latest podspec

{
    "name": "SwiftDataProvider",
    "version": "1.9.2",
    "summary": "Reduce boilerplate code for UITableView and UITableViewController's data source",
    "description": "Handling TableViews and animated updates is now easer than you think. Design your TableView with your Models instead of keeping track of all the IndexPaths and IndexSets.",
    "homepage": "https://github.com/EMart86/SwiftDataProvider",
    "license": {
        "type": "MIT",
        "file": "LICENSE"
    },
    "authors": {
        "Martin Eberl": "[email protected]"
    },
    "source": {
        "git": "https://github.com/EMart86/SwiftDataProvider.git",
        "tag": "1.9.2"
    },
    "platforms": {
        "ios": "8.0"
    },
    "swift_version": "4.2",
    "source_files": "SwiftDataProvider/Classes/**/*"
}

Pin It on Pinterest

Share This