how to get main tableview index in nested tableview in swift - ios

I am new in swift and I am not able to get main tableview index on nested tableview button click
my code is like this
extension Section2QuestionsViewController: UITableViewDataSource, UITableViewDelegate
{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrFinancialYears.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let strCellID = "Section2QuestionCell"
var cell = tableView.dequeueReusableCell(withIdentifier: strCellID) as? Section2QuestionCell
if cell == nil
{
tableSection2.register(Section2QuestionCell.self, forCellReuseIdentifier: strCellID)
cell = tableSection2.dequeueReusableCell(withIdentifier: strCellID) as? Section2QuestionCell
}
let dictAppStats = arrFinancialYears[indexPath.row] as? [String:Any]
cell?.lblQuestionTitle.text = "\(indexPath.row + 1). \(dictAppStats?["question"] as? String ?? "")"
cell?.arrCourses = [Any]()
cell?.arrCourses = dictAppStats?["options"] as? [Any] ?? []
cell?.tableInsideHeightConstraints.constant = CGFloat(28 * (cell?.arrCourses.count ?? 0))
cell?.tableInside.reloadData()
return cell!
}
}
Inside tableview
extension Section2QuestionCell: UITableViewDataSource, UITableViewDelegate
{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrCourses.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "InsideSection2QuestionCell", for: indexPath) as! InsideSection2QuestionCell
cell.selectionStyle = .none
let dictFeeStats = arrCourses[indexPath.row] as? [String:Any]
cell.lblOption.text = dictFeeStats?["option_value"] as? String
cell.btnOption.tag = indexPath.item
cell.btnOption.addTarget(self, action: #selector(btnOptionClick), for: .touchUpInside)
cell.lblAnswerKey.text = dictFeeStats?["answer_key"] as? String
cell.lblQuestionId.text = dictFeeStats?["question_id"] as? String
cell.lblAnswerId.text = dictFeeStats?["option_id"] as? String
return cell
}
}
Button Click
#objc func btnOptionClick(_ sender: UIButton)
{
let index = IndexPath(row: sender.tag, section: 0)
let cell: InsideSection2QuestionCell = tableInside.cellForRow(at: index) as! InsideSection2QuestionCell
let QuestionId = cell.lblQuestionId.text
let AnswwerId = cell.lblAnswerId.text
print(QuestionId as Any)
print(AnswwerId as Any)
Globalnewdict = ["option":AnswwerId as Any,"question":QuestionId as Any]
Globalindexvalue = sender.tag
NotificationCenter.default.post(name: Notification.Name(rawValue: "disconnectPaxiSockets"), object: nil)
tableInside.reloadData()
}
I am not able to get main tableview index path value on button. Is there is any way to get main tableview index path value on button click.
Please help
Thanks in Advance!

You could add an index path object in your Section2QuestionCell
var parentTableIndexPath : IndexPath!
Then set the value in cellForRowAt tableview delegate method
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let strCellID = "Section2QuestionCell"
var cell = tableView.dequeueReusableCell(withIdentifier: strCellID) as? Section2QuestionCell
if cell == nil {
tableSection2.register(Section2QuestionCell.self, forCellReuseIdentifier: strCellID)
cell = tableSection2.dequeueReusableCell(withIdentifier: strCellID) as? Section2QuestionCell
}
cell.parentTableIndexPath = indexPath
let dictAppStats = arrFinancialYears[indexPath.row] as? [String:Any]
cell?.lblQuestionTitle.text = "\(indexPath.row + 1). \(dictAppStats?["question"] as? String ?? "")"
cell?.arrCourses = [Any]()
cell?.arrCourses = dictAppStats?["options"] as? [Any] ?? []
cell?.tableInsideHeightConstraints.constant = CGFloat(28 * (cell?.arrCourses.count ?? 0))
cell?.tableInside.reloadData()
return cell!
}
Since btnOptionClick() is in same class, you can directly access the parent table Index path in your button action.

