Passing UITableViewCell Data from Firebase populated array - ios

I have a tableview that loads database info from Firebase and the image pulls from Firebase storage with my hardcoded directory/file.
I want the value of cell.videoID.text so that I can pass it to another viewcontroller via Segue. I just can't seem to get the value of cell.videoID.text when the cell is clicked and have tried all sorts of ways from this and other sites.
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return vehicleList.count
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! ViewControllerTableViewCell
let vehicle: VehicleModel
vehicle = vehicleList[indexPath.row]
cell.videoID.text = vehicle.id
cell.neworusedLabel.text = vehicle.neworused
cell.yearLabel.text = vehicle.year
cell.priceLabel.text = vehicle.price
cell.makeLabel.text = vehicle.make
cell.modelLabel.text = vehicle.model
cell.packageLabel.text = vehicle.package
cell.colorLabel.text = vehicle.color
// Get the image from storage container
let storage = Storage.storage().reference()
let imagePath = "tmpDir/tmpImage.png"
let tempImageRef = storage.child(imagePath)
tempImageRef.getData(maxSize: 1 * 600 * 600) { data, error in
if error == nil {
cell.lblView.image = UIImage(data: data!)
} else {
print(error?.localizedDescription)
}
}
return cell
}
var valueToPass:String!
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// Get Cell Label
let indexPath = tableView.indexPathForSelectedRow!
let currentCell = tableView.cellForRow(at: indexPath)! as UITableViewCell
print("currentCell")
print("You selected cell #\(indexPath.row)!")
// valueToPass = "Trying to get the videoID"
performSegue(withIdentifier: "detailSegue", sender: self)
}

My answer was: valueToPass = vehicleList[indexPath.row].id
Thanks to Kosuke above in the comments!

Related

Passing TableViewCell to a new TableView (at the top) Swift

What I want to do:
I have a feed (TableView( and once the user taps on a Post (TableViewCell), he should see a new Page (TableView) with the Post he tapped on first (the same TableViewCell) on top and a couple of comments below.
My Problem:
I dont get how to "clone" that TableViewCell.
Here two pictures for a better understanding:
Some complications:
I have multiple post types in the main feed, so the code would have to differentiate between them to see which cell type to use to display the content.
My code:
Main Feed
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
}
My second ViewController
class CommentsViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet var table: UITableView!
var texty = [TextComment]()
override func viewDidLoad() {
super.viewDidLoad()
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.register(textComTableViewCell.nib(), forCellReuseIdentifier: textComTableViewCell.identifier)
table.delegate = self
table.dataSource = self
}
func numberOfSections(in tableView: UITableView) -> Int {
2
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0{
return 1
}
else{
return 15
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0{
let cell = tableView.dequeueReusableCell(withIdentifier: textTableViewCell.identifier, for: indexPath) as! textTableViewCell
return cell
}
else{
let cell = tableView.dequeueReusableCell(withIdentifier: textComTableViewCell.identifier, for: indexPath) as! textComTableViewCell
return cell
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.section == 0{
// self.table.estimatedRowHeight = 250
// self.table.rowHeight = UITableView.automaticDimension
// return UITableView.automaticDimension
return 300
}
else{
// self.table.estimatedRowHeight = 150
// self.table.rowHeight = UITableView.automaticDimension
// return UITableView.automaticDimension
return 150
}
}
Note
Right now the it isnt working at all, how I want it. I just have these "mock" posts as space-fillers in there.
Any help or ideas would be greatly appreciated!
My structs
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
}
Here my errors:
Each instance of UITableView has its own pool of cells, for this reason it would not be correct to "steal" an instance of the cell from one UITableView and put it into another. Also, as far as i can see you already have a convenient way to feed your cells with data, and dequeue corresponding types. Thus the only thing left here is to pass the required data from MainFeed under your tableView(_: didSelectRowAt:) function, something like that:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
guard let vc = storyboard.instantiateViewController(withIdentifier: "commentsVC") as? CommentsViewController else {
return
}
switch indexPath.section {
case 0:
vc.mixedData = mixed[indexPath.row]
case 1:
vc.photoData = photos[indexPath.row]
default:
vc.textData = texttt[indexPath.row]
}
vc.modalPresentationStyle = .fullScreen
navigationController?.pushViewController(vc, animated: true)
}
And then, under the CommentsViewController's tableView(_:, cellForRowAt:) function, implement pretty much the same stuff you did in MainFeed:
var mixedData: MixedPhoto?
var photoData: PhotoPost?
var textData: TextPost?
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0 {
let cell: UITableViewCell
switch (mixedData, photoData, textData) {
case (.some(let value), _, _):
cell = tableView.dequeueReusableCell(withIdentifier: mixedTableViewCell.identifier, for: indexPath) as! mixedTableViewCell
cell.configure(with: value)
case (_, .some(let value), _):
cell = tableView.dequeueReusableCell(withIdentifier: popularTableViewCell.identifier, for: indexPath) as! popularTableViewCell
cell.configure(with: value)
case (_, _, .some(let value)):
cell = tableView.dequeueReusableCell(withIdentifier: textTableViewCell.identifier, for: indexPath) as! textTableViewCell
cell.configure(with: value)
default:
fatalError("The data is not set")
}
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: textComTableViewCell.identifier, for: indexPath) as! textComTableViewCell
return cell
}
}
Also I should say that it's a good idea to implement a common protocol for your data types, so you actually can define a single non-optional variable in the CommentsViewController instead of three optionals.

