showing an error as has need to conform the protocol - ios

This is my code:-
Model:-
class QuestionListModel: NSObject {
var optionsModelArray:[OptionsModel] = []
var question:String!
init(dictionary :JSONDictionary) {
guard let question = dictionary["question"] as? String
else {
return
}
if let options = dictionary["options"] as? [String]{
print(options)
print(options)
for values in options{
print(values)
let optionmodel = NH_OptionsModel(values: values)
self.optionsModelArray.append(optionmodel)
}
}
self.question = question
// print(self.dataListArray33)
}
}
optionModel:-
class OptionsModel: NSObject {
var values:String?
init(values:String) {
self.values = values
print( self.values)
}
}
in viewmodel:-
var questionsModelArray:Array<NH_QuestionListModel>? = []
init(withdatasource newDatasourceModel:NH_QuestionDataSourceModel) {
datasourceModel = newDatasourceModel
print(datasourceModel.dataListArray?.count)
self.questionsModelArray = datasourceModel.dataListArray
print(self.questionsModelArray)
print(datasourceModel.dataListArray)
}
func numberOfSections() -> Int{
return (self.questionsModelArray?.count)!
}
func titleForHeaderInSection(atindexPath indexPath: IndexPath) -> QuestionListModel {
return self.questionsModelArray![indexPath.row]
}
func numberOfRowsInSection(indexPath:IndexPath) -> Int {
if let questionModel = self.questionsModelArray?[indexPath.section]{
return questionModel.optionsModelArray.count
}
else{
return 0
}
}
func datafordisplay(atindex indexPath: IndexPath) -> OptionsModel{
let questionModel = self.questionsModelArray?[indexPath.section]
return questionModel!.optionsModelArray[indexPath.row]
}
And in ViewController:-
func numberOfSections(in tableView: UITableView) -> Int {
return questionViewModel.numberOfSections()
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: IndexPath) -> UIView? {
// let headercell = Bundle.main.loadNibNamed("HeaderCell", owner: self, options: nil)?.first as! NH_questionheader
let identifier = "HeaderCell"
var headercell: NH_questionheader! = tableView.dequeueReusableCell(withIdentifier: identifier) as? NH_questionheader
if headercell == nil {
tableView.register(UINib(nibName: "NH_questionheader", bundle: nil), forCellReuseIdentifier: identifier)
headercell = tableView.dequeueReusableCell(withIdentifier: identifier) as? NH_questionheader
}
headercell.setReviewData(reviews:questionViewModel.titleForHeaderInSection(atindexPath:section))
return headercell
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 150
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: IndexPath) -> Int {
return questionViewModel.numberOfRowsInSection(indexPath: section)
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let identifier = "Cell"
var cell: CellTableViewCell! = tableView.dequeueReusableCell(withIdentifier: identifier) as? CellTableViewCell
if cell == nil {
tableView.register(UINib(nibName: "CellTableViewCell", bundle: nil), forCellReuseIdentifier: identifier)
cell = tableView.dequeueReusableCell(withIdentifier: identifier) as? CellTableViewCell
}
cell.contentView.backgroundColor = UIColor.clear
cell.setOptions(Options1: questionViewModel.datafordisplay(atindex: indexPath))
print("Section \(indexPath.section), Row : \(indexPath.row)")
return cell
}
my json file:-
{
"data":[
{
"question": "Gender",
"options": ["Male","Female"]
},
{
"question": "How old are you",
"options": ["Under 18","Age 18 to 24","Age 25 to 40","Age 41 to 60","Above 60"]
}, {
"question": "I am filling the Questionnaire for?",
"options": ["Myself","Mychild","Partner","Others"]
}
]
}
This is my data .So i need to display the questions in header and options in the cell for index .But showing as error as UITableview has need to conform the protocol UITableviewDataSource.
Also showing error as Index out of range.
How to do.....

I think you are not assign a datasource to your view controller. So please assign it in your ViewDidLoad of your view controller
override func viewDidLoad() {
super.viewDidLoad()
self.yourtableview.delegate = self
self.yourtableview.dataSource = self
// Do any additional setup after loading the view.
}

This error usually occurs when you fail to implement the required methods of a protocol. In this case the methods would be :
cellForRowAt
numberOfRowsInSection
Since you already have them implemented in your view controller chances are that you might have failed to set the datasource for the table view.
Refer to this
https://developer.apple.com/documentation/uikit/uitableviewdatasource

your view controller cannot find the data source and delegate for the table view. make sure you have assigned the data source and delegate
self.yourtableview.delegate = self
self.yourtableview.dataSource = self
and also make sure that your controller also inherit the UITableViewDelegate and UITableViewDataSource like this
class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource

