[iOS/Swift 3] Membuat Multi-Section UITableView

Pada tutorial-tutorial sebelumnya kita telah mempelajari berbagai cara penggunaan UITableView, tetapi jika Anda sadari semuanya menggunakan single section UITableView. Pada tutorial kali ini kita akan mempelajari cara menggunakan UITableView yang banyak bagiannya (multi-section), baik dengan data yang statis maupun dinamis. Mari kita mulai tutorial kali ini.

Dengan menggunakan data statis:

1. Buat proyek Xcode baru dengan pilihan template aplikasi "Single View Application" atau Anda bisa juga menggunakan file dari 2 tutorial sebelumnya.

2. Anda dapat menggunakan UITableViewController atau menggunakan UIViewController yang memiliki UITableView. Jika Anda menggunakan opsi yang kedua, jangan lupa reference-kan UITableView tsb pada file ViewController.swift yang Anda gunakan dan tambahkan protokol UITableViewDataSource dan UITableViewDelegate. Kemudian masukan semua fungsi yang dibutuhkan oleh kedua protokol tersebut. Untuk menghilangkan row yang tidak terpakai pada UITableView, beirkan nilai UIView() pada metode tableFooterView.


class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
   
    @IBOutlet weak var tableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()
        self.tableView.tableFooterView = UIView() //menghilangkan row yang tidak terpakai
        tableView.dataSource = self
        tableView.delegate = self
    }
}

3. Buat 2 buah array seperti berikut ini:

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
    let sections = ["section 1", "section 2", "section 3"]
    let items = [["item 1", "item 2", "item 3"], ["item 4", "item 5"], [""item 6""]]
    @IBOutlet weak var tableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()
        self.tableView.tableFooterView = UIView()
        tableView.dataSource = self
        tableView.delegate = self
    }
}

4. Pada fungsi numberOfSections(in tableView: UITableView) kita harus memberikan nilai return sebanyak jumlah isi array sections

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
    let sections = ["section 1", "section 2", "section 3"]
    let items = [["item 1", "item 2", "item 3"], ["item 4", "item 5"], [""item 6""]]
    @IBOutlet weak var tableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()
        self.tableView.tableFooterView = UIView()
        tableView.dataSource = self
        tableView.delegate = self
    }

    func numberOfSections(in tableView: UITableView) -> Int {
        return self.sections.count
    }

...
}

5. Tambahkan fungsi tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) dan berikan nilai return sesuai dengan ini array sections. Fungsi ini belum pernah digunakan pada tutorial-tutorial UITableView dengan single section.

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
    let sections = ["section 1", "section 2", "section 3"]
    let items = [["item 1", "item 2", "item 3"], ["item 4", "item 5"], [""item 6""]]
    @IBOutlet weak var tableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()
        self.tableView.tableFooterView = UIView()
        tableView.dataSource = self
        tableView.delegate = self
    }

    func numberOfSections(in tableView: UITableView) -> Int {
        return self.sections.count
    }

    func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return self.sections[section]
    }
...
}

6. Pada fungsi tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) kita harus memberikan nilai return sebanyak jumlah isi array items.

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
    let sections = ["section 1", "section 2", "section 3"]
    let items = [["item 1", "item 2", "item 3"], ["item 4", "item 5"], [""item 6""]]
    @IBOutlet weak var tableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()
        self.tableView.tableFooterView = UIView()
        tableView.dataSource = self
        tableView.delegate = self
    }

    func numberOfSections(in tableView: UITableView) -> Int {
        return self.sections.count
    }

    func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return self.sections[section]
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.items[section].count
    }
...
}

7. Pada fungsi tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) tuliskan nama cell identifier pada metode dequeueReusableCell(_:) dan berikan nilai textLabel dengan isi dari array items:

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
    let sections = ["section 1", "section 2", "section 3"]
    let items = [["item 1", "item 2", "item 3"], ["item 4", "item 5"], [""item 6""]]
    @IBOutlet weak var tableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()
        self.tableView.tableFooterView = UIView()
        tableView.dataSource = self
        tableView.delegate = self
    }

    func numberOfSections(in tableView: UITableView) -> Int {
        return self.sections.count
    }

    func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return self.sections[section]
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.items[section].count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        
        cell.textLabel?.text = self.items[indexPath.section][indexPath.row]
        cell.textLabel?.sizeToFit()

        return cell
    }
}