In
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let strCellID = "Section2QuestionCell"
var cell = tableView.dequeueReusableCell(withIdentifier: strCellID) as? Section2QuestionCell
if cell == nil
{
tableSection2.register(Section2QuestionCell.self, forCellReuseIdentifier: strCellID)
cell = tableSection2.dequeueReusableCell(withIdentifier: strCellID) as? Section2QuestionCell
}
let dictAppStats = arrFinancialYears[indexPath.row] as? [String:Any]
cell?.lblQuestionTitle.text = "\(indexPath.row + 1). \(dictAppStats?["question"] as? String ?? "")"
cell?.arrCourses = [Any]()
cell?.arrCourses = dictAppStats?["options"] as? [Any] ?? []
cell?.tableInsideHeightConstraints.constant = CGFloat(28 * (cell?.arrCourses.count ?? 0))
cell?.tableInside.tag = indexPath.row
cell?.tableInside.reloadData()
return cell!
}
In ButtonClick
#objc func btnOptionClick(_ sender: UIButton)
{
let index = IndexPath(row: sender.tag, section: 0)
let cell: InsideSection2QuestionCell = tableInside.cellForRow(at: index) as! InsideSection2QuestionCell
let QuestionId = cell.lblQuestionId.text
let AnswwerId = cell.lblAnswerId.text
print(QuestionId as Any)
print(AnswwerId as Any)
Globalnewdict = ["option":AnswwerId as Any,"question":QuestionId as Any]
Globalindexvalue = tableInside.tag
NotificationCenter.default.post(name: Notification.Name(rawValue: "disconnectPaxiSockets"), object: nil)
tableInside.reloadData()
}
In cellForRowAt I set indexpath.row to tableview.tag.
Then on button click I set tableview.tag to global indexpath.

Related

Order multiple TableViewCell types by TimeStamp

