How to change button title from table static cells? - ios

I have HomeViewController that's segued modally to a Navigation Controller with an identifier of: pickSubjectAction
And on SubjectPickerTableViewController is where my subjects to choose. This is my code
import UIKit
class SubjectPickerTableViewController: UITableViewController {
var subjects:[String] = [
"English",
"Math",
"Science",
"Geology",
"Physics",
"History"]
var selectedSubject:String? {
didSet {
if let subject = selectedSubject {
selectedSubjectIndex = subjects.index(of: subject)!
}
}
}
var selectedSubjectIndex:Int?
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return subjects.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "SubCell", for: indexPath)
cell.textLabel?.text = subjects[indexPath.row]
if indexPath.row == selectedSubjectIndex {
cell.accessoryType = .checkmark
} else {
cell.accessoryType = .none
}
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
//Other row is selected - need to deselect it
if let index = selectedSubjectIndex {
let cell = tableView.cellForRow(at: IndexPath(row: index, section: 0))
cell?.accessoryType = .none
}
selectedSubject = subjects[indexPath.row]
//update the checkmark for the current row
let cell = tableView.cellForRow(at: indexPath)
cell?.accessoryType = .checkmark
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "saveSelectedSubject" {
if let cell = sender as? UITableViewCell {
let indexPath = tableView.indexPath(for: cell)
if let index = indexPath?.row {
selectedSubject = subjects[index]
}
}
}
}
}
This is segued also with identifier: savedSelectedSubject.
Q1: How can i segued from button to the tableview controller?
I tried this but failed
Q2: How to changed the button titled from selected Subject?
my resources: https://www.raywenderlich.com/113394/storyboards-tutorial-in-ios-9-part-2
Any help is appreciated. Thanks

How can i segued from button to the tableview controller? I tried
this but failed
performSegueWithIdentifier expects a String format while you are sending it in Any format. Correct way for call this function is
self.performSegue(withIdentifier: "pickSubjectAction", sender: self)
How to changed the button titled from selected Subject?
I guess you want to reflect the selected subject in the controller presented after savedSelectedSubject segue. Let ViewController A be the one through which you are pushing/presenting and ViewController B be the one which is pushed/presented. Follow the following steps :
For this you need to fetch the destination controller (B) from prepare(for segue: UIStoryboardSegue, sender: Any?) function via segue.destination property.
Make a public variable in B in which you can set your selected subject.
Using that property you can show your selected subject title.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let B = segue.destination
// Assuming B's public var is named selectedSubject and is of String type
if let subject = self.selectedSubject {
B.selectedSubject = subject
}
}
In Controller B
override func viewWillAppear() {
super.viewWillAppear()
button.setTitle(self.selectedSubject, for: .normal)
}
// We already have the value of selectedSubject which we are using to set title for the button.

Related

Problem tu update tableview, Delegate Hell

