Use Realm Query Results as UITableView Section Headers - ios

I am trying to use results from a Realm query as section headers in a UITableView.
Realm classes:
class Person: Object {
#objc dynamic var personId = UUID().uuidString
#objc dynamic var firstName: String = ""
#objc dynamic var surname: String = ""
#objc dynamic var mobileNumber: Int = 0
#objc dynamic var password: String = ""
override static func primaryKey() -> String? {
return "personId"
}
}
class Category: Object {
#objc dynamic var categoryId = UUID().uuidString
#objc dynamic var person: Person?
#objc dynamic var categoryName: String = ""
let categoryContent = List<String>()
override static func primaryKey() -> String? {
return "categoryId"
}
}
My code:
class HomeController: UIViewController, UITableViewDelegate, UITableViewDataSource {
let realm = try! Realm()
var itemsInSections: Array<Array<String>> = [["1A"], ["2A"], ["3A"], ["4A"], ["5A"], ["6A"], ["7A"], ["8A"], ["9A"], ["10A"]] //Test content to figure out later
#IBOutlet weak var tableDetails: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableDetails.dataSource = self
tableDetails.delegate = self
}
func numberOfSections(in tableView: UITableView) -> Int {
return getCategoryNames().count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return itemsInSections[section].count
}
private func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> [String] {
return getCategoryNames()
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "HomeTableViewCell", for: indexPath)
let text = self.itemsInSections[indexPath.section][indexPath.row]
cell.textLabel!.text = text
return cell
}
func getCategoryNames() -> [String] {
let categoryNames = realm.objects(Category.self).filter("person.mobileNumber == %#", mobileNumber).map({$0.categoryName})
return Array(categoryNames)
}
}
The number of sections works perfectly, but the section headers are blank.
If I add:
print(Array(categoryNames))
to the getCategoryNames function, it returns ["Category 1", "Category 2", "Category 3", "Category 4"] several times. This seems to be the correct format for the string that is required for the section headers, but the table header is not showing.

Try this:
private func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
let nameArr = getCategoryNames()
return nameArr[section]
}
Function: func tableView(_ tableView: UITableView,
titleForHeaderInSection section: Int) -> String? so you need to return string for a particular section.

Related

How to get the name list on Realm database and display on my stimulator?

Here I have a Realm Database which is have some data in it and I want to display it on my Stimulator but it turn out display some other thing. What's wrong in my code?
This is the data of my Realm Database and I also marked the data which I want to display it.
The stimulator which display something like this.
And here is my ViewController.swift code's.
import UIKit
import RealmSwift
class ViewController: UIViewController,UITableViewDataSource { //UITableViewDataSource
#IBOutlet weak var mytableview: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let realm = try! Realm()
let theItem = realm.objects(Item.self).filter("itemid >= 1")
return theItem.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let realm = try! Realm()
let theItem = realm.objects(Item.self).filter("itemid >= 1")
print(theItem)
let cell = tableView.dequeueReusableCell(withIdentifier: "cell1")
//I suspect the problem is at here...
cell?.textLabel?.text = "\(theItem)"
return cell!
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
}
class Category: Object {
#objc dynamic var name: String?
#objc dynamic var caid: Int = 0
}
class Item: Object {
#objc dynamic var name: String?
#objc dynamic var itemid: Int = 0
#objc dynamic var cateid: Int = 0
}
Your problem is that you need to get the string from the Item object. try something like
"\(theItem.name)".
func getNames() -> [String]{
let items = realm.objects(Item.self).filter("itemid >= 1").toArray(ofType: Item.self ) as [Item]
return items.map { $0.name }
}
extension Results {
func toArray<T>(ofType: T.Type) -> [T] {
var array = [T]()
for i in 0 ..< count {
if let result = self[i] as? T {
array.append(result)
}
}
return array
}
}
I found a way to display the data already. I just need to add indexPath.row in my code and it can handle the data already.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let realm = try! Realm()
let theItem = realm.objects(Item.self).filter("itemid >= 1")
//I only add below this indexpath
let cellData = theItem[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "cell1")
//and change this part and it's done.
cell?.textLabel?.text = cellData.name
print(theItem)
return cell!
}

Outputting element from two-dimensional array from separate class