swift4 uitableview retain selection

I am preparing a small app for online exams for which I need to reload the tableView for every question. Multiple selection and single selection both are needed based on question type. I was able to manage the selection type based on question type but the thing is when i reload the tableview the previous selection is replicating in the next question.
var DictItemSerialNumber = 0
let Dict = [["Question":"How many days in a week?",
"Options":["1","2","3","7"],
"QuestionType":1],
["Question":"How many days in a month?",
"Options":["28","29","30","31","32"],
"QuestionType":2],
["Question":"How many days in a Year?",
"Options":["234","265","365","400"],
"QuestionType":1]]
var SavedOptions = [String:[Any]]()
var selectedIndex:Int? = nil
override func viewDidLoad() {
super.viewDidLoad()
self.Tab.rowHeight = UITableView.automaticDimension
self.Tab.estimatedRowHeight = 300
self.Tab.tableFooterView = UIView()
self.Tab.delegate = self
self.Tab.dataSource = self
self.Tab.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
}
#IBAction func PrvsBtnActn(_ sender: UIButton) {
if DictItemSerialNumber > 0 {
DictItemSerialNumber -= 1
Tab.reloadData()
}
}
#IBAction func NextBtnActn(_ sender: UIButton) {
if DictItemSerialNumber < Dict.count-1{
DictItemSerialNumber += 1
Tab.reloadData()
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let DictObj = Dict[DictItemSerialNumber] as NSDictionary
let optionsCount = DictObj["Options"] as! NSArray
return optionsCount.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = Tab.dequeueReusableCell(withIdentifier: "cell")!
let DictObj = Dict[DictItemSerialNumber]
let qstnType = DictObj["QuestionType"] as! Int
if qstnType == 2{
self.Tab.allowsMultipleSelection = true
}else{
self.Tab.allowsMultipleSelection = false
}
QstnLbl.text = DictObj["Question"] as? String
let optionsAns = DictObj["Options"] as! NSArray
cell.textLabel?.text = optionsAns[indexPath.row] as? String
cell.selectionStyle = .none
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let cell = tableView.cellForRow(at: indexPath) {
cell.accessoryType = .checkmark
}
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
if let cell = tableView.cellForRow(at: indexPath) {
cell.accessoryType = .none
}
}
}
question type = 1 means single selection and 2 is multiple selection

Swift - Multiple TableView checkmark - save and load choice