What I want to do:
Order all my TableViewCells from most recent to the oldest.
What is my problem:
I can order Cells from the same type by Time, though I fail at ordering them all in the same section by one common value (the time).
Here is my code:
import UIKit
import Firebase
class popularViewController: UIViewController, UITableViewDelegate, UITableViewDataSource{
#IBOutlet var table: UITableView!
// var models = [PhotoPost]()
var texttt = [TextPost]()
var phots = [PhotoPost]()
var mixed = [MixedPhoto]()
var switchy = [Any]()
override func viewDidLoad() {
super.viewDidLoad()
gettingPosts()
table.register(popularTableViewCell.nib(), forCellReuseIdentifier: popularTableViewCell.identifier)
table.register(featuredTableViewCell.nib(), forCellReuseIdentifier: featuredTableViewCell.identifier)
table.register(textTableViewCell.nib(), forCellReuseIdentifier: textTableViewCell.identifier)
table.register(mixedTableViewCell.nib(), forCellReuseIdentifier: mixedTableViewCell.identifier)
table.delegate = self
table.dataSource = self
self.table.estimatedRowHeight = 225
self.table.rowHeight = UITableView.automaticDimension
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(true)
}
func numberOfSections(in tableView: UITableView) -> Int {
return 3
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0{
return mixed.count
}
else if section == 1{
return phots.count
}
else{
return texttt.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0{
let cell = tableView.dequeueReusableCell(withIdentifier: mixedTableViewCell.identifier, for: indexPath) as! mixedTableViewCell
cell.configure(with: self.mixed[indexPath.row])
return cell
}
else if indexPath.section == 1{
let cell = tableView.dequeueReusableCell(withIdentifier: popularTableViewCell.identifier, for: indexPath) as! popularTableViewCell
cell.configure(with: self.phots[indexPath.row])
return cell
}
else{
let cell = tableView.dequeueReusableCell(withIdentifier: textTableViewCell.identifier, for: indexPath) as! textTableViewCell
cell.configure(with: self.texttt[indexPath.row])
return cell
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "commentsVC")
vc.modalPresentationStyle = .fullScreen
self.navigationController?.pushViewController(vc, animated: true)
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
func gettingPosts(){
let db = Firestore.firestore()
let postsRef = db.collection("posts")
postsRef.addSnapshotListener { (querySnapshot, error) in
guard let snapshot = querySnapshot else {
print("Error fetching snapshots: \(error!)")
return
}
snapshot.documentChanges.forEach { diff in
if (diff.type == .added){
let data = diff.document.data()
let Name = data["username"] as! String
let text = data["description"]
let likes = data["likes"] as! Int
let typ = data["postType"] as! Int
let pfp = data["profileImage"] as! String
let uid = data["uid"] as! String
let pic = data["picture"]
let time = data["time"] as! String
let pid = data["postID"] as! String
if typ == 0{ // Text post
let dasDing = TextPost(numberOfComments: 0, username: Name, timestampName: time, userImageName: pfp, textName: text as! String, postID: pid)
self.texttt.append(dasDing)
self.texttt.sort(by: { $0.timestampName > $1.timestampName })
}
if typ == 1{ // Text + Picture post
let Mixed = MixedPhoto(numberOfComments: 0, username: Name, timestampName: time, userImageName: pfp, textName: text as! String, postImageName: pic as! String, postID: pid)
self.mixed.append(Mixed)
self.mixed.sort(by: { $0.timestampName > $1.timestampName })
}
if typ == 2{ // Picture Post
let Foto = PhotoPost(numberOfComments: 0, username: Name, timestampName: time, userImageName: pfp, postImageName: pic as! String, postID: pid)
self.phots.append(Foto)
self.phots.sort(by: { $0.timestampName > $1.timestampName })
}
if typ == 3{ // Text + Video Post
}
if typ == 4{ // Video Post
}
}
}
self.table.reloadData()
}
}
}
struct PhotoPost {
let numberOfComments: Int
let username: String
let timestampName: String
let userImageName: String
let postImageName: String
let postID: String
}
struct TextPost {
let numberOfComments: Int
let username: String
let timestampName: String
let userImageName: String
let textName: String
let postID: String
}
struct MixedPhoto {
let numberOfComments: Int
let username: String
let timestampName: String
let userImageName: String
let textName: String
let postImageName: String
let postID: String
}
Note
Right now I ordered every Cell type in its own section to be able to display them all, but this isnt a long-term solution for me. I want to have them all in only one section.
Here is another solution:
After reading Paul & Rikh's answer, I thought about this other solution.
You can have one Post model defined as follows:
struct Post {
let numberOfComments: Int
let username: String
let timestampName: String
let userImageName: String
let postImageName: String?
let textName: String?
let postID: String
}
Notice how postImageName and textName are both optionals. That will help you distinguish among post types.
Next, you want to declare a variable allPosts of type [Post]:
var allPosts = [Post]()
And you need to feed it to your tableView:
func numberOfSections(in tableView: UITableView) -> Int {
return 1 // You only need one section. You can't omit this function btw.
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return allPosts.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let post = allPosts[indexPath.row]
if post.postImageName != nil && post.textName != nil {
let cell = tableView.dequeueReusableCell(withIdentifier: mixedTableViewCell.identifier, for: indexPath) as! mixedTableViewCell
cell.configure(with: post)
return cell
}
else if post.postImageName != nil {
let cell = tableView.dequeueReusableCell(withIdentifier: popularTableViewCell.identifier, for: indexPath) as! popularTableViewCell
cell.configure(with: post)
return cell
}
else if post.textName != nil {
let cell = tableView.dequeueReusableCell(withIdentifier: textTableViewCell.identifier, for: indexPath) as! textTableViewCell
cell.configure(with: post)
return cell
}
return UITableViewCell() // default: return empty cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "commentsVC")
vc.modalPresentationStyle = .fullScreen
self.navigationController?.pushViewController(vc, animated: true)
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
Finally, inside your gettingPosts function, you can assign each item to allPosts, and before reloading your tableView, you can sort allPosts by timestamp (and don't forget to call reloadData from the main thread):
self.allPosts.sort(by: { $0.timestampName > $1.timestampName })
DispatchQueue.main.async {
self.tableView.reloadData()
}
EDIT: Inside your gettingPosts function you need to feed the values to your Post struct rather than the previous model you had.
let post = Post(numberOfComments: 0, username: Name, timestampName: time, userImageName: pfp, textName: text as? String, postImageName: pic as? String, postID: pid)
self.allPosts.append(dasDing)
One more remark: there has to be a better way to do this. Why not decode your JSON instead? This can become messy if you got several types of posts. If you post your JSON structure, maybe we can help you figure out a better solution.
You can do that, but you have to declare an array allPosts of type Any:
var allPosts = [Any]()
And you need to feed it to your tableView:
func numberOfSections(in tableView: UITableView) -> Int {
return 1 // You only need one section. You can't omit this function btw.
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return allPosts.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let mixedPhoto = allPosts[indexPath.row] as? MixedPhoto {
let cell = tableView.dequeueReusableCell(withIdentifier: mixedTableViewCell.identifier, for: indexPath) as! mixedTableViewCell
cell.configure(with: mixedPhoto)
return cell
}
else if let photoPost = allPosts[indexPath.row] as? PhotoPost {
let cell = tableView.dequeueReusableCell(withIdentifier: popularTableViewCell.identifier, for: indexPath) as! popularTableViewCell
cell.configure(with: photoPost)
return cell
}
else if let textPost = allPosts[indexPath.row] as? TextPost {
let cell = tableView.dequeueReusableCell(withIdentifier: textTableViewCell.identifier, for: indexPath) as! textTableViewCell
cell.configure(with: textPost)
return cell
}
return UITableViewCell() // default: return empty cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "commentsVC")
vc.modalPresentationStyle = .fullScreen
self.navigationController?.pushViewController(vc, animated: true)
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
Finally, inside your gettingPosts function, you can assign each item to allPosts since it is of type any, and before reloading your tableView, you can sort allPosts by timestamp (and don't forget to call reloadData from the main thread):
self.allPosts.sort(by: { $0.timestampName > $1.timestampName })
DispatchQueue.main.async {
self.tableView.reloadData()
}
You have three different lists maintained. To order all of them, you will have to combine them in one list. Now all of your models have majority of the data common. You can combine them into one protocol and have all your subsequent models conform to that protocol. Something like this:
protocol Post{
var numberOfComments: Int { get set }
var username: String {get set}
var timestampName: String {get set}
var userImageName: String {get set}
}
struct PhotoPost : Post{
var numberOfComments: Int
var username: String
var timestampName: String
var userImageName: String
let postImageName: String
let postID: String
}
struct TextPost : Post { ... }
struct MixedPhoto : Post { ... }
And inside your UIViewController you should have one list.
var oneListToRuleThemAll = [Post]()
func gettingPosts(){
snapshot.documentChanges.forEach{
//blah blah blah
oneListToRuleThemAll.append(PhotoPost(...))
}
//sort by timestamp and reload the table!
}
Or as Paul suggests in his comment, you can go the class (inheritance) route too! To avoid having to write the variables again inside each subclass (But you cannot use structs with that and will have to change everything to classes).

How to get row index from UITableView which the array list made by append to a class

How to get row index from UITableView which the array list made by append to a Object Class.
And I want to get the row index based on the value from the object, I needed that for scroll to a row which I only know a value from object, but don't know which the row index.
Below is the code for create a array and show to the UITableView.
let paging: Int
let obj: Any
var currentAyaPlaying: Int?
var listArr = [] as [Any]
override func viewDidLoad() {
super.viewDidLoad()
tableView.estimatedRowHeight = 700
tableView.rowHeight = UITableView.automaticDimension
tableView.allowsSelection = true
if paging == Paging.SURA {
let sura = obj as! Sura
listArr.append(Sura(sura.index, sura.start, sura.ayas, sura.type, sura.img, sura.name, sura.translate))
for aya in 1...sura.ayas {
listArr.append(Mark(sura.index, aya))
}
} else if (paging == Paging.JUZ){
let juz = obj as! Juz
for suras in juz.sura_start...juz.sura_end {
let sura = MetaData().mSuras[suras - 1]
if juz.sura_start == suras {
for aya in juz.aya_start...(juz.sura_end == suras ? juz.aya_end : sura.ayas) {
listArr.append(Mark(suras, aya))
}
} else if juz.sura_end == suras {
listArr.append(Sura(sura.index, sura.start, sura.ayas, sura.type, sura.img, sura.name, sura.translate))
for aya in 1...juz.aya_end {
listArr.append(Mark(suras, aya))
}
} else {
listArr.append(Sura(sura.index, sura.start, sura.ayas, sura.type, sura.img, sura.name, sura.translate))
for aya in 1...sura.ayas {
listArr.append(Mark(suras, aya))
}
}
}
}
NotificationCenter.default.addObserver(self, selector: #selector(appearNotifAudioReload(_:)), name: NSNotification.Name(rawValue: NotifKey.actAudioReloadFromParentToChild), object: nil)
}
#objc func appearNotifAudioReload(_ notification: Notification) {
guard let sura = notification.userInfo?["sura"] as? Int else { return }
guard let aya = notification.userInfo?["aya"] as? Int else { return }
print("sura: \(sura)")
print("aya: \(aya)")
self.currentAyaPlaying = aya
if paging == Paging.SURA {
let indexPath = NSIndexPath(row: self.currentAyaPlaying!, section: 0)
tableView.scrollToRow(at: indexPath as IndexPath, at: .top, animated: true)
} else if paging == Paging.JUZ {
let IStackInHere = Mark(sura, aya) // how to get the row index from this data?
let indexPath = NSIndexPath(row: IStackInHere, section: 0)
tableView.scrollToRow(at: indexPath as IndexPath, at: .top, animated: true)
}
tableView.reloadData()
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return listArr.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if (listArr[indexPath.row] as? Sura) != nil {
tableView.register(UINib(nibName: identifierAyaHeader, bundle: Bundle.main), forCellReuseIdentifier: identifierAyaHeader)
let cell = tableView.dequeueReusableCell(withIdentifier: identifierAyaHeader, for: indexPath) as! AyaCellHeader
let data = listArr[indexPath.row] as! Sura
cell.configureWithData(data)
return cell
}
tableView.register(UINib(nibName: identifierAya, bundle: Bundle.main), forCellReuseIdentifier: identifierAya)
let cell = tableView.dequeueReusableCell(withIdentifier: identifierAya, for: indexPath) as! AyaCell
let data = listArr[indexPath.row] as! Mark
cell.configureWithData(data)
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if (listArr[indexPath.row] as? Mark) != nil {
tableView.deselectRow(at: indexPath, animated: false)
let mark = listArr[indexPath.row] as! Mark
showActionBottom(mark: mark)
}
}
I want to get it in the condition if paging == Paging.JUZ in the func appearNotifAudioReload, I just try to get it with:
let index = listArr.firstIndex{$0 === Mark(sura, aya)}
But no lucky and error
"Binary operator '===' cannot be applied to operands of type 'Any' and
'Mark'"
I know this forum is not to solve my coding problems, but right now I'm really troubled.
Thanks in advance.
You need to use == (to equal signs) to compare equality. Assuming the Mark struct conforms to Equatable, you can use the following:
let index = listArr.firstIndex { $0 as! Mark == Mark(sura, aya) }

Selected row from each section of UITableView ( Multiple Selection )

I have used tableview(grouped).
So i need to select one row from the each section of UITableviewSection.
So for that i have tableview and one submit button .So i need to check when i click on the submit button i need to check whether i have selected one row from the each section ,if not then show alert as not selected the section number.How to check?
This is my data.
{
"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"]
}
]
}
QuestionModel:-
class QuestionListModel: NSObject {
var selected = false
var dataListArray33:[NH_OptionsModel] = []
var id:Int!
var question:String!
var buttontype:String!
var options:[String]?
var v:String?
var optionsModelArray:[OptionsModel] = []
init(dictionary :JSONDictionary) {
guard let question = dictionary["question"] as? String,
let typebutton = dictionary["button_type"] as? String,
let id = dictionary["id"] as? Int
else {
return
}
if let options = dictionary["options"] as? [String]{
print(options)
print(options)
for values in options{
print(values)
let optionmodel = OptionsModel(values: values)
self.optionsModelArray.append(optionmodel)
}
}
self.buttontype = typebutton
self.question = question
self.id = id
// print(self.dataListArray33)
}
}
optionModel:-
class OptionsModel: NSObject {
var isSelected:Bool? = false
var v:String?
var values:String?
init(values:String) {
self.values = values
print( self.values)
}
ViewModel:-
func numberOfSections(tableView: UITableView) -> Int{
print((datasourceModel.dataListArray?.count)!)
return (datasourceModel.dataListArray?.count)!
}
func titleForHeaderInSection(atsection section: Int) -> NH_QuestionListModel {
return datasourceModel.dataListArray![section]
}
func numberOfRowsIn(section:Int) -> Int {
print( datasourceModel.dataListArray?[section].optionsModelArray.count ?? 0)
return datasourceModel.dataListArray?[section].optionsModelArray.count ?? 0
// return self.questionsModelArray?[section].optionsModelArray.count ?? 0
}
func datafordisplay(atindex indexPath: IndexPath) -> NH_OptionsModel{
print(datasourceModel.dataListArray![indexPath.section].optionsModelArray[indexPath.row])
return datasourceModel.dataListArray![indexPath.section].optionsModelArray[indexPath.row]
}
func question(answer:String) {
print(questions)
questions.append(answer)
print(questions )
}
func questionlist(answer:String) {
print( questionlist )
questionlist.append(answer)
print( questionlist )
}
func answer(answer:String) {
answers.append(answer)
print(answers)
}
and finally viewController:-
func numberOfSections(in tableView: UITableView) -> Int {
return questionViewModel.numberOfSections(tableView: tableView)
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let identifier = "HeaderCell"
var headercell: questionheader! = tableView.dequeueReusableCell(withIdentifier: identifier) as? questionheader
if headercell == nil {
tableView.register(UINib(nibName: "questionheader", bundle: nil), forCellReuseIdentifier: identifier)
headercell = tableView.dequeueReusableCell(withIdentifier: identifier) as? NH_questionheader
}
headercell.setReviewData(reviews:questionViewModel.titleForHeaderInSection(atsection:section))
return headercell
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 150
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return questionViewModel.numberOfRowsIn(section: section)
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let identifier = "Cell"
var cell: QuestionListCell! = tableView.dequeueReusableCell(withIdentifier: identifier) as? QuestionListCell
if cell == nil {
tableView.register(UINib(nibName: "QuestionListCell", bundle: nil), forCellReuseIdentifier: identifier)
cell = tableView.dequeueReusableCell(withIdentifier: identifier) as? NH_QuestionListCell
}
cell.contentView.backgroundColor = UIColor.clear
let questionsModel = questionViewModel.titleForHeaderInSection(atsection:indexPath.section)
print(questionsModel.buttontype)
questionViewModel.button = questionsModel.buttontype
cell.setOptions(Options1: questionViewModel.datafordisplay(atindex: indexPath))
print("Section \(indexPath.section), Row : \(indexPath.row)")
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){
print("Section \(indexPath.section), Row : \(indexPath.row)")
let cell = tableview.cellForRow(at: indexPath) as? NH_QuestionListCell
let model = questionViewModel.datafordisplay(atindex: indexPath)
print(model.isSelected)
cell?.setOptions(OptionsSelected:questionViewModel.datafordisplay(atindex: indexPath))
print(model.isSelected)
questionViewModel.isselected = model.isSelected!
let section = indexPath.section
let index = indexPath.row
print(section)
print(index)
if !questionViewModel.selectedIndexPaths.contains(indexPath) {
questionViewModel.selectedIndexPaths.append(indexPath)
print(questionViewModel.selectedIndexPaths.append(indexPath))
let questionModel = questionViewModel.titleForHeaderInSection(atsection: section)
print(questionModel.question)
questionViewModel.question = questionModel.question
questionViewModel.questionlist(answer: questionViewModel.question!)
let cell = tableview.cellForRow(at: indexPath) as? NH_QuestionListCell
let model = questionViewModel.datafordisplay(atindex: indexPath)
print(model.values)
questionViewModel.answer(answer: model.values!)
let value: Int = questionModel.id
let string = String(describing: value)
//let x: Int? = Int(model.id)
questionViewModel.question_id = string
questionViewModel.question(answer: questionViewModel.question_id!)
print(questionModel.id)
// append the selected index paths
} // if indexPath.section == section {
// questionViewModel.indexPath(indexPaths: index)
// }
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
if let index = questionViewModel.selectedIndexPaths.index(of: indexPath) {
print(index)
questionViewModel.selectedIndexPaths.remove(at: index)
}
}
According to this i got the output .
But i have button action in viewcontroller.
#IBAction func forward(_ sender: AnyObject) {
}
In this button action i need to check whether from each section did i selected one row or not .if not show alert .How to do
my current didselect method :-
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){
let cell = tableview.cellForRow(at: indexPath) as? NH_QuestionListCell
let model = questionViewModel.datafordisplay(atindex: indexPath)
print(model.isSelected)
cell?.setOptions(OptionsSelected:questionViewModel.datafordisplay(atindex: indexPath))
print(model.isSelected)
questionViewModel.isselected = model.isSelected!
let section = indexPath.section
let index = indexPath.row
print(section)
print(index)
if !questionViewModel.selectedIndexPaths.contains(indexPath) {
questionViewModel.selectedIndexPaths.append(indexPath)
print(questionViewModel.selectedIndexPaths.append(indexPath))
let questionModel = questionViewModel.titleForHeaderInSection(atsection: section)
print(questionModel.question)
questionViewModel.question = questionModel.question
questionViewModel.questionlist(answer: questionViewModel.question!)
let cell = tableview.cellForRow(at: indexPath) as? NH_QuestionListCell
let model = questionViewModel.datafordisplay(atindex: indexPath)
print(model.values)
questionViewModel.answer(answer: model.values!)
let value: Int = questionModel.id
let string = String(describing: value)
//let x: Int? = Int(model.id)
questionViewModel.question_id = string
questionViewModel.question(answer: questionViewModel.question_id!)
print(questionModel.id)
}
I have 3 array
According to this didselect method:-
ex:-for section 1 :-i selected 1st row so the data append as below.
questionlist:["How r u?"]
answelist:["fine"]
But suppose i think that i need 2nd indexpath ,so i need to remove the previous appended data from arrays and append the current data .As below:
questionlist:["How r u?"]
answelist:["not well"]
And next for section 2 : i selected 1st indexpath.row data .then that data is append.So i need to get as below:-
questionlist:["How r u?","Gender"]
answelist:["not well","Male"]
Here selecting i think that i need the 2nd option then remove the added indexpath.row data from array and show as:-
questionlist:["How r u?","Gender"]
answelist:["not well","Female"]
Such way how to set?
you can update your model based on the selection like
"data":[
{
"question": "Gender",
"options": ["Male","Female"],
"optionSelected": "Male"
}
]
and on Submit , check data for selections
The table view has a property to get selected index paths. You can use all native components for that. What you need is to deselect an item at index path where one is already selected in a certain section. You also just need to then check that the number of selected index paths is the same as number of arrays in your data source.
Check something like this:
var dataSource: [[Any]]!
var tableView: UITableView!
func didSelectRowAt(_ indexPath: IndexPath) {
guard let selectedPaths = tableView.indexPathsForSelectedRows else { return } // We need to have selected paths
guard selectedPaths.contains(indexPath) == false else { return } // The same cell being selected
let previouslySelectedCellIndexPaths: [IndexPath] = selectedPaths.filter { $0.section == indexPath.section && $0 != indexPath } // Getting all selected index paths within this section
previouslySelectedCellIndexPaths.forEach { tableView.deselectRow(at: $0, animated: true) } // Deselect waht was previously selected
}
/// Will return array of selected objects only if all sections have a selected index
///
/// - Returns: A result array
func getSelectionData() -> [Any]? {
guard let selectedPaths = tableView.indexPathsForSelectedRows else { return nil } // We need to have selected paths
guard selectedPaths.count == dataSource.count else { return nil } // This should prevent missing selections assuming all index paths are unique in sections
return selectedPaths.map { dataSource[$0.section][$0.row] } // Map selected index paths back to objects
}
I tried to use kind of minimum code to show all of this. It is all commented so you can see row by row what goes on.
You might want to check is all sections are unique the second method but it is not needed if the first one is always used.
You can store selected indexPath in an array. OnClick of submit just loop through array and check either at least one element is from each section.
FYI : indexPath contains section info also.
Declare an mutable array and allocate in viewDidLoad.
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[anArray addObject:indexPath];
}
on Submit action follow this, you can improvise based on your requirement
-(void)onSubmitAction{
[anArray addObject:indexPath];
NSMutableArray *countOfSection=[[NSMutableArray alloc]init];
for (NSIndexPath*indexPath in anArray ) {
if(![anArray containsObject:indexPath.section])
[countOfSection addObject:indexPath.section];
}
if(countOfSection.count == self.tableview.numberOfSections){
//write your code
}else{
// show alert
}
}
Step 1 : Create Global Variable
var selectedIndexPaths = [IndexPath]()
Step 2: Add UITableView Property
tableView.allowsMultipleSelection = true
Step 3 : Implement the delegate methods
//On Selection
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let selectedIndexPathAtCurrentSection = selectedIndexPaths.filter({ $0.section == indexPath.section})
for indexPath in selectedIndexPathAtCurrentSection {
tableView.deselectRow(at: indexPath, animated: true)
if let indexOf = selectedIndexPaths.index(of: indexPath) {
selectedIndexPaths.remove(at: indexOf)
}
}
selectedIndexPaths.append(indexPath)
}
// On DeSelection
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
if let index = selectedIndexPaths.index(of: indexPath) {
selectedIndexPaths.remove(at: index)
}
}
Step 4: Getting Selected IndexPaths with sections
#IBAction func forward(sender:Any){
let totalSections = questionViewModel.numberOfSections(tableView: tableView)
for section in 0..<totalSections {
if (selectedIndexPaths.filter({ $0.section == section}).count >= 1) {
continue
} else {
// Show alert
print("Please select item at",(section))
return
}
}
}