first of all I'am renewing my votes with mobile dev almost 4 yeas without any code, a decided to start over new... so is like I'm a newvbie right now!!!
I'm creating a sort of restaurant app, where you can choose pizza, dinks and some other staff that i haven't decided yet.
My problems is..my main view controller I have a UIView and inside it a table view...
I've put a button (the pizza button) that has a segue to another view with a table view controller and data is plenty of pizza info. You have to choose a pizza and then DONE button witch sends data back to my main view controller and this view controller should populate the table view from the choice I've made in the view before.
This is my storyboard
My OrderTableViewController do this:
class OrderTableViewController: UITableViewController {
var orderedItems = OrderList();
override func viewDidLoad() {
super.viewDidLoad()
let noOrder = OrderItem()
noOrder.itemName = "No item Yet"
orderedItems.add(orderItem: noOrder)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true);
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return orderedItems.list.count;
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
// Configure the cell...
let row = indexPath.row
cell.textLabel?.text = orderedItems.list[row].itemName
cell.detailTextLabel?.text = orderedItems.list[row].itemSize
return cell
}
// MARK - Dev methods
func updateTable(orderList:OrderList){
// Here in this line I get que item from my other tableview
print("\(orderedItems.lastSelection) inside OrderTableView");
orderedItems = orderList;
tableView.reloadData();
}
Before call reloadData() I can see that that the result is correctly put on the orderedItem I can even print it
But the method reloadData does nothing.. the view keep showing "no items".
Maybe I misunderstood the whole protocol delegate pattern.
Can you see where is it wrong?
My MainController;
class MainController: UIViewController, PizzaViewControllerDelegate {
var orderedItems = OrderList();
var orderTableVC = OrderTableViewController()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
orderTableVC.updateTable(orderList: orderedItems);
}
func didSelectPizza(pizza: OrderItem) {
orderedItems.add(orderItem: pizza);
orderTableVC.updateTable(orderList: orderedItems);
}
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
if segue.identifier == "orderSegue" { //embedded view -- keep controller around
orderTableVC = segue.destination as! OrderTableViewController
}
if segue.identifier == "pizzaSegue"{
let pizzaViewController = segue.destination as! PizzaViewController
pizzaViewController.delegate = self
}
}
}
My protocol for pizza:
protocol PizzaViewControllerDelegate {
func didSelectPizza(pizza:OrderItem);
}
protocol PizzaTableViewControllerDelegate {
func didSelectPizzaCell(pizza:String)
}
My PizzaViewController
class PizzaViewController: UIViewController, PizzaTableViewControllerDelegate {
var pizza = OrderItem();
var delegate: PizzaViewControllerDelegate!;
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
if segue.identifier == "pizzaTableSegue" {
let vc = segue.destination as! PizzaTableViewController;
vc.delegate = self;
}
}
//IBActions
#IBAction func didCancel(_ sender: Any) {
_ = navigationController?.popViewController(animated: true);
}
#IBAction func didDone(_ sender: UIButton) {
delegate.didSelectPizza(pizza: pizza);
_ = navigationController?.popViewController(animated: true);
}
// MARK -
func didSelectPizzaCell(pizza: String) {
self.pizza.itemName = pizza;
}
}
My PizzaTableViewControlle
class PizzaTableViewController: UITableViewController {
var delegate:PizzaTableViewControllerDelegate! = nil
var pizzaMenu = PizzaMenu();
var pizza = String();
override func viewDidLoad() {
super.viewDidLoad()
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1;
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return pizzaMenu.menu.count;
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath);
let row = indexPath.row;
cell.textLabel?.text = pizzaMenu.menu[row].pizzaName;
cell.detailTextLabel?.text = pizzaMenu.menu[row].pizzaDescription;
// Configure the cell...
//Making the cell fancy
//font changes
cell.textLabel?.font = UIFont.preferredFont(forTextStyle: .headline)
cell.detailTextLabel?.font = UIFont.preferredFont(forTextStyle: .caption1)
cell.textLabel?.backgroundColor = UIColor.clear
cell.detailTextLabel?.backgroundColor = UIColor.clear
if row % 2 == 0 {
cell.backgroundColor = UIColor(white: 1.0, alpha: 0.7)
} else {
cell.backgroundColor = UIColor(white: 1.0, alpha: 0.5)
}
return cell;
}
// MARK: - TableView Delegate Methods
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
pizza = pizzaMenu.menu[indexPath.row].pizzaName;
delegate.didSelectPizzaCell(pizza: pizza);
}
///This changes cell format on the fly
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return view.frame.size.height/5.0;
}
}
I'm sure that is something I haven't understood yet.. :)
Thanks!!!

swift tableview sentence bug

I am trying to make a tableview where the user can click on the cells so the cells open a new ViewController which sets the navbar title to the clicked cell's label.
It doesn't really work for me because when I click on a cell it opens a view which has the previously clicked cell's value (not the current cells value) and then again opens a new view where the title is the current cells's value.
I uploaded the viewcontrollers to a GitHub repo: https://github.com/SiposPtr/stackoverflow
var selectedValue: String?
var numberOfFileToLoad: Int = 1
let cellak = [
"Első",
"Második",
"Harmadik",
"Negyedik",
"Ötödik",
"Hatodik",
"Hetedik",
"Nyolcadik",
"Kilencedik"
]
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return cellak.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifier", for: indexPath)
cell.textLabel?.text = cellak[indexPath.row]
// Configure the cell...
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectedValue = cellak[indexPath.row]
numberOfFileToLoad = indexPath.row + 1
performSegue(withIdentifier: "gotoSentences", sender: nil)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "gotoSentences"{
let nextViewController = segue.destination as! ButtonEditViewController
nextViewController.title = selectedValue
nextViewController.numberOfFileToLoad = numberOfFileToLoad
}
}
It seems the segue is performed twice. If you have a segue connection from a table view cell to next view controller, the segue performed immediately after the cell is selected and didSelectRowAt method will be called after that.
You can get the selected row in prepare for segue method and pass the selected data to next view controller.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "gotoSentences"{
if let nextViewController = segue.destination as? ButtonEditViewController,
let indexPath = tableView.indexPathForSelectedRow {
nextViewController.title = cellak[indexPath.row]
nextViewController.numberOfFileToLoad = indexPath.row + 1
}
}
}