To achieve what you want, you should set your VC as the delegate and datasource of your table.
Option 1, do it dynamically:
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.delegate = self
self.tableView.dataSource = self
}
Option 2, from your storyboard (example below):
After this, you should use the following datasource functions of UITableView:
// return number of questions
func numberOfSections(in tableView: UITableView) -> Int
// return number of options per question (indicated by section)
func tableView(UITableView, numberOfRowsInSection: Int) -> Int

You haven't correctly declared the numberOfRowsInSection function; section is an Int, not an IndexPath. As a result you have not implemented the mandatory functions of UITableViewDataSource.
You want:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return questionViewModel.numberOfRowsIn(section: section)
}
With an appropriate change in your view model:
func numberOfRowsIn(section:Int) -> Int {
return self.questionsModelArray?[section].optionsModelArray.count ?? 0
}
I would also suggest that you review your use of implicitly unwrapped optionals and force unwrapping; this is just asking for crashes.
For example, there is no reason for the question property of QuestionListModel to be String!; just declare it as String and make your initialiser failable. Better yet, use Codable to create your model from JSON and get rid of all of that code.
You can eliminate the force unwrapping in numberOfSections too:
func numberOfSections() -> Int {
return self.questionsModelArray?.count ?? 0
}
I would also suggest you make QuestionListModel a struct rather than an NSObject subclass.
If I were you I would re-factor to remove the view model, it is adding unnecessary complexity in this case, and use Codable for your JSON deserialisation:
struct Questions: Codable {
enum CodingKeys: String, CodingKey {
case questions = "data"
}
var questions: [Question]
}
struct Question: Codable {
var question: String
var options: [String]
}
Your view controller then becomes much simpler:
class ViewController: UIViewController, UITableViewDatasource {
var questionData: Questions?
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UINib(nibName: "NH_questionheader", bundle: nil), forCellReuseIdentifier: "HeaderCell")
tableView.register(UINib(nibName: "CellTableViewCell", bundle: nil), forCellReuseIdentifier: "Cell")
// You don't show how you load your JSON, but assuming you have it in an instance of `Data` called `jsonData`:
do {
self.questionData = try JSONDecoder().decode(Questions.self, from: jsonData)
} catch {
print("Error decoding JSON: \(error.localizedDescription)")
}
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: IndexPath) -> UIView? {
let identifier = "HeaderCell"
guard let questionData = self.questionData,
let headercell = tableView.dequeueReusableCell(withIdentifier: identifier) as? NH_questionheader else {
return nil
}
headercell.label.text = questionData.questions[section].question
return headercell
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 150
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.questionData?.questions[section].options.count ?? 0
}
func numberOfSections(in tableView: UITableView) -> Int {
return self.questionData?.questions.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let identifier = "Cell"
// Note, I have used force unwrapping and a forced downcast here as if either of these lines fail you have a serious problem and crashing is the simplest way of finding it during development
let option = self.questionData!.questions[indexPath.section].options[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: identifier, for: indexPath ) as! CellTableViewCell
cell.contentView.backgroundColor = .clear
cell.label.text = option
return cell
}
}
Once you have this basic approach working you can try and add a view model if you like.

Related

Filtering query for Realm

I have a function which prints all the objects in my realm table to a table view. I would like to be able to filter these objects by their "muscle" property.
Here's my DB helper functions:
func getMusclesCount()-> Int {
let storedExercise = realm.objects(StoredExercise.self)
return storedExercise.count
}
//MARK:- getAllMuscelsNames
func getAllMusclesNames()-> [String] {
var musclesName = [String]()
let storedExercise = realm.objects(StoredExercise.self)
for exercise in storedExercise {
print("Muscle = \(exercise.muscle)")
musclesName.append(exercise.name)
}
return musclesName
}
Here's my Table View Controller class :
class TableViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return DBHelper.shared.getAllMusclesNames().count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
if cell == nil {
cell = UITableViewCell(style: .default, reuseIdentifier: "cell")
}
let muscle = DBHelper.shared.getAllMusclesNames()[indexPath.row]
cell.textLabel?.text = muscle
return cell
}
I've tried adding .Filter to 'let storedExercise' but I'm not sure how to set it up correctly. Any assitance would be greatly appreciated, thanks.
If your StoredExercise model looks like this
class StoredExercise: Object {
#objc dynamic var muscle = ""
}
then to get all of the exercises that are for the biceps, it's this
let bicepResults = realm.objects(StoredExercise.self).filter("muscle == 'biceps'")

Convert JSON to a Array with struct