I need to output the second element from a two-dimensional array from one class to a TableViewController. I've tried a couple things, such as data.reduce into:, with no luck. The FirstViewController is supposed to be populated with the three genres "Action, Suspense and Romance", which can then be clicked on to show all the movies that belong to that genre.
First Class:
import Foundation
protocol MovieModelDelegate: class {
func didRecieveDataUpdate(data: [[String]])
}
class MovieModel {
weak var delegate: MovieModelDelegate?
var genreArray: [String] = []
let data: [[String]] = [
["Avatar", "Action"],
["Limitless", "Suspense"],
["Die Hard", "Action"],
["The Avengers", "Action"],
["The Notebook", "Romance"],
["Lakehouse", "Romance"],
["Gone Girl", "Suspense"],
["Deadpool", "Action"],
["Passengers", "Suspense"],
["Inception", "Suspense"],
["Mission Impossible", "Action"]
]
func requestData() {
let movie: [[String]] = data
delegate?.didRecieveDataUpdate(data: movie)
}
}
**TableView Class:**
class FirstTableView: UITableViewController, MovieModelDelegate {
var model = MovieModel()
var selectedGenre: String = ""
override func viewDidLoad() {
super.viewDidLoad()
model.delegate = self
model.requestData()
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return model.genreArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "GenreCells", for: indexPath) as! TableViewCell
cell.genreLabel?.text = model.genreArray[indexPath.item]
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectedGenre = model.data[indexPath.row]
selectedGenre = ""
for indexPath in model.data{
if indexPath[1] == selectedGenre{
selectedGenre.append(indexPath[0])
}
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "pushToMovies") {
if let VC = segue.destination as? FilteredSelection {
VC.selectedMovies = [selectedGenre]
}
}
}
func didRecieveDataUpdate(data: [[String]]) {
}
deinit{
}
}
You need to change the data into a form that can then be indexed by a tableview. I would change it into a dictionary using the following code.
let genreDictionary = data.reduce(into: [:]) { d, element in
d[element[1], default: []].append(element[0])
}
This will create the following Dictionary
["Suspense": ["Limitless", "Gone Girl", "Passengers", "Inception"],
"Romance": ["The Notebook", "Lakehouse"],
"Action": ["Avatar", "Die Hard", "The Avengers", "Deadpool", "Mission Impossible"]]
Then in your tableview functions you use the dictionary as follows
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return model.genreDictionary.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "GenreCells", for: indexPath) as! TableViewCell
let d = model.genreDictionary
cell.genreLabel?.text = d[d.keys.index(d.startIndex, offsetBy: indexPath.row)].key
return cell
}
When you need the array of films for a certain tableview row you can use the following
let d = model.genreDictionary
let arrayOfFilms = d[d.keys.index(d.startIndex, offsetBy: indexPath.row)].value
You can use a Set to get all Genres without to have duplicates.
I recognized you want to display the genres in your TableView with model.genreArray but your genreArray is always empty because you never append data to it.
The second thing I recoginzed: In your TableViewController you
implemented the didReciveDataUpdate function, but you didnt do
anything with it.
First Class:
import Foundation
protocol MovieModelDelegate: class {
func didRecieveDataUpdate(data: [[String]])
}
class MovieModel {
weak var delegate: MovieModelDelegate?
let data: [[String]] = [
["Avatar", "Action"],
["Limitless", "Suspense"],
["Die Hard", "Action"],
["The Avengers", "Action"],
["The Notebook", "Romance"],
["Lakehouse", "Romance"],
["Gone Girl", "Suspense"],
["Deadpool", "Action"],
["Passengers", "Suspense"],
["Inception", "Suspense"],
["Mission Impossible", "Action"]
]
private var genres = [String]()
public init() {
for dataSet in data {
self.genres.append(dataSet[1])
}
//this will generate a array with only uniqe genres
var genreArray = Array(Set(self.genres))
}
func requestData() {
let movie: [[String]] = data
delegate?.didRecieveDataUpdate(data: movie)
}
}
FirstTableView Class:
(view didReciveDataUpdate function)
class FirstTableView: UITableViewController, MovieModelDelegate {
var model = MovieModel()
var selectedGenre: String = ""
override func viewDidLoad() {
super.viewDidLoad()
model.delegate = self
model.requestData()
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return model.genreArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "GenreCells", for: indexPath) as! TableViewCell
cell.genreLabel?.text = model.genreArray[indexPath.row]
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
//To get the Genre
selectedGenre = model.data[indexPath.row][1]
for indexPath in model.data{
if indexPath[1] == selectedGenre{
selectedGenre.append(indexPath[0])
}
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "pushToMovies") {
if let VC = segue.destination as? FilteredSelection {
VC.selectedMovies = [selectedGenre]
}
}
}
func didRecieveDataUpdate(data: [[String]]) {
//=================here you need to update your tableView===================
}
deinit{
}
}

Firebase import array data to tableview

