In first VC I have an array with images (which I picked - array.append) which goes over prepareforsegue to another VC with tableview, and tableview reads that array and everything works, however when going back from tableview to first VC to pick another set of images (array.append) tableview is populating cells with set of previous picked images, because array have previous picked images. How could I make that tableview remember only the last added images.
ViewController
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var image1: UIImageView!
#IBOutlet weak var image2: UIImageView!
#IBOutlet weak var image3: UIImageView!
#IBOutlet weak var label1: UILabel!
#IBOutlet weak var label2: UILabel!
#IBOutlet weak var label3: UILabel!
var array = [UIImage]()
var array2 = [String]()
var number = 0
#IBAction func gamb(sender: UIButton) {
}
#IBAction func gamb2(sender: UIButton) {
array.append(self.image2.image!)
array2.append(self.label2.text!)
}
#IBAction func gamb3(sender: AnyObject) {
array.append(self.image1.image!)
array2.append(self.label1.text!)
}
#IBAction func gamb4(sender: UIButton) {
array.append(self.image3.image!)
array2.append(self.label3.text!)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let destVC = segue.destinationViewController as! TableViewController
let priljepak = self.array
destVC.array = priljepak
let priljepak2 = self.array2
destVC.array2 = priljepak2
}
}
TableViewController
import UIKit
class TableViewController: UIViewController,UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var tableView: UITableView!
var array = [UIImage]()
var array2 = [String]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return array.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)
cell.imageView?.image = array[indexPath.row]
cell.textLabel!.text = array2[indexPath.row]
return cell
}
}
In the first ViewController, override viewWillAppear. Call super and empty the arrays.
override func viewWillAppear(animated:bool) {
super.viewWillAppear(animated)
array = [UIImage]()
array2 = [String]()
}
This'll cause any selection to be removed when returning to the first VC.
Insert the following override into your ViewController:
override func viewWillAppear(animated: Bool){
super.viewWillAppear(animated)
array.removeAll()
array2.removeAll()
}
This will clean the arrays in your first view controller, when TableViewController is dismissed.
Related
How to pass data from view controller to table view controller? and also how to store the selected data to the table view controller? but The output shows multiple row, how to make it based on the user click at the bag? and how to pass the data inside it?
! ]2
Here my Item Detail View Controller
import UIKit
class ItemDetailViewController: UIViewController {
var items = [item]()
var name : String = ""
var price : String = ""
var imagee : String = ""
#IBOutlet weak var labelname: UILabel!
#IBOutlet weak var image: UIImageView!
#IBOutlet weak var labelprice: UILabel!
//here the button to add to the table view
#IBAction func addtobag(_ sender: Any) {
let viewController = storyboard?.instantiateViewController(withIdentifier: "BagViewController") as? BagViewController
viewController?.name = self.name
viewController?.imagee = self.imagee
viewController?.price = self.price
viewController?.items = self.items
navigationController?.pushViewController(viewController!, animated: true)
}
override func viewDidLoad() {
super.viewDidLoad()
labelname.text = name
labelprice.text = price
image.image = UIImage(named: imagee)
}
}
And here my Bag View Controller
import UIKit
class BagViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var totalprice: UILabel!
#IBOutlet weak var tableview: UITableView!
var items = [item]()
var name : String = ""
var price : String = ""
var imagee : String = ""
override func viewDidLoad() {
super.viewDidLoad()
tableview.delegate = self
tableview.dataSource = self
// Do any additional setup after loading the view.
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return name.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath as IndexPath) as! ShoppingTableViewCell
return cell
}
}
and here my Shopping Table View
import UIKit
class ShoppingTableViewCell: UITableViewCell {
#IBOutlet weak var dfs: UIImageView!
#IBOutlet weak var labelname: UILabel!
#IBOutlet weak var labelprice: UILabel!
#IBOutlet weak var stepperlabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
#IBAction func stepper(_ sender: UIStepper) {
stepperlabel.text = String(Int(sender.value))
}
}
I think your logic is kind of bad, you're instantiating a VC in code but you have a segue, I recommend you pass data through the prepare function:
// MARK: - Navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
if let vc = segue.destination as? BagViewController {
vc.name = self.name
vc.imagee = self.imagee
vc.price = self.price
vc.items = self.items
}
// Pass the selected object to the new view controller.
}
And in your addtobag IBAction you just will call the segue, I recommend you to use a String based segue extension String+PerformSegue.swift it lets you easily perform segue in a given ViewController like this:
#IBAction func addtobag(_ sender: Any) {
"nameOfTheSegue".performSegue(on: self)
// If you don't want to use String+PerformSegue.swift uncomment
// the next line and comment the last one.
// self.performSegue(withIdentifier: "nameOfTheSegue", sender: nil)
}
I have a UI as given below and when i click save button in UI i want to add three values on top of the view to a table view, in which has three different labels for representing them and a custom structure to define the model. But my problem is that i can only append one element but what i want is to keep previously added elements in that array and show them in a tableView.
Here is the UI image
Here is the code:
MainViewController.swift
class MainViewController: UIViewController {
#IBOutlet weak var minDbLabel: UILabel!
#IBOutlet weak var averageDbLabel: UILabel!
#IBOutlet weak var maximumDbLabel: UILabel!
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "saveRecord" {
let recordVC = segue.destination as! RecordTableViewController
recordVC.record.minimumValue = (minDbLabel.text! as NSString).floatValue
recordVC.record.averageValue = (averageDbLabel.text! as NSString).floatValue
recordVC.record.maximumValue = (maximumDbLabel.text! as NSString).floatValue
recordVC.recordsArray.append(recordVC.record)
}
}
#IBAction func save(_ sender: UIButton){
self.performSegue(withIdentifier: "saveRecord", sender: nil)
}
}
RecordTableViewController.swift:
class RecordCell: UITableViewCell {
#IBOutlet weak var dateLabel: UILabel!
#IBOutlet weak var minimumValueLabel: UILabel!
#IBOutlet weak var averageValueLabel: UILabel!
#IBOutlet weak var maximumValueLabel: UILabel!
}
class RecordTableViewController: UITableViewController {
let cellIdentifier: String = "cellID"
var recordsArray = [Record]()
var record: Record = Record()
override var shouldAutorotate: Bool {
return false
}
override func viewDidLoad() {
super.viewDidLoad()
let swipe = UISwipeGestureRecognizer(target: self, action: #selector(swipeRight(_:)))
swipe.direction = .right
self.view.addGestureRecognizer(swipe)
tableView.insertRows(at: [IndexPath(row: recordsArray.count - 1, section: 0)], with: .automatic)
tableView.reloadData()
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return recordsArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! RecordCell
cell.minimumValueLabel.text = "\(recordsArray[indexPath.row].minimumValue)"
cell.averageValueLabel.text = "\(recordsArray[indexPath.row].averageValue)"
cell.maximumValueLabel.text = "\(recordsArray[indexPath.row].maximumValue)"
return cell
}
}
Record.swift
struct Record {
var minimumValue: Float = .nan
var averageValue: Float = .nan
var maximumValue: Float = .nan
}
Thanks in advance.
Note: I already have searched on Google to find an answer but to no avail.
you should append the data in recordsArray in MainViewController first before performing the segue. See the code below
class MainViewController: UIViewController {
#IBOutlet weak var minDbLabel: UILabel!
#IBOutlet weak var averageDbLabel: UILabel!
#IBOutlet weak var maximumDbLabel: UILabel!
var recordsArray = [Record]()
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "saveRecord" {
let recordVC = segue.destination as! RecordTableViewController
var record = Record()
record.minimumValue = Float(minDbLabel.text!) ?? 0.0
record.averageValue = Float(averageDbLabel.text!) ?? 0.0
record.maximumValue = Float(maximumDbLabel.text!) ?? 0.0
self.recordsArray.append(record)
recordVC.recordsArray = self.recordsArray
}
}
#IBAction func save(_ sender: UIButton){
self.performSegue(withIdentifier: "saveRecord", sender: nil)
}
}
Just replace your MainViewController with the code above and it should work.
When i click table view cell click event not working. I am assigned the data to view in custom tableView cell class and passed the value from viewController class. Is there is any problem in assigning data to views in custom table view cell class
ViewController.class
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = self.ViewAllTableView.dequeueReusableCell(withIdentifier: "ViewAllTableViewCell", for: indexPath) as! ViewAllTableViewCell
let products = self.allProducts[indexPath.row]
cell.setData(products: products)
cell.delegate = self
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "allDetail", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destination = segue.destination as? ProductDetailViewController{
let products = self.allProducts[(ViewAllTableView.indexPathForSelectedRow?.row)!]
destination.productID = products.id
}
}
This is Custom Table View Cell class
ViewAllTableViewCell.class
class ViewAllTableViewCell: UITableViewCell {
#IBOutlet weak var ItemImage: UIImageView!
#IBOutlet weak var ItemName: UILabel!
#IBOutlet weak var ItemOfferPrice: UILabel!
#IBOutlet weak var ItemOriginalPrice: UILabel!
#IBOutlet weak var ItemWeight: UILabel!
#IBOutlet weak var ItemCountLabel: UILabel!
var delegate : ViewAllTableViewCellDelegate?
var allProduct: ViewAllProductsData!
func setData(products: ViewAllProductsData){
self.allProduct = products
self.ItemName.text = allProduct.name
self.ItemWeight.text = "\(allProduct.quantity) \(allProduct.unit)"
self.ItemOfferPrice.text = "\(allProduct.price)"
self.ItemOriginalPrice.text = "\(allProduct.originalPrice)"
self.ItemCountLabel.text = "\(allProduct.count)"
let url: URL = NSURL(string: allProduct.image)! as URL
self.ItemImage.af_setImage(withURL: url)
}
#IBAction func ViewAllMinusButton(_ sender: UIButton) {
delegate?.minusCount(data: allProduct)
}
#IBAction func ViewAllPlusbutton(_ sender: UIButton) {
delegate?.addCount(data: allProduct)
}
}
protocol ViewAllTableViewCellDelegate{
func addCount(data: ViewAllProductsData)
func minusCount(data: ViewAllProductsData)
}
It happens because either you haven't conform properly to UITableViewDelegate or you have UITapGestureRecognizer somewhere in your view controller.
It worked for me after changing tableView attribute selection from no selection to single selection
I am trying to dynamically update a tableView while the program is running. I believe I have updated the array that the data loads from correctly, but when I press the button that calls self.eventTable.reloadData() I receive the error:
fatal error: unexpectedly found nil while unwrapping an Optional value
Here is the relevant code:
View Controller:
import UIKit
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
//Timer view
#IBOutlet weak var playButton: UIBarButtonItem!;
#IBOutlet weak var pauseButton: UIBarButtonItem!;
#IBOutlet weak var refreshButton: UIBarButtonItem!;
#IBOutlet weak var timerLabel: UILabel!
var counter = 0
var timer = Timer()
var isTimerRunning = false
//testing view container
var viewShowing = 1;
override func viewDidLoad() {
// Do any additional setup after loading the view, typically from a nib.
pauseButton.isEnabled = false
hideAll();
self.basicContainer.isUserInteractionEnabled = true;
self.basicContainer.isHidden = false;
self.timerLabel.text = String("00:00:00");
eventTable.dataSource = self
eventTable.delegate = self
super.viewDidLoad()
loadEvents(event: "timer start")
}
...
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// Add table to keep track of events
#IBOutlet weak var eventTable: UITableView!
var eventData = [Session]()
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return eventData.count;
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellReuseIdentifier") as! eventTableViewCell
let event = eventData[indexPath.row]
cell.eventLabel.text = event.session
return cell
}
private func loadEvents(event: String) {
guard let event1 = Session(session: event) else {
fatalError("Unable to instantiate event")
}
eventData += [event1]
DispatchQueue.main.async() {
self.eventTable.reloadData()
}
}
func testPrint() {
loadEvents(event: "testing cell adding")
//self.eventTable.reloadData()
viewWillAppear(false)
print("This is a test print");
}
}
The function works fine when it is called in ViewDidLoad(), but not when it is called by the button in another class ("This is a test print" prints to console so I know the button call is going through).
Expected behavior is the tableView (eventTable) reloading showing two cells, "timer start" and "testing cell adding" (ideally with "testing cell adding" being at the top).
Also want to emphasize that eventTable is connected to the storyboard, which seems to be a common problem on here.
Here is the Session.swift file and the eventTableViewCell.swift file if those are helpful:
Session.swift
import Foundation
import UIKit
class Session {
//MARK: Properties
var session: String
//MARK: Initialization
init?(session: String) {
guard !session.isEmpty else {
return nil
}
self.session = session
}
}
eventTableViewCell.swift
import Foundation
import UIKit
class eventTableViewCell: UITableViewCell {
//MARK: Properties
#IBOutlet weak var eventLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
Thanks!
Edit: The ViewController from where I call testPrint().
import UIKit
class BasicViewController: UIViewController {
var VC = ViewController();
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//Basic buttons
#IBOutlet weak var warmButton: UIButton!
#IBOutlet weak var dryButton: UIButton!
#IBOutlet weak var stimulateButton: UIButton!
#IBOutlet weak var controlButton: UIButton!
#IBOutlet weak var bedButton: UIButton!
#IBOutlet weak var tempButton: UIButton!
#IBOutlet weak var pulseButton: UIButton!
#IBOutlet weak var ecgButton: UIButton!
#IBOutlet weak var apgarButton: UIButton!
#IBOutlet weak var helpButton: UIButton!
//APGAR options
#IBOutlet weak var skinColor: UIButton!
#IBOutlet weak var pulse: UIButton!
#IBOutlet weak var grimace: UIButton!
#IBOutlet weak var flexion: UIButton!
#IBOutlet weak var respiratoryEffort: UIButton!
#IBAction func warmButton(sender: AnyObject) {
VC.testPrint();
}
}
It would seem that you are all right in stating that I am instantiating a new ViewController which is causing the issue. How should I go about fixing this? Fairly new to Swift
I think, your problem is in this lines of codes:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellReuseIdentifier") as! eventTableViewCell
let event = eventData[indexPath.row]
cell.eventLabel.text = event.session
return cell
}
Can you check the cell identifier is same as your cell identifier
And number of rows in eventData array
I have a button on my custom tableview cell that is showing the users name. When you click on it, you should be taken to his/her profile but nothing happens?
Here is my custom tableview cell class (commentsTableViewCell.swift) :
import UIKit
protocol commentsTableViewCellDelegate {
func namesIsTapped(cell: commentsTableViewCell)
}
class commentsTableViewCell: UITableViewCell {
#IBOutlet weak var nameButton: UIButton!
#IBOutlet weak var commentLabel: UILabel!
#IBOutlet weak var profilePic: UIImageView!
#IBOutlet weak var dateLabel: UILabel!
#IBOutlet weak var uidLabel: UILabel!
var delegate: commentsTableViewCellDelegate?
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
#IBAction func nameIsTapped(sender: AnyObject) {
//4. call delegate method
//check delegate is not nil
if let _ = delegate {
delegate?.namesIsTapped(self)
} else {
print("Delegate is \(delegate)")
}
}
}
Here is the important part of commentsTableViewController.swift:
class commentsTableViewController: UITableViewController, commentsTableViewCellDelegate, UITextViewDelegate {
#IBOutlet weak var commentLabel: UITextView!
#IBOutlet weak var theLabel: UILabel!
var dataGotten = "Nothing"
var updates = [CommentSweet]()
func namesIsTapped(cell: commentsTableViewCell) {
//Get the indexpath of cell where button was tapped
//let indexPath = self.tableView.indexPathForCell(cell)
let allDataSend = cell.nameButton.titleLabel?.text!
self.performSegueWithIdentifier("toDetailtableViewController", sender: allDataSend)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "toDetailtableViewController" {
if let nextVC = segue.destinationViewController as? theProfileTableViewController {
nextVC.viaSegue = sender! as! String
}
}
}
override func viewDidLoad() {
Kindly set the delegate to self.
In cellforRowIndexPath
commentsTableViewCell.delegate = self
Where commentsTableViewCell is the custom UITableViewCell object
I suggest to handle the action of the cell's button in the viewController. You can recognize which button has been tapped by setting a tag for it.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") as! TableViewCell
cell.myButton?.tag = indexPath.row
cell.myButton?.addTarget(self, action: #selector(), for: .touchUpInside)
return cell
}
func namesIsTapped(tappedButton: UIButton) {
// get the user (from users array for example) by using the tag, for example:
let currentUser = users[tappedButton.tag]
// do whatever you want with this user now...
}