I’ve been trying to solve this for a couple of days now. Whenever I add a new contact and load it from Realm, a new section is created with the same header. Every section has only one row and cannot accommodate more. I’m trying to accomplish functionality like the contacts app on the phone. I want every section to hold as many names (rows) as possible with unique names.
Here’s my code:
class ArtistNamesViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var contacts: [Contact] = []
var contactsArray = [[Contact]]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(didTapAdd))
loadArtists()
}
func setupContacts() {
let groupedContacts = Dictionary(grouping: contacts) { (contact) -> Character in
return contact.name.first!
}
let keys = groupedContacts.keys.sorted()
keys.forEach { (key) in
contactsArray.append(groupedContacts[key]!)
}
}
}
//MARK: - Realm Methods
func uploadContacts(contactName: String, contactNumber: String) {
let contact = ContactRealm()
contact.artistName = contactName
contact.artistPhoneNumber = contactNumber
let realm = try! Realm()
try! realm.write {
realm.add(contact)
}
}
func loadArtists(){
let contactsRealm = realm.objects(ContactRealm.self)
for contact in contactsRealm {
if let name = contact.artistName,
let number = contact.artistPhoneNumber {
self.contactsArray.append([Contact(name: name, number: number)])
}
}
self.tableView.reloadData()
}
//MARK: - TableView Methods
func numberOfSections(in tableView: UITableView) -> Int {
return contactsArray.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return contactsArray[section].count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ArtistNamesCell", for: indexPath) as! ContactsTableViewCell
cell.configureName(with: contactsArray[indexPath.section][indexPath.row].name)
cell.configureNumber(with: contactsArray[indexPath.section][indexPath.row].number)
return cell
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
let title = String(contactsArray[section].first?.name.prefix(1) ?? "")
return title
}
//MARK: - Segue
@IBAction func goToContacts(segue: UIStoryboardSegue) {
guard let viewController = segue.source as? AddArtistViewController else { return }
guard let name = viewController.name.text,
let phoneNumber = viewController.phoneNumber.text else {
return
}
contactsArray = []
let contact = Contact(name: name, number: phoneNumber)
contacts.append(contact)
uploadContacts(contactName: name, contactNumber: phoneNumber)
setupContacts()
tableView.reloadData()
}
}
ContactRealm Class
class ContactRealm: Object {
@objc dynamic var artistName: String?
@objc dynamic var artistPhoneNumber: String?
}
Contact Class
import Foundation
struct Contact {
let name: String
let number: String
}
Thank you in advance.
2
Answers
It was solved using this extension:
And adding...
contactArray = contacts.group(by: { $0.name.first ?? "-" }, sortOrder: .descending)
toloadArtists()
Also,
setupContacts()
has been changed to:Because you are returning multiple sections in
Solution 1: // Bit Complex
setArray.append(String(contactsArray[section].first?.name.prefix(1) ?? ""))
return this
setArray.count
in numberOfSections.in numberOfRowsInSection filter out array with items and return which are present with Alphabet. e.g
let rowsCount = contactArray.filter({$0.name. prefix(1) == setArray[section] })
return row which belongs this group in cellForRowAt.
let contact = contactArray.filter({$0.name. prefix(1) == setArray[indexpath.section]})[indexpath.row] as? Contact
Solution 2:
Create Unique dictionary that maintains Alphabet and contact objects.
e.g
let contactDict = [ 'A': [Contact(name: name, number: number), Contact(name: name, number: number)]], 'B': [Contact(name: name, number: number), Contact(name: name, number: number)]]
// This list you can update dynamically once you received contact from database.return this
Array(contactDict.keys).count
in numberOfSections.in numberOfRowsInSection return
let rowsCount = contactsDict[Array(contactsDict.keys).sorted()[section]].count
return row which belongs this group in cellForRowAt.
let contact = contactsDict[Array(contactsDict.keys).sorted()[section]][indexpath.row]