I have tableview in VC and I would like to import "Detail" item form current recipe:
Firebase entries
to tableView - each to a separate cell.
My Code in RecipiesModel:
class RecipiesModel {
var title: String?
var desc: String?
var detail: Array<Any>?
init(title: String?, desc: String?, detail: Array<Any>?){
self.title = title
self.desc = desc
self.detail = detail
}
}
My Code in VC:
import UIKit
import FirebaseDatabase
class DescriptionViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var textInput: String = ""
var descInput: String = ""
var ref:DatabaseReference!
var recipiesList = [RecipiesModel]()
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var titleLabelDesc: UILabel!
#IBOutlet weak var descriptionLabelDesc: UILabel!
#IBOutlet weak var imageView: UIImageView!
#IBOutlet weak var tabBarView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
UIApplication.shared.statusBarStyle = .lightContent
tableView.delegate = self
tableView.dataSource = self
customUIView()
titleLabelDesc.text = textInput
descriptionLabelDesc.text = descInput
loadList()
}
//Database
func loadList() {
ref = Database.database().reference()
ref.child("Recipies").observe(.childAdded, with: { (snapshot) in
let results = snapshot.value as? [String : AnyObject]
let title = results?["Recipies title"]
let desc = results?["Recipies description"]
let detail = results?["Detail"]
let myRecipies = RecipiesModel(title: title as! String?, desc: desc as! String?, detail: detail as! Array<Any>?)
self.recipiesList.append(myRecipies)
DispatchQueue.main.async {
self.tableView.reloadData()
}
})
}
func customUIView() {
tabBarView.layer.shadowColor = UIColor.lightGray.cgColor
tabBarView.layer.shadowOpacity = 1
tabBarView.layer.shadowOffset = CGSize.zero
tabBarView.layer.shadowRadius = 3
}
#IBAction func dismissButton(_ sender: Any) {
dismiss(animated: true, completion: nil)
}
//TableView
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return recipiesList.count
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellDescription") as! TableViewCellDescription
let recipies = recipiesList[indexPath.row]
cell.recipiesModuleLabel.text = recipies.detail?.description
return cell
}
}
At this moment the result is:
Table View Entries
Any ideas?
In your case you want to show details items in different row whereas you have array of RecipiesModel.
var recipiesList = [RecipiesModel]()
In case you can represent each modal object of array as a section and details object as their rows. You can do that as:
// TableView datasource and delegate methods
func numberOfSections(in tableView: UITableView) -> Int {
return recipiesList.count
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
let modal = recipiesList[section]
return "\(modal.title ?? ""): \(modal.desc ?? "")"
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return recipiesList[section].detail?.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellDescription") as! TableViewCellDescription
if let detailName = recipiesList[indexPath.section].detail?[indexPath.row] as? String {
cell.recipiesModuleLabel.text = detailName
} else {
cell.recipiesModuleLabel.text = ""
}
return cell
}

ObjectMapper displayed model in TableView Swift

I am new to Swift , i parsing my JSON by using ObjectMapper but I want data displayed in TableView
I do not know how to do that
My Model:
import Foundation
import ObjectMapper
import SwiftyJSON
class AllCnannelModel : Mappable {
var id : Int?
var name: String?
var url : URL?
var picture : URL?
var category_id: Int?
required init?(map: Map) {}
func mapping(map: Map) {
id<-map["id"]
name<-map["name"]
url<-map["url"]
picture<-map["picture"]
category_id<-map["category_id"]
}
}
My TableView :
var name = [String]()
var urlChannel = [URL]()
override func viewDidLoad() {
super.viewDidLoad()
let URL = "http://52.50.138.211:8080/ChanelAPI/chanels"
Alamofire.request(URL).responseArray { (response: DataResponse<[AllCnannelModel]>) in
let channnellArray = response.result.value
if let channnellArray = channnellArray {
for channel in channnellArray {
self.name.append(channel.name!)
}
}
self.tableView.reloadData()
}
}
I can describe one type of data in the array and display:
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return self.name.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as UITableViewCell
cell.textLabel?.text = self.name[indexPath.row]
return cell
}
but i want all type of data in one array and display TableViewController
How can you implement?
Did you implemented numberOfSections(in tableView: UITableView) -> Int ?

Group and sort Backendless data in UITableview with Swift

I'm looking to group and sort a list of users from backendless, similar to iPhone contacts. I want to add sectionIndexTitlesForTableView(_:), titleForHeaderInSection(_:), and sectionForSectionIndexTitle(_:). I haven't found a tutorial on how to do this, and I have been stuck for weeks.
So far, I'm able to retrieve users and populate the table view. I also implemented UISearchBarDelegate.
var users: [BackendlessUser] = []
var filteredUsers : [BackendlessUser] = []
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if tableView == self.tableView {
return users.count
} else {
return self.filteredUsers.count
}
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = UITableViewCell()
if tableView == self.tableView {
let user = users[indexPath.row]
cell.textLabel?.text = user.name
} else {
let filteredUser = filteredUsers[indexPath.row]
cell.textLabel?.text = filteredUser.name
}
return cell
}
You must have a dictionary of array (name 'data' for example)
data["A"] = ["Ananas", "Anaconda", "Apple"]
data["B"] = ["Banana", "Baby"]
...
data["Z"] = ["Zoro"]
begin:
let letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
var headers: [String] = []
var data : [String: [String]] = [:] // Choose your type
override func viewDidLoad(){
// Do your stuff...
headers = letters.keys.sort()
// init your data var
data = ...
tableView.reloadData()
}
for header:
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return headers.count
}
func sectionHeaderTitlesForTableView(tableView: UITableView) -> [String]?{
return headers
}
func tableView: UITableView, titleForHeaderInSection section: Int) -> String?{
return headers[section];
}
cell
func tableView(tableView: UITableView, numberOfRowInSection section: Int) -> Int {
// Exemple
return data[section].count
}

Resources