Swift 4.2 - How to call "indexPath.row" from "didSelectRowAtIndexPath" method in a tableView to another class?

I have two viewControllers. One has a tableView which has some cells from an array; And the other is a viewController which contains a webkit that I want to present some local HTML files. Also I defined the webKit page as tableView's next page.
What I want is, when a user chooses a cell in the tableView, according to which cell is selected, it goes to webkit Page, and some parts of codes runs for user to show a specific HTML. In other words, I have 5 HTML files and 5 items in tableViewCells
so if a user chooses for example the first item, the HTML1 shows to him, if he chooses the second cell, the HTML2 present for him etc.
I tried a lot of ways. but nothing happened. also tried to create instance object from the tableview class...
tried also some same problem here ins StackOverFlow but not succeed
First Page:
var arr = ["masoud" , "hossein", "reza" , "shiva" , "fateme"]
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("item selected is : \(indexPath.row)")
// if indexPath.row == 1 {
performSegue(withIdentifier: "TableSegue", sender: nil)
//}
tableView.deselectRow(at: indexPath, animated: true)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
switch (segue.destination.view, segue.destination, sender) {
case let (_, controller as WebKitController, indexPath as NSIndexPath):
controller.indexPath = indexPath
break
default:
break
}
}
the Second Page:
import WebKit
class WebKitController: UIViewController, WKUIDelegate, WKNavigationDelegate {
#IBOutlet weak var myWebKit: WKWebView!
var reza : String = String()
var indexPath: NSIndexPath? {
didSet {
reza = (indexPath?.row.description)!
print(indexPath?.row as Any)
self.myWebKit.uiDelegate = self
self.myWebKit.navigationDelegate = self
}
}
override func viewDidLoad() {
super.viewDidLoad()
let url = Bundle.main.url(forResource: "reza", withExtension: "html", subdirectory: "ReZeynoo2")!
myWebKit.loadFileURL(url, allowingReadAccessTo: url)
let request = URLRequest(url: url)
myWebKit.load(request)
self.myWebKit.uiDelegate = self
self.myWebKit.navigationDelegate = self
}
As an alternative approach
I would store not a simple array but struct of name and bool is selected or not
struct CellData {
let name: String!
let isSelected: Bool!
let index: Int!
init(name: String, isSelected: Bool, index: Int) {
self.name = name
self.isSelected = isSelected
self.index = index
}
}
Then in didSelectAtRow func will make selected the cell which tapped and use this info in prepare for segue func
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.deselectAll()
self.cellItems[indexPath.row].isSelected = true
performSegue(withIdentifier: "TableSegue", sender: nil)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
switch (segue.destination.view, segue.destination, sender) {
case let (_, controller as WebKitController, indexPath as NSIndexPath):
if let item = cellItems.first(where: {$0.isSelected == true}) {
controller.indexPath = item.index
}
break
default:
break
}
}
private func deselectAll() {
for item in cellItems {
item.isSelected = false
}
}
You need to create a Int variable in WebKitController class as selectedRow where the selected row will get assigned from table view cell selection,
// MARK: - Table view delegates
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.performSegue(withIdentifier: "TableSegue", sender: indexPath)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "TableSegue", let indexPath = sender as? IndexPath {
let webController = segue.destination as? WebKitController
webController.selectedRow = indexPath.row
}
}
I think you can pass your indexpath.row value in sender of your perfomSegue and your second view controller just use this
here is code
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "secondvc", sender: indexPath.row)
}
just send indexpath.row value in sender
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "secondvc"{
let vc = segue.destination as! SecondViewController
vc.row = sender as! Int
}
}

Pass the myCell.textLabel?.text value via a segue in a dynamic prototype

