How can I make same day message in one section? - ios

import UIKit
class MessageDetailViewController: UIViewController {
#IBOutlet weak var tableview: UITableView!
struct data{
let time: String
let message: String
let date: String
let type: String
}
struct section {
let date: String
var array = [data]()
}
let sectionArray = [
section(date: "yesterday", array: [
data(time: "3:30 PM", message: "I am looking for your service, can you please give more information on that.", date: "yesterday", type: "sender"),
data(time: "3:40 PM", message: "Sure i am here to help you", date: "yesterday", type: "receiver")
]),
section(date: "today", array: [data(time: "4:40 PM", message: "Ok, I wil contact you on your phone for that.", date: "today", type: "sender")])
]
override func viewDidLoad() {
super.viewDidLoad()
self.tableview.register(UINib(nibName: "SenderCell", bundle: nil), forCellReuseIdentifier: "SenderCell")
self.tableview.register(UINib(nibName: "ReceiverCell", bundle: nil), forCellReuseIdentifier: "ReceiverCell")
self.tableview.register(UINib(nibName: "customHeaderViewCell", bundle: nil), forCellReuseIdentifier: "customHeaderViewCell")
}
}
extension MessageDetailViewController: UITableViewDelegate, UITableViewDataSource{
func numberOfSections(in tableView: UITableView) -> Int {
return sectionArray.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return sectionArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if sectionArray[indexPath.section].array[indexPath.row].type == "sender"
{
let cell = tableview.dequeueReusableCell(withIdentifier: "SenderCell", for: indexPath) as! SenderCell
cell.setData(reciverTime: sectionArray[indexPath.section].array[indexPath.row].time, reciverMsg: sectionArray[indexPath.section].array[indexPath.row].message)
return cell
}
else
{
let cell = tableView.dequeueReusableCell(withIdentifier: "ReceiverCell", for: indexPath) as! ReceiverCell
cell.setData(reciverTime: sectionArray[indexPath.section].array[indexPath.row].time, reciverMsg: sectionArray[indexPath.section].array[indexPath.row].message)
return cell
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = UIView()
let headerCell = tableView.dequeueReusableCell(withIdentifier: "customHeaderViewCell") as! customHeaderViewCell
if sectionArray[section].date == "yesterday"{
headerCell.labelHeader.text = "yesterday"
}
else{
headerCell.labelHeader.text = "today"
}
headerView.addSubview(headerCell)
return headerView
}
}
This is my message detail code.
I want to achieve these
But through these array I achieved these
what changes should I do in my code so that I can get same day message in one section
this ---
sectionArray.append(section(date: "yesterday", array: [data(time: "3:40 PM", message: "SURE i am here to help you", date: "yesterday", type: "receiver")]))
Making a new section I don't want to make new section when sure I am here o help you array comes.

As I've seen your code, you're using String to indicate the day of the message which is bad practice. Instead, you should use Date, which will help you group the messages by date:
let sectionArray = messages.reduce(into: [section]()) { result, element in
if let section = result.firstIndex(where: {Calendar.current.isDate($0.date, inSameDayAs: element.date)}) {
result[section].append(element)//append message to section
}else {
//create new section
}
}
If you really need to use String, use this:
let sectionArray = messages.reduce(into: [section]()) { result, element in
if let section = result.firstIndex(where: {$0.date == element.date}) {
result[section].append(element)//append message to section
}else {
//create new section
}
}

Related

Swift 5 - Set TextLabel in Custom CollectionviewCell from JSON Array

I have created a custom cell for my collectionview that i have set in a tableview for my app. I need to know to to set the text label to appear as the items in my array that is listed in my JSON File that is local.
View Controller:
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var workoutData = [Models]()
#IBOutlet weak var tableview: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
parseJSON()
tableview.register(CollectionTableViewCell.nib(), forCellReuseIdentifier: CollectionTableViewCell.identifier)
print(workoutData)
}
func numberOfSections(in tableView: UITableView) -> Int {
return workoutData.count
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return workoutData[section].title
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return workoutData[section].workouts.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: CollectionTableViewCell.identifier, for: indexPath) as! CollectionTableViewCell
cell.configure(with: workoutData)
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableview.deselectRow(at: indexPath, animated: true)
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 250.0
}
func parseJSON() {
let url = Bundle.main.url(forResource: "data", withExtension: "json")!
do{
let data = try Data(contentsOf: url)
workoutData = try JSONDecoder().decode([Models].self, from: data)
} catch {
print(error)
}
}
}
My Custom Cell File:
import UIKit
class MyCollectionViewCell: UICollectionViewCell {
var workoutData = [Models]()
#IBOutlet weak var myLabel: UILabel!
static let identifier = "MyCollectionViewCell"
static func nib() -> UINib {
return UINib(nibName: "MyCollectionViewCell", bundle: nil)
}
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
public func configure(with model: Models) {
self.myLabel.text = //what to put here.
print(model.title)
}
}
My JSON File:
[
{
"title": "Chest",
"workouts": [
"Bench",
"Pushup",
"Incline Press",
"Decline Press",
]
},
{
"title": "Back",
"workouts": [
"Barbell Row",
"Lat Pulldown",
"Deadlift",
"Back Extension",
]
},
{
"title": "Arms",
"workouts": [
"Barbell Curl",
"Dumbbell Curl",
"Tricep Pressdown",
"Skull Crusher",
]
}
]
I want my text label to show the items in my workouts array. when i set it i get the error "cannot assign value of type '[String]' to type 'String'". I would appreciate any help or directions. Thanks
EDIT:
I am looking to build my layout similar to the horizontal scroll of the the app store
workouts is an array of String. So firstly you need to get the String from array by index.
You can use this to show the first value on the label
self.myLabel.text = models.workouts[0]
Or If you want to show all the workouts values on the array then you can use
self.myLabel.text = models.workouts.joined(separator: ", ")