Im trying to save and load choice from TableView Multiple checkmarks.
I have a code ready, but I don't know how to save the selection. And how to load the selection at the opening of the list.
MY CODE:
var selectedCells = [IndexPath]()
var selectedAreas = [String]()
var Areas = [] //my text for the cells..
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return Areas.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCell(withIdentifier: "cell")!
cell.textLabel?.text = Areas[indexPath.row]
cell.accessoryType = selectedCells.contains(indexPath) ? .checkmark : .none
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let selectedCell = tableView.cellForRow(at: indexPath)
selectedCells.append(indexPath)
if selectedCell?.accessoryType == .checkmark {
if let indexremove = selectedAreas.firstIndex(of: (Areas[indexPath.row])) {
selectedAreas.remove(at: indexremove)
}
selectedCell?.accessoryType = .none
print(selectedCells)
print(selectedAreas)
print("remove ")
selectedCells = selectedCells.filter {$0 != indexPath}
} else {
print(selectedCells)
print(selectedAreas)
print("add")
selectedAreas.append(Areas[indexPath.row])
selectedCell?.accessoryType = .checkmark
}
}
Don't use multiple arrays as data source. That's pretty bad practice and inefficient.
Delete them
var selectedCells = [IndexPath]()
var selectedAreas = [String]()
Declare Area as struct and add an isSelected member
struct Area {
let name : String
var isSelected : Bool
init(name : String, isSelected : Bool = false) {
self.name = name
self.isSelected = isSelected
}
}
var areas = [Area(name: "Foo"), Area(name: "Bar")]
In cellForRowAt assign the checkmark depending on isSelected
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
let area = areas[indexPath.row]
cell.textLabel?.text = area.name
cell.accessoryType = area.isSelected ? .checkmark : .none
return cell
}
In didSelectRow toggle isSelected and reload the row (yes, only two lines of code)
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
areas[indexPath.row].isSelected.toggle()
tableView.reloadRows(at: [indexPath], with: .none)
}
You get the selected areas with
let selectedAreas = areas.filter{$0.isSelected}
and an array of the names
let selectedAreaNames = areas.filter{$0.isSelected}.map{$0.name}
To load and save the names to UserDefaults add these two methods
func saveSelection()
{
let selectedAreaNames = areas.filter{$0.isSelected}.map{$0.name}
UserDefaults.standard.set(selectedAreaNames, forKey: "selectedNames")
}
func loadSelection()
{
guard let selectedAreaNames = UserDefaults.standard.array(forKey: "selectedNames") as? [String] else { return }
for (index, area) in areas.enumerated() {
areas[index].isSelected = selectedAreaNames.contains(area.name)
}
tableView.reloadData()
}

how do i create this expandable cell without nib? swift 4

hey i have a tableview with images and some text labels the whole cell is 400 in height and i want to extend it to 700 when i click the cell to make the user see more information of the cell so i wrote this code
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if isExpanded && self.selectedIndex == indexPath{
return 700
}
return 400.0
}
var selectedIndex:IndexPath?
var isExpanded = false
func didExpandCell() {
self.isExpanded = !isExpanded
self.postsTableView.reloadRows(at: [selectedIndex!], with: .automatic)
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.selectedIndex = indexPath
self.didExpandCell()
}
but this code requires a .xib file off the Cell, i have tryed to run the app without the code below but it doesnt work and i have tryed it with it and it doesnt work because i need a .xib file for the cell so i was wondering if it is possible that someone could help me with this and just explain how i can this cells epandable without this .xib file of the cell
func unnesseryNibFile(){
//this code goes in the viewDidLoad func and it is required to have a .xib file of the Cell protoype
let nib = UINib.init(nibName: "postTableViewCell", bundle: nil)
self.postsTableView.register(nib, forCellReuseIdentifier: "Cell")
}
here is my 'cellForRowAt'
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! PostTableViewCell
// Configure the cell...
let post = self.posts[indexPath.row] as! [String: AnyObject]
cell.locationLabel.text = post["location"] as? String
cell.usernameLabel.text = post["username"] as? String
cell.titleLabel.text = post["title"] as? String
cell.contentTextView.text = post["content"] as? String
if let imageName = post["image"] as? String {
let imageRef = Storage.storage().reference().child("images/\(String(describing: imageName))")
imageRef.getData(maxSize: 25 * 1024 * 1024, completion: { (data, error) -> Void in
if error == nil {
//succeful
let image = UIImage(data: data!)
cell.postImageView.image = image
}else{
//Not Succesful
print("error Downloading The Image\(String(describing: error?.localizedDescription))")
}
})
}
return cell
}
thanks for your time. :)

I have an array of dictionary and i would like to get an item from it and use it

var savedFaouritePlaces: NSMutableArray = [] //matched strings
Here is the info I get and I want to use this items cell for row at index path
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
guard let cell = tableView.dequeueReusableCell(withIdentifier: "HeartTabCell") as? HeartTabTableViewCell else {
return UITableViewCell()
}
cell.heartTabTitleLabel.text = "Wanna use that title here"
cell.heartTabImageView.image = "wanna use that image here"
return cell
}
You should use indexPath to retrieve each dictionary in that array:
let dict = savedFaouritePlaces[indexPath.row]
cell.heartTabTitleLabel.text = dict["Title"]
cell.heartTabImageView.image = UIImage(named: dict["Image"])
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCell(withIdentifier: "HeartTabCell") as? HeartTabTableViewCell
let dictionary = savedFaouritePlaces[indexPath.row]
cell.heartTabTitleLabel.text = dictionary["Title"]
cell.heartTabImageView.image = UIImage(named: dictionary["Image"])
return cell
}

Resources