I'm trying to segue from one UITableView to another UITableView. I want to segue and pass the myCell.textLabel?.text value of the selected cell to the second UITableView.
The code for my first UITableView (MenuTypeTableViewController and the code for my second UITableView (TypeItemsTableViewController) is also below.
I'm fully aware this involves the prepareForSegue function which currently I've not created, purely because I'm unsure where I override it and how to pass in the textLabel value to it.
Hope my question makes sense, I will update with suggestions and edits.
class MenuTypeTableViewController: UITableViewController, MenuTypeServerProtocol {
//Properties
var cellItems: NSArray = NSArray()
var menuType: MenuTypeModel = MenuTypeModel()
override func viewDidLoad() {
super.viewDidLoad()
let menuTypeServer = MenuTypeServer()
menuTypeServer.delegate = self
menuTypeServer.downloadItems()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return cellItems.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellIdentifier: String = "cellType"
let myCell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier)!
let item: MenuTypeModel = cellItems[indexPath.row] as! MenuTypeModel
myCell.textLabel?.text = item.type
return myCell
}
func itemsDownloaded(items: NSArray) {
cellItems = items
tableView.reloadData()
}
}
class TypeItemsTableViewController: UITableViewController, TypeItemsServerProtocol {
//Properties
var cellItems: NSArray = NSArray()
var typeItemList: TypeItemsModel = TypeItemsModel()
override func viewDidLoad() {
super.viewDidLoad()
let typeItemsServer = TypeItemsServer()
typeItemsServer.delegate = self
typeItemsServer.downloadItems()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return cellItems.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellIdentifier: String = "cellTypeItem"
let myCell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier)!
let item: TypeItemsModel = cellItems[indexPath.row] as! TypeItemsModel
myCell.textLabel?.text = item.name
return myCell
}
func itemsDownloaded(items: NSArray) {
cellItems = items
tableView.reloadData()
}
}
Hi try the following set of code, I have added few additional changes in your code make use of it, I hope it will solve your issue.
I have added only the extra codes which you needed
class TypeItemsTableViewController: UITableViewController, TypeItemsServerProtocol {
// Add this variable in this class and use it whereever you needed it in this class
var selectedItem: String?
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// Get the selected cell
let selectedCell = tableView.cellForRow(at: indexPath)
// Now maintain the text which you want in this class variable
selectedItem = selectedCell?.textLabel?.text
// Now perform the segue operation
performSegue(withIdentifier: "TypeItemsTableViewController", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "TypeItemsTableViewController" {
let destinationVC = segue.destination as? TypeItemsTableViewController
destinationVC?.selectedItem = self.selectedItem // Pass the selected item here which we have saved on didSelectRotAt indexPath delegate
}
}
In Second class:
class TypeItemsTableViewController: UITableViewController, TypeItemsServerProtocol {
// Add this variable in this class and use it whereever you needed it in this class
var selectedItem: String?
What you can do is to make a variable in your second UITableView
var String: labelSelected?
then in you prepare for segue method just set the labelSelected to the value of the cell.
refToTableViewCell.labelSelected = youCell.textlabel?.text
If you set up a segue in storyboards from one storyboard to another, you can use the code below in your prepareForSegue method. You'll need to add a testFromMenuTableViewController property to your TypeItemsTableViewController.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destination = segue.destination as? TypeItemsTableViewController,
let path = self.tableView.indexPathForSelectedRow,
let cell = self.tableView.cellForRow(at: path),
let text = cell.textLabel?.text {
destination.textFromMenuTypeTableViewController = text
}
}
For more info check this SO answer.

Move Text from cell to text label in a different view controller

I have created an app that displays 10 random numbers in a table view. This is the code I used
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ShowNumber", for: indexPath)
// Configure the cell...
cell.textLabel?.text = "\(indexPath.row + 1): \(Int(arc4random_uniform(10001)))"
return cell
}
Now I want to be able to click on one cell and be taken to another view controller and in the center of the page it displays the random number. I have the view controller all set up and linked to the original table view. I'm just having trouble passing my data through the segue. This is what I have so far. I know it unfinished, I just don't know what to do.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showRandomNumber" {
let controller = segue.destination as! ShowNumberTableViewController
let selectedRow = (tableView.indexPathForSelectedRow as NSIndexPath?)?.row ?? 0
controller.LabelText =
}
The LabelText is the name of the label that I want to pass the data to, but I don't know how to
Using the indexPathForSelectedRow, you can get a reference to the cell that triggered the segue. You can then access the textLabel within that cell, get its value, and pass it to the next view controller.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showRandomNumber" {
let controller = segue.destination as! ShowNumberTableViewController
if let indexPath = tableView.indexPathForSelectedRow {
let cell = tableView.cellForRowAtIndexPath(indexPath) as UITableViewCell
if let textToPass = cell.textLabel.text {
controller.labelText = textToPass
}
}
}
}
Then in ShowNumberTableViewController you want a var labelText and in your viewDidLoad() you can assign it to the textLabel in that view controller with
centerLabel.text = labelText
The way you are doing, the numbers will change when you scroll the table view. I think you should save the numbers in an array.
About how to grab the selected number in the prepareForSegue: I would do this way:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showRandomNumber" {
if let cell = sender as? UITableViewCell, indexPath = tableView.indexPathForCell(cell) {
let selectedNumber = numbers[indexPath.row]
controller.labelText = String(selectedNumber)
}
}
}

Resources