Group UITableView sections by date

I have a JSON file with Title, startDate, and endDate. I would like to group my sections in my UITableView by dates and to add the date of each group as the header. I am unsure of how to retrieve the data from my groupByDate function to populate the specific sections. Would I have to create a new array from my groupByDate function.
var eventList: [Event] = []
var eventGroup: [[Event]] = []
func numberOfSections(in tableView: UITableView) -> Int {
return eventGroup.count
}
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
v.backgroundColor = .darkGray
return v
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 3.0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "myCell", for: indexPath) as! MyTableCell
cell.titleLabel.textColor = .red
}else{
cell.titleLabel.textColor = .black
}
return cell
}
You need to get the idea first. Imagine you just have one section of all your events. What would you have as your model?
A title
An array of events
Right?
Okay if the above makes sense, you then would need multiple of that said models. Right again? Now break that into more specific terms. Like actual model type.
struct Event {
let title: String
let startDate: Date
// maybe an endDate object too
}
struct Section {
let title: String
let events: [Event]
}
So now you will need to provide an array of Section object to the table view.
But before that you will need to group your sections by the startDate object. Swift has a pretty convenience initializer of Dictionary type that allows us to group an array by choosing a particular property's value from the object in the array. Pay attention to the function below:
func groupedSectionsByDate(from events: [Event]) -> [Section] {
let grouped = Dictionary(grouping: events) { $0.startDate }
// here you will need a date formatter object that will be used to convert
// the Date type to String type. It's left as an assignment for the reader
let dateFormatter: DateFormatter // init and configure it yourself
let sections = grouped.map { Section(title: dateFormatter.string(from: $0.key), events: $0.value) }
return sections
}
The above function should get you the sections with titles as grouped by date.
Now how would you use it with the table view?
class TableViewController: UITableViewController {
. . .
let sections = [Section]()
. . .
. . .
func numberOfSections(in tableView: UITableView) -> Int {
return sections.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return sections[section].count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
. . .
let event = sections[indexPath.section].events[indexPath.row]
. . .
}
. . .
. . .
}
update
The initial data of the hypothesis is like this
[
{
"title": "Bicycling with Friends",
"start": "11-01-2018"
},
{
"title": "Yoga",
"start": "11-01-2018"
},
{
"title": "Yoga",
"start": "11-02-2018"
}
]
If you want to group display, you need to assemble the array into dates like this, each group of titles can use start
[
[
{
"title": "Bicycling with Friends",
"start": "11-01-2018"
},
{
"title": "Yoga",
"start": "11-01-2018"
}
],
[
{
"title": "Yoga",
"start": "11-02-2018"
}
]
]
I think your data source can hold a two-dimensional array eventGroup, or a dated dictionary [dateString : [event]]. Only use eventGroup can be modified to be like this
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return eventGroup[section].count
}
func numberOfSections(in tableView: UITableView) -> Int {
return eventGroup.count
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
let events = eventGroup[section]
let event = events.first
return event?.title //Replace with the header title you want
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "myCell", for: indexPath) as! MyTableCell
let events = eventGroup[indexPath.section]
let dateRow = events[indexPath.row].start
let dateRowEnd = events[indexPath.row].end
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let myString = formatter.string(from: dateRow)
let yourDate = formatter.date(from: myString)
formatter.dateFormat = "MM-dd-yyyy h:mm a"
let myStringafd = formatter.string(from: yourDate!)
cell.titleLabel.text = eventList[indexPath.row].title
cell.dateStartLabel.text = "Start date: \(myStringafd)"
if events[indexPath.row].conflict == true {
cell.titleLabel.textColor = .red
}else{
cell.titleLabel.textColor = .black
}
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{
}
}

showing an error as has need to conform the protocol

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.

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
}

Resources