I am trying to make a IOS app that is a home automation thing. I am using TableViewCell to display information.
My problem is that I have no idea how to get JSON to an Array with struct because I have to have struct I think.
My JSON is:
[{"namea":"TV","statea":"up_tv"},{"namea":"test","statea":"test"}]
My code is:
struct cellData {
let nameLabel : String!
let stateLabel : String!
}
class Main: UITableViewController {
var array = [cellData]()
override func viewDidLoad() {
array = [cellData(nameLabel: "tv", stateLabel: "up_tv"),
cellData(nameLabel: "tv", stateLabel: "down_tv")]
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return array.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = Bundle.main.loadNibNamed("TableViewCell", owner: self, options: nil)?.first as! TableViewCell
cell.nameLabel.text = array[indexPath.row].nameLabel
cell.stateLabal.text = array[indexPath.row].stateLabel
return cell
}
You need jsonDecoder
struct cellData : Decodable {
let nameLabel : String
let stateLabel : String
enum CodingKeys:String,CodingKey {
case nameLabel = "namea"
case stateLabel = "statea"
}
}
//
let str = """
[{"namea":"TV","statea":"up_tv"},{"namea":"test","statea":"test"}]
"""
do {
let cellArr = try JSONDecoder().decode([cellData].self, from: str.data(using:.utf8)!)
print(cellArr) //// check this
} catch {
}
//
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "id") as TableViewCell
}

How to pass data (which am getting from server) into tableView which is in UIView