Tapped cell in UITableView returns label text from last cell out of an array not the chosen one

I have fixed my earlier problem and have now worked out where the main problem is, I am pulling in a json array with alamofire but am not sure how to properly move the data from one viewcontroller to another. If I hardcode the array with var name = ["Hello", "Goodbye"] I can get it to work but am not sure how to do it with the json. Thank you to any and all help.
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
let URL_GET_DATA = "http://www.localnewsplus.com.au/ios/service.php"
#IBOutlet weak var tableViewHeroes: UITableView!
var heroes = [Hero]()
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return heroes.count
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! ViewControllerTableViewCell
let hero: Hero
hero = heroes[indexPath.row]
cell.labelName.text = hero.name
cell.labelTeam.text = hero.team
Alamofire.request(hero.imageUrl!).responseImage { response in
if let image = response.result.value {
cell.heroImage.image = image
}
}
//cell.labelName.text = name[indexPath.row]
return cell
}
override func viewDidLoad() {
super.viewDidLoad()
Alamofire.request(URL_GET_DATA).responseJSON { response in
if let json = response.result.value {
let heroesArray : NSArray = json as! NSArray
for i in 0..<heroesArray.count{
self.heroes.append(Hero(
name: (heroesArray[i] as AnyObject).value(forKey: "st_heading") as? String,
team: (heroesArray[i] as AnyObject).value(forKey: "st_modified") as? String,
imageUrl: (heroesArray[i] as AnyObject).value(forKey: "imageurl") as? String
))
}
self.tableViewHeroes.reloadData()
}
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let vc = storyboard?.instantiateViewController(withIdentifier: "articleViewController") as? articleViewController
vc?.article_st_heading = name[indexPath.row]
self.navigationController?.pushViewController(vc!, animated: true)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
There are 2 ways to do this
Try to get data from the array which you used in cellForRow to populate data
Let text = someArray[indexPath. Row]
Get the cell instead of the create new one in didSelect method
Let cell = table. CellForRowAt[indexPath ]
Let text = cell.text

Parsing multiple images in swift from JSON

Json has multiple images,
img1
Json has date with multiple images, I want show Date and first image of that Date in tableview, working fine.
img2
Note :
when click any cell in tableview, display that Date with all images in collection view, But am parsing only first image of that Date,that image only showing in collection view
how to parse all images from Json and pass to collection view from tableview, and display images into collocation view
img3
this is the code ...
json Code
if errorCode == "0" {
if let Media_list = jsonData["events"] as? [Any] {
self.Mediainfo.removeAll()
for i in 0 ..< Media_list.count {
if let MediaEventData = Media_list[i] as? [String: Any] {
var eventImages = MediaEventData["eventImages"] as? [[String: Any]]
if (eventImages?.count)! > 0 {
let bannerImage = eventImages?[0]["bannerImage"] as? String
print(bannerImage as Any)
self.imageUrl = self.url+"/images/events/" + String(describing: bannerImage!)
self.Mediainfo.append(MediaEvent(
eventId: MediaEventData["eventId"]as?String,
date: MediaEventData["date"]as?String,
eventname: MediaEventData["eventName"]as?String,
bannerImages: self.imageUrl
)
)
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Media", for: indexPath)as! MediaCustomTableViewCell
let row = indexPath.row
let media = Mediainfo[row] as MediaEvent
cell.DisplayDate.text = media.date
cell.DisplayName.text = media.eventName
cell.selectionStyle = .none
cell.DisplayImage.downloadImageFrom(link:media.bannerImages, contentMode: UIViewContentMode.scaleAspectFit)
return cell
}
override func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return CGFloat.leastNormalMagnitude
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
let media = Mediainfo[(indexPath.row)] as MediaEvent
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let tabBarController = storyboard.instantiateViewController(withIdentifier: "IMAGEVID") as! UITabBarController
if let viewControllers = tabBarController.viewControllers,
let imageController = viewControllers.first as? ImagesCollectionViewController {
imageController.RecivedData1 = media.bannerImages
}
navigationController?.pushViewController(tabBarController, animated: true)
}
collection view Code :
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! ImageCollectionViewCell
cell.ImageviewCell.downloadImageFrom(link:nameofImages[indexPath.row], contentMode: UIViewContentMode.scaleAspectFit)
return cell
}
pls help me......!
u can do soemthing like this
let eventImages = MediaEventData["eventImages"] as? [[String: Any]]
if (eventImages?.count)! > 0 {
for i in 0...eventImages.count{
let bannerImage = eventImages?[i]["bannerImage"] as? String
self.imageUrl = self.url+"/images/events/" + String(describing: bannerImage!)
self.Mediainfo.append(bannerImage)
// or like u did u can append to array
self.Mediainfo.append(MediaEvent(
eventId: MediaEventData["eventId"]as?String,
date: MediaEventData["date"]as?String,
eventname: MediaEventData["eventName"]as?String,
bannerImages: self.imageUrl
)
} }
In didselect
let media = Mediainfo[(indexPath.row)] as MediaEvent
imageController.RecivedData1 = media.bannerImages
Your doing like this Means Your are slecting a particular cell and
that index your are passing to NextVC.
if you want to show all images You should pass complete array to
nextvc
You should declare a array of same type Mediainfo array in Next VC
and do like
EX: imageController.array = Mediainfo

Resources