8. Jika Anda melakukan semuanya dengan benar maka seharusnya ketika di run tampil seperti berikut ini simulator/device Anda.

Dengan menggunakan data dinamis:

1. Dengan menggunakan file ViewController.swift dengan yang di atas, tambahkan library Alamofire dan Gloss dengan menggunakan Cocoapod.

import Gloss
import Alamofire

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
   ...
}

2. Edit array sections dan items menjadi seperti berikut ini:

import Gloss
import Alamofire

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
    var sections:Array<String> = Array <String>()
    var items = [[String]]()
    ...
}

3. Buat sebuah fungsi yang akan memastikan bahwa data di array sections tidak ada yang terduplikat. Letakkan fungsi tersebut diakhir class.

import Gloss
import Alamofire

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
    ...
    func removeDuplicates(array: [String])->[String] {
        var encountered = Set<String>()
        var result: [String] = []
        for value in array {
            if encountered.contains(value) {
                // Do not add a duplicate element.
            }
            else {
                encountered.insert(value)
                result.append(value)
            }
        }
        return result
    }
}

4. Buat sebuah fungsi yang akan digunakan untuk mengunduh data dari server seperti berikut ini.

import Gloss
import Alamofire

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
    ...

    func get_data_from_url(url:String){
        sections.removeAll(keepingCapacity: false)
        items.removeAll(keepingCapacity: false)
        Alamofire.request(url, method:.get).validate(contentType: ["application/json"]).responseJSON{ response in
            switch response.result{
            case .success(let data):
                guard let value = data as? JSON,
                    let eventsArrayJSON = value["prodlist"] as? [JSON]
                    else { fatalError() }
                let DaftarProduk = [daftarProduk].from(jsonArray: eventsArrayJSON)
                for j in 0 ..< Int((DaftarProduk?.count)!){
                    self.sections.append((DaftarProduk?&#91;j&#93;.prodCat!)!)
                }
                self.sections = self.removeDuplicates(array: self.sections)
                
                for k in 0 ..< self.sections.count{
                    for l in 0 ..< Int((DaftarProduk?.count)!){
                        if !self.items.isEmpty {
                                if (DaftarProduk?&#91;l&#93;.prodCat!)! != self.sections&#91;k&#93;{
                                    self.items.append(&#91;(DaftarProduk?&#91;l&#93;.prodName!)!&#93;)
                                } else {
                                    self.items&#91;k&#93;.append((DaftarProduk?&#91;l&#93;.prodName!)!)
                                }
                        } else {
                            self.items.append(&#91;(DaftarProduk?&#91;l&#93;.prodName!)!&#93;)
                        }
                        
                    }
                }
                
                DispatchQueue.main.async(execute: {
                    self.tableView.reloadData()
                })
                break
            case .failure(let error):
                print("Error: (error)")
                let alert2 = UIAlertController (title: "Error", message: error.localizedDescription, preferredStyle: UIAlertControllerStyle.alert)
                alert2.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default,handler: nil))
                self.present(alert2, animated: true, completion: nil)
                break
            }
        }
    }

    func removeDuplicates(array: &#91;String&#93;)->[String] {
        var encountered = Set<String>()
        var result: [String] = []
        for value in array {
            if encountered.contains(value) {
                // Do not add a duplicate element.
            }
            else {
                encountered.insert(value)
                result.append(value)
            }
        }
        return result
    }
}

5. Agar dapat menggunakan cara untuk mendeserialisasi JSON ala GLoss seperti pada fungsi get_data_from_url(_:) dengan baik, Anda perlu untuk membuat decodable struct untuk memodelkan data yang diunduh dari server.

import Gloss
import Alamofire

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
    struct daftarProduk: Decodable{
        let prodID: Int?
        let prodName: String?
        let prodCat: String?
        
        init?(json: JSON){
            self.prodID = "id" <~~ json
            self.prodName = "name" <~~ json
            self.prodCat = "category" <~~ json
        }
    }

    ...

    func get_data_from_url(url:String){
        sections.removeAll(keepingCapacity: false)
        items.removeAll(keepingCapacity: false)
        Alamofire.request(url, method:.get).validate(contentType: &#91;"application/json"&#93;).responseJSON{ response in
            switch response.result{
            case .success(let data):
                guard let value = data as? JSON,
                    let eventsArrayJSON = value&#91;"prodlist"&#93; as? &#91;JSON&#93;
                    else { fatalError() }
                let DaftarProduk = &#91;daftarProduk&#93;.from(jsonArray: eventsArrayJSON)
                for j in 0 ..< Int((DaftarProduk?.count)!){
                    self.sections.append((DaftarProduk?&#91;j&#93;.prodCat!)!)
                }
                self.sections = self.removeDuplicates(array: self.sections)
                
                for k in 0 ..< self.sections.count{
                    for l in 0 ..< Int((DaftarProduk?.count)!){
                        if !self.items.isEmpty {
                                if (DaftarProduk?&#91;l&#93;.prodCat!)! != self.sections&#91;k&#93;{
                                    self.items.append(&#91;(DaftarProduk?&#91;l&#93;.prodName!)!&#93;)
                                } else {
                                    self.items&#91;k&#93;.append((DaftarProduk?&#91;l&#93;.prodName!)!)
                                }
                        } else {
                            self.items.append(&#91;(DaftarProduk?&#91;l&#93;.prodName!)!&#93;)
                        }
                        
                    }
                }
                
                DispatchQueue.main.async(execute: {
                    self.tableView.reloadData()
                })
                break
            case .failure(let error):
                print("Error: (error)")
                let alert2 = UIAlertController (title: "Error", message: error.localizedDescription, preferredStyle: UIAlertControllerStyle.alert)
                alert2.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default,handler: nil))
                self.present(alert2, animated: true, completion: nil)
                break
            }
        }
    }

    func removeDuplicates(array: &#91;String&#93;)->[String] {
        var encountered = Set<String>()
        var result: [String] = []
        for value in array {
            if encountered.contains(value) {
                // Do not add a duplicate element.
            }
            else {
                encountered.insert(value)
                result.append(value)
            }
        }
        return result
    }
}

6. Panggil fungsi get_data_from_url(_:) dari fungsi viewDidAppear(_:).

import Gloss
import Alamofire

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
    struct daftarProduk: Decodable{
        let prodID: Int?
        let prodName: String?
        let prodCat: String?
        
        init?(json: JSON){
            self.prodID = "id" <~~ json
            self.prodName = "name" <~~ json
            self.prodCat = "category" <~~ json
        }
    }

    ...

    override func viewDidAppear(_ animated: Bool) {
        get_data_from_url("https://imperio.co.id/project/ecommerceApp/allproducts.php")
    }
 
    ...

    func get_data_from_url(url:String){
        sections.removeAll(keepingCapacity: false)
        items.removeAll(keepingCapacity: false)
        Alamofire.request(url, method:.get).validate(contentType: &#91;"application/json"&#93;).responseJSON{ response in
            switch response.result{
            case .success(let data):
                guard let value = data as? JSON,
                    let eventsArrayJSON = value&#91;"prodlist"&#93; as? &#91;JSON&#93;
                    else { fatalError() }
                let DaftarProduk = &#91;daftarProduk&#93;.from(jsonArray: eventsArrayJSON)
                for j in 0 ..< Int((DaftarProduk?.count)!){
                    self.sections.append((DaftarProduk?&#91;j&#93;.prodCat!)!)
                }
                self.sections = self.removeDuplicates(array: self.sections)
                
                for k in 0 ..< self.sections.count{
                    for l in 0 ..< Int((DaftarProduk?.count)!){
                        if !self.items.isEmpty {
                                if (DaftarProduk?&#91;l&#93;.prodCat!)! != self.sections&#91;k&#93;{
                                    self.items.append(&#91;(DaftarProduk?&#91;l&#93;.prodName!)!&#93;)
                                } else {
                                    self.items&#91;k&#93;.append((DaftarProduk?&#91;l&#93;.prodName!)!)
                                }
                        } else {
                            self.items.append(&#91;(DaftarProduk?&#91;l&#93;.prodName!)!&#93;)
                        }
                        
                    }
                }
                
                DispatchQueue.main.async(execute: {
                    self.tableView.reloadData()
                })
                break
            case .failure(let error):
                print("Error: (error)")
                let alert2 = UIAlertController (title: "Error", message: error.localizedDescription, preferredStyle: UIAlertControllerStyle.alert)
                alert2.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default,handler: nil))
                self.present(alert2, animated: true, completion: nil)
                break
            }
        }
    }

    func removeDuplicates(array: &#91;String&#93;)->[String] {
        var encountered = Set<String>()
        var result: [String] = []
        for value in array {
            if encountered.contains(value) {
                // Do not add a duplicate element.
            }
            else {
                encountered.insert(value)
                result.append(value)
            }
        }
        return result
    }
}

7. Jika Anda melakukan semuanya dengan benar maka seharusnya ketika di run tampil seperti berikut ini simulator/device Anda. Data yang digunakan untuk tutorial dengan menggunakan data dinamis ini hanya data dummy.

Berikut ini adalah kodingan lengkap untuk menggunakan multi-section UITableView dengan data yang dinamis.

import UIKit
import Gloss
import Alamofire

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
    struct daftarProduk: Decodable{
        let prodID: Int?
        let prodName: String?
        let prodCat: String?
        
        init?(json: JSON){
            self.prodID = "id" <~~ json
            self.prodName = "name" <~~ json
            self.prodCat = "category" <~~ json
        }
    }

    var sections:Array<String> = Array <String>()
    var items = [[String]]()

    @IBOutlet weak var tableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()
        self.tableView.tableFooterView = UIView()
        tableView.dataSource = self
        tableView.delegate = self
    }

    override func viewDidAppear(_ animated: Bool) {
        get_data_from_url("https://imperio.co.id/project/ecommerceApp/allproducts.php")
    }
 
    func numberOfSections(in tableView: UITableView) -> Int {
        return self.sections.count
    }

    func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return self.sections[section]
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.items[section].count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        
        cell.textLabel?.text = self.items[indexPath.section][indexPath.row]
        cell.textLabel?.sizeToFit()

        return cell
    }

    func get_data_from_url(url:String){
        sections.removeAll(keepingCapacity: false)
        items.removeAll(keepingCapacity: false)
        Alamofire.request(url, method:.get).validate(contentType: ["application/json"]).responseJSON{ response in
            switch response.result{
            case .success(let data):
                guard let value = data as? JSON,
                    let eventsArrayJSON = value["prodlist"] as? [JSON]
                    else { fatalError() }
                let DaftarProduk = [daftarProduk].from(jsonArray: eventsArrayJSON)
                for j in 0 ..< Int((DaftarProduk?.count)!){
                    self.sections.append((DaftarProduk?&#91;j&#93;.prodCat!)!)
                }
                self.sections = self.removeDuplicates(array: self.sections)
                
                for k in 0 ..< self.sections.count{
                    for l in 0 ..< Int((DaftarProduk?.count)!){
                        if !self.items.isEmpty {
                                if (DaftarProduk?&#91;l&#93;.prodCat!)! != self.sections&#91;k&#93;{
                                    self.items.append(&#91;(DaftarProduk?&#91;l&#93;.prodName!)!&#93;)
                                } else {
                                    self.items&#91;k&#93;.append((DaftarProduk?&#91;l&#93;.prodName!)!)
                                }
                        } else {
                            self.items.append(&#91;(DaftarProduk?&#91;l&#93;.prodName!)!&#93;)
                        }
                        
                    }
                }
                
                DispatchQueue.main.async(execute: {
                    self.tableView.reloadData()
                })
                break
            case .failure(let error):
                print("Error: (error)")
                let alert2 = UIAlertController (title: "Error", message: error.localizedDescription, preferredStyle: UIAlertControllerStyle.alert)
                alert2.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default,handler: nil))
                self.present(alert2, animated: true, completion: nil)
                break
            }
        }
    }

    func removeDuplicates(array: &#91;String&#93;)->[String] {
        var encountered = Set<String>()
        var result: [String] = []
        for value in array {
            if encountered.contains(value) {
                // Do not add a duplicate element.
            }
            else {
                encountered.insert(value)
                result.append(value)
            }
        }
        return result
    }
}

Tingkat kesulitan: Pemula

Share this post to the world:
Facebooktwittergoogle_pluspinterestlinkedinFacebooktwittergoogle_pluspinterestlinkedin

Leave a Reply

Your email address will not be published. Required fields are marked *