I have one viewController. In that i have one button, if i click on that button am presenting a UIView on that viewController.
In that UIVew i have one tableView. Now i want to pass data into that tableview, which am getting from server.
I cant display the data in tableView, i kept breakpoint and checked. am not able to enter into cellForRowAt indexPath method also
could any one help me with this
Here is the code which i tried
Here is my UIView class
class ButtonClicked: UIView {
#IBOutlet weak var tableView: UITableView!
override func didMoveToSuperview() {
//super.awakeFromNib()
}
Here is my ViewController class
class ViewController: UIViewController{
var tableviewDisplayArray: NSArray = []
override func viewDidLoad() {
super.viewDidLoad()
buttonClicked.tableView.register(UINib(nibName: “TableViewDisplayCell", bundle: nil), forCellReuseIdentifier: “tableViewDispCell")
buttonClicked.tableView.delegate = self
buttonClicked.tableView.dataSource = self
}
#IBAction func addMoneyButtonClicked() {
buttonClickedWebserviceCall()
actionAlertViewController.actionType = ActionAlertType.ADD_MONEY
present(self.view.actionAlertPopup(alertVC: actionAlertViewController), animated: animated, completion: nil)
}
func buttonClickedWebserviceCall(){
let params: NSDictionary = ["langId" : “1”, "countryId" : “1”]
callingWebservice().dataTaskWithPostRequest(urlrequest: URL_BUTTONCLICKED viewcontroller: self, params: params) { (result, status) in
let response : NSDictionary = result as! NSDictionary
let status = response.value(forKey: "httpCode") as! NSNumber
if status == 200{
DispatchQueue.main.async {
self.tableviewDisplayArray= (response.value(forKey: “response”) as? NSArray)!
print(self.tableviewDisplayArray)
self.buttonClicked.tableView.reloadData()
}
}
else{
DispatchQueue.main.async {
}
}
}
}//method close
}//class close
extension ViewController: UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if tableView == buttonClicked.tableView {
return tableviewDisplayArray.count
}
else{
return 5
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if tableView == buttonClicked.tableView {
return 30.0
}
else{
return 75.0
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if tableView == buttonClicked.tableView {
let cell = buttonClicked.tableView.dequeueReusableCell(withIdentifier: "tableViewDispCell", for: indexPath) as! TableViewDisplayCell
let storedArray = self.tableviewDisplayArray.object(at: indexPath.row) as! NSDictionary
print(storedArray)
return cell
}
else{
let cell = tableView.dequeueReusableCell(withIdentifier: “normalCell”, for: indexPath) as! NormalCell
return cell
}
}
}
You have written the tableView delegate methods in an extension of UIViewController class. Just write that code inside the ViewController class where you have set the delegate and datasource to.Like this
class ViewController: UIViewController,UITableViewDelegate, UITableViewDataSource{
var tableviewDisplayArray: NSArray = []
override func viewDidLoad() {
super.viewDidLoad()
buttonClicked.tableView.register(UINib(nibName: “TableViewDisplayCell", bundle: nil), forCellReuseIdentifier: “tableViewDispCell")
buttonClicked.tableView.delegate = self
buttonClicked.tableView.dataSource = self
}
#IBAction func addMoneyButtonClicked() {
buttonClickedWebserviceCall()
actionAlertViewController.actionType = ActionAlertType.ADD_MONEY
present(self.view.actionAlertPopup(alertVC: actionAlertViewController), animated: animated, completion: nil)
}
func buttonClickedWebserviceCall(){
let params: NSDictionary = ["langId" : “1”, "countryId" : “1”]
callingWebservice().dataTaskWithPostRequest(urlrequest: URL_BUTTONCLICKED viewcontroller: self, params: params) { (result, status) in
let response : NSDictionary = result as! NSDictionary
let status = response.value(forKey: "httpCode") as! NSNumber
if status == 200{
DispatchQueue.main.async {
self.tableviewDisplayArray= (response.value(forKey: “response”) as? NSArray)!
print(self.tableviewDisplayArray)
self.buttonClicked.tableView.reloadData()
}
}
else{
DispatchQueue.main.async {
}
}
}
}//method close
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if tableView == buttonClicked.tableView {
return tableviewDisplayArray.count
}
else{
return 5
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if tableView == buttonClicked.tableView {
return 30.0
}
else{
return 75.0
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if tableView == buttonClicked.tableView {
let cell = buttonClicked.tableView.dequeueReusableCell(withIdentifier: "tableViewDispCell", for: indexPath) as! TableViewDisplayCell
let storedArray = self.tableviewDisplayArray.object(at: indexPath.row) as! NSDictionary
print(storedArray)
return cell
}
else{
let cell = tableView.dequeueReusableCell(withIdentifier: “normalCell”, for: indexPath) as! NormalCell
return cell
}
}
//Notice that tableView delegate methods should be in your ViewController class because that is the 'self' here so delegate and datasource is the ViewController class
//buttonClicked.tableView.delegate = self
//buttonClicked.tableView.dataSource = self
//as you write this the tableview looks for data in this ViewController class.
//Extensions are meant for another purpose.
}
//class close

How to connect swift codes and storyboard?

I am trying to figure out a way to use the Pod ColorMatchTabs, however its example is doing it programmatically and I can't find a way to use them in my project. I will summarize this:
To use the pod, I have to follow this protocols to install the tabs in my viewController:
extension ExampleViewController: ColorMatchTabsViewControllerDataSource {
func tabsViewController(_ controller: ColorMatchTabsViewController, iconAt index: Int) -> UIImage {
return TabItemsProvider.items[index].normalImage
}
func tabsViewController(_ controller: ColorMatchTabsViewController, hightlightedIconAt index: Int) -> UIImage {
return TabItemsProvider.items[index].highlightedImage
}
func numberOfItems(inController controller: ColorMatchTabsViewController) -> Int {
return TabItemsProvider.items.count
}
func tabsViewController(_ controller: ColorMatchTabsViewController, viewControllerAt index: Int) -> UIViewController {
return StubContentViewControllersProvider.viewControllers[index]
}
func tabsViewController(_ controller: ColorMatchTabsViewController, titleAt index: Int) -> String {
return TabItemsProvider.items[index].title
}
func tabsViewController(_ controller: ColorMatchTabsViewController, tintColorAt index: Int) -> UIColor {
return TabItemsProvider.items[index].tintColor
}
These are the protocols to handle how the tabs look like, how many items and my difficulties are in the part calling UIViewController. I assume it return which controllers are used based on which tab, and here goes the code in StubContentViewControllersProvider:
import UIKit
import ColorMatchTabs
class StubContentViewControllersProvider {
static let viewControllers: [UIViewController] = {
let productsViewController = StubContentViewController()
productsViewController.type = .products
let venuesViewController = StubContentViewController()
venuesViewController.type = .venues
let reviewsViewController = StubContentViewController()
reviewsViewController.type = .reviews
let usersViewController = StubContentViewController()
usersViewController.type = .users
return [productsViewController, venuesViewController, reviewsViewController, usersViewController]
}()
}
I assume we are calling all the controllers from StubContentViewController and here is how it looks like:
import UIKit
class StubContentViewController: UITableViewController {
enum `Type` {
case products, venues, reviews, users
}
var type: Type!
fileprivate var objects: [UIImage] = []
override func viewDidLoad() {
super.viewDidLoad()
setupTableView()
setupDataSource()
}
fileprivate func setupTableView() {
tableView.backgroundColor = UIColor.clear
tableView.allowsSelection = true
tableView.separatorColor = UIColor.clear
tableView.register(UINib(nibName: "ExampleTableViewCell", bundle: nil), forCellReuseIdentifier: "cell")
}
fileprivate func setupDataSource() {
if type == .products || type == .reviews {
self.objects = [UIImage(named: "product_card1")!, UIImage(named: "product_card2")!]
} else if type == .venues || type == .users {
self.objects = [UIImage(named: "venue_card1")!, UIImage(named: "venue_card2")!]
}
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return objects.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! ExampleTableViewCell
let image = objects[(indexPath as NSIndexPath).row]
cell.apply(image)
return cell
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return tableView.bounds.width / 1.4
}
}
So my question here is, I am setting up a TableViewController and reference it to StubContentViewController in storyboard, but why when I make changes in the storyboard, it doesn't make any effect? And for example I want to perform a segue for the table cell, I couldn't find any way to make it via the storyboard?

Slow/Stuttered scroll in tableview

I'm loading about 150 elements from an array of arrays of dictionaries (tasks) and I can get all of the data into my tableview but when I scroll its stupid slow. When I print out the information of one of my functions to the console, it looks like I am getting all of the data back every time I scroll. Is this something I am not loading well (i.e. asynchronously) or do I need to change my functions?
func querySections() -> [String] {
var sectionsArray = [String]()
for task in tasks {
let dueTimes = task.dueTime
sectionsArray.append(dueTimes)
}
let uniqueSectionsArray = Array(Set(sectionsArray.sort()))
// print(uniqueSectionsArray)
return uniqueSectionsArray
}
func queryDueTimes(section:Int) -> [Task] {
var sectionItems = [Task]()
for task in tasks {
let dueTimes = task.dueTime
if dueTimes == querySections()[section] {
sectionItems.append(task)
}
}
print(sectionItems)
return sectionItems
}
// MARK: - Table view data source
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return querySections()[section]
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return querySections().count
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return queryDueTimes(section).count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("TaskCell", forIndexPath: indexPath) as! TaskCell
// Configure the cell...
cell.selectionStyle = .None
let times = queryDueTimes(indexPath.section)
let task = times[indexPath.row]
cell.label.text = task.title
if task.done == true {
cell.checkBox.image = UIImage(named: "checkedbox")
cell.detailLabel.text = "Completed By: \(task.completedBy)"
}
else {
cell.checkBox.image = UIImage(named: "uncheckedbox")
cell.detailLabel.text = ""
}
cell.delegate = self
return cell
}
Basically, in querySections, I'm iterating through all of the dueTimes for each task and then changing them into an array of a set so I can filter out all of the duplicates. This is giving me all of my sections. For queryDueTimes, I'm iterating through the tasks and matching them to a section.
I had a thought about calling the functions in viewDidLoad but that isn't working (it keeps giving me an empty array when I try to pass it to another empty array thats more accessible outside of the function) and I can't access section (for queryDueTimes) in viewDidLoad (as far as what I know how to do).
Update 1:
I think the mistake is on my end. I said that I tasks is an array of arrays when its just an array of Tasks (a struct with all of the properties of each task). When I load the app, I append all of the tasks from my backend to a local array ("tasks"). Should I have an array of arrays for this to work or can I amend my code somehow and get it to work?
Update 2:
I'm getting sectionTimes and tasksInSectionArray as empty arrays when I print them.
var sectionTimes = [String]()
var tasksInSectionArray = [[Task]]()
var tasks = [Task]() {
didSet {
tableView?.reloadData()
}
}
func updateTableView() {
sectionTimes = Set(tasks.map{$0.dueTime}).sort()
tasksInSectionArray = sectionTimes.map{section in tasks.filter{$0.dueTime == section}}
print(sectionTimes)
print(tasksInSectionArray)
tableView.reloadData()
}
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return sectionTimes[section]
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return sectionTimes.count
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tasksInSectionArray[section].count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("TaskCell", forIndexPath: indexPath) as! TaskCell
// Configure the cell...
cell.selectionStyle = .None
let task = tasksInSectionArray[indexPath.section][indexPath.row]
Like you guessed, the data is being loaded and sorted over and over again, instead of only once. Save the results of querySelections and queryDueTimes and use that inside the table view data source methods.
You can do this in viewDidLoad - call both functions once and assign the results to a variable at the class level, and then call tableView.reloadData() (assuming you have a reference to the table view).
var sections: [String] = []
var data: [[Tasks]] = []
func updateTableView() {
sections = Set(tasks.map { $0.dueTime }).sort()
data = sections.map { section in tasks.filter { $0.dueTime == section } }
tableView.reloadData()
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return sections.count
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data[section].count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let task = data[indexPath.section][indexPath.row]
// Cell configuration
}
This is basically what DMan said, but I've made an example for you.

Resources