I am using two view Controllers i.e. StateListVC and PlayVC. In StateListVC, I am using container view with 3 VCs. After tapping on 3rd View Controller, I am going to PlayVC with delegate method. I don't know how to do that. Please help me to resolve this issue.
StateListVC
class StateListVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
if isMoveToAnotherVC
{
let vc = self.storyboard?.instantiateViewController(withIdentifier: "PlaceVC") as! PlaceVC
vc.delegate = self
}
}
}
extension StateListVC: MoveToAnotherVC {
func moving(string: String) {
print(string)
}
}
ThirdVC
protocol MoveToAnotherVC {
func moving(string: String)
}
class PlaceVC: UIViewController {
#IBOutlet weak var tableViewPlace: UITableView!
var delegate: MoveToAnotherVC? = nil
var arrPlace = ["Place1", "Place2"]
override func viewDidLoad() {
super.viewDidLoad()
}
extension PlaceVC: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrPlace.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.textLabel?.text = arrPlace[indexPath.row]
return cell
}
}
extension PlaceVC: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
isMoveToAnotherVC = true
print(delegate)
guard let delegate = self.delegate else{
print("Delegate not set")
return
}
delegate.moving(string: "test")
}
}
This is hooked up fine:
protocol MoveToAnotherVC: AnyObject {
func moving(string: String)
}
class StateListVC: UIViewController, MoveToAnotherVC {
override func viewDidLoad() {
super.viewDidLoad()
let vc = self.storyboard?.instantiateViewController(withIdentifier: "PlaceVC") as! PlaceVC
vc.delegate = self
}
func moving(string: String) {
print(string)
}
}
class PlaceVC: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var tableViewPlace: UITableView!
weak var delegate: MoveToAnotherVC?
var arrPlace = ["Place1", "Place2"]
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrPlace.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = arrPlace[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
delegate?.moving(string: "test")
}
}
I made the protocol a class protocol, moved the view controller instantiation into viewDidLoad, removed some (what I consider) extraneous unwrapping, and stripped your protocol/delegate pattern down to the basics. This works. I would plug this into your project and add what you need piece by piece until it breaks because your problem is outside of this. I suspect it may have to do with something you didn't include in your question but this answers your question about how to set up a protocol/delegate pattern.
Related
I want to take selected cell as a text, and save it in "var productName" as a String. I've tried to use didSelectRowAt funcion, but I don't know how to implement it.
That's my code:
import UIKit
class ChooseProductViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var productName: String? = ""
var workModel: ActualValues?
var closureBlock2: (() -> Void)?
#IBOutlet weak var checkButton: UIButton!
let productList : [String] = ["Almond 20g",
"Almond 40g",
"Baharat Spice Mix 2g",
"Baharat Spice Mix 4g",
]
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return productList.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let myCell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
myCell.textLabel?.text = productList[indexPath.row]
return myCell
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func checkButton(_ sender: UIButton) {
workModel?.product = productName
closureBlock2?()
self.dismiss(animated: true, completion: nil)
}
func configureProduct(model: ActualValues) {
workModel = model
}
}
How can I fix it?
Something like this is probably what you want?
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
productName = productList[indexPath.row]
}
And make sure you've set the data source and delegate, and that the table view allows seletion:
override func viewDidLoad() {
super.viewDidLoad()
tableView.allowsSelection = true
tableView.dataSource = self
tableView.delegate = self
}
For some reason, the delegate method is not being called. I am printing the delegate property in the console but it returns nil. I was looking for other answers here, but none of them were helpful for me.
protocol FilterSwitchDelegate {
func switchValueChanged(tagValue:Int)
}
class FilterTableViewCell: UITableViewCell {
#IBOutlet weak var filterLabel: UILabel!
#IBOutlet weak var filterSwitch: UISwitch!
var delegate:FilterSwitchDelegate?
#IBAction func filterSwitchValueChanged(_ sender: UISwitch) {
print(sender.tag)
delegate?.switchValueChanged(tagValue: sender.tag)
}
}
//In FilterViewController I am calling this delegate method
class FilterViewController: UIViewController {
#IBOutlet weak var tableView: UITableView!
var dataSource = FilterTableViewCell()
var filterModel = [FilterVCDataModel]()
var ids = [Int]()
override func viewDidLoad() {
super.viewDidLoad()
dataSource.delegate = self
}
}
extension FilterViewController: FilterSwitchDelegate {
func switchValueChanged(tagValue: Int) {
ids.remove(at: tagValue)
print(ids)
}
}
TableView dataSource and delegate methods
extension FilterViewController:UITableViewDelegate,UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return filterModel.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "filterCell", for: indexPath) as! FilterTableViewCell
cell.filterSwitch.tag = indexPath.row
cell.filterLabel.text = filterModel[indexPath.row].filterData["title"] as? String
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 66
}
}
in the cellForRow you have to dequeue your cell.
let cell = tableView.dequeueReusableCell(withIdentifier: "yourId") as? FilterTableViewCell
cell.delegate = self
return cell
and the job is done
Im trying to load a array of strings in a table view but the view does not recognize the array.
I have an array called Playlists (declared as global on ThirdViewController) with objects from class Playlist. When I use it on every other table view I can access every object and use it on the table view (I'm using it on ThirdViewController), but on AddToPlaylist view I can't use it. I think I'm using correctly the cells and func for table views.
This happens when I press the button "AƱadir" on player view. It should load the table view with the array info.
Here is the project (develop branch): tree/develop
import UIKit
class AddToPlaylist: UIViewController, UITableViewDelegate, UITableViewDataSource{
#IBOutlet weak var myTableViewPlaylist: UITableView!
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return Playlists.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "hola", for: indexPath)
cell.textLabel?.text = Playlists[indexPath.row].name
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
Playlists[indexPath.row].songs.append(songName)
performSegue(withIdentifier: "addedSong", sender: self)
}
override func viewDidLoad() {
super.viewDidLoad()
myTableViewPlaylist.delegate = self
myTableViewPlaylist.dataSource = self
myTableViewPlaylist.reloadData()
}
}
Here is the declaration of Playlists array:
import UIKit
import AVFoundation
var favorites:[String] = []
var Playlists:[Playlist] = []
var selecPlaylist = 0
var firstOpen2 = true
class ThirdViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var myTableView2: UITableView!
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
//print(Playlists.count)
return Playlists.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .default, reuseIdentifier: "cell")
cell.textLabel?.text = Playlists[indexPath.row].name
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selecPlaylist = indexPath.row
performSegue(withIdentifier: "segue", sender: self)
}
override func viewDidLoad() {
super.viewDidLoad()
myTableView2.delegate = self
myTableView2.dataSource = self
if firstOpen2{
crear()
firstOpen2 = false
}
myTableView2.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func crear(){
let pl1 = Playlist(name: "Prueba")
pl1?.addSong(song: songs[0])
Playlists.append(pl1!)
let pl2 = Playlist(name: "Prueba2")
pl2?.addSong(song: songs[1])
Playlists.append(pl2!)
}
}
let cell = tableView.dequeueReusableCell(withIdentifier: "yourIdentifier") as! UITableViewCell
cell.textLabel?.text = Playlists[indexPath.row].name
return cell
this is my first post on here, so please forgive me if I forget to post a detail or two:)
I set up a View Controller (Storyboard ID: "SavedMemeVC")
I need to segue from another VC that contains a table, however the tap is completely ignored. Can you please help?
Code is below:
import UIKit
import Foundation
class MemeTableVC: UIViewController, UITableViewDataSource, UITableViewDelegate, UINavigationControllerDelegate {
#IBOutlet weak var memeTable: UITableView!
var memes : [Meme]!
override func viewWillAppear(_ animated: Bool) {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
memes = appDelegate.memes
self.memeTable.reloadData()
}
override func viewDidLoad() {
super.viewDidLoad()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return memes.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MemeCell")!
let memeListItem = memes[(indexPath as NSIndexPath).row]
cell.textLabel?.text = "\(memeListItem.topText!)"
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let detailController = self.storyboard!.instantiateViewController(withIdentifier: "SavedMemeVC") as! SavedMemeVC
let meme = memes[(indexPath as NSIndexPath).row]
detailController.memeImage = meme.memedImage
self.navigationController!.pushViewController(detailController, animated: true)
print("something")
}
}
You should add delegate of tableview
override func viewDidLoad() {
super.viewDidLoad()
memeTable.delegate = self
}
This question already has answers here:
Passing data between view controllers
(45 answers)
Closed 6 years ago.
I'm new to Swift. I have two table view controllers, one with static cells and one with dynamic ones. I basically want to let a user select his marital status on the second table view controller and send his choice back to the first table view controller (and display his selection on the cell "Marital Status"). Here is a screenshot of my storyboard:
Storyboard
Current code on second table view controller:
import UIKit
class SecondTableViewController: UITableViewController {
let maritalStatusArray: [String] = ["Single", "Married"]
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return maritalStatusArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MaritalStatusCell", for: indexPath)
cell.textLabel?.text = maritalStatusArray[indexPath.row]
return cell
}
}
My guess is that I have to add a segue from the dynamic cell of the second view controller back to the first one. Is that right ?
Supposing this is the way to do it, I have afterwards to update the text of the static label to include the choice made by the user. Any ideas ?
There few ways by which you can implement the callback functionality to pass data.
Delegate
Using Block CallBack
Post Notification
But I would suggest to use delegate which is best way, Post Notification is also a way but I do not want to prefer.
You can use custom delegate to do this:
ViewController.swift:
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, SecondViewControllerProtocol {
#IBOutlet weak var userInfoTableView: UITableView!
var userInfoArray: [String] = []
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
userInfoArray = ["Marital Status","Canton","Commune","Religion"]
self.userInfoTableView?.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 4
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let userInfoCell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
userInfoCell.textLabel?.text = userInfoArray[indexPath.row]
if indexPath.row == 0{
userInfoCell.accessoryType = UITableViewCellAccessoryType.disclosureIndicator
}
return userInfoCell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.row == 0{
let secondVC = storyboard?.instantiateViewController(withIdentifier: "SecondViewControllerIdentifier") as! SecondViewController
secondVC.statusDelegate = self
self.navigationController?.present(secondVC, animated: true, completion: nil)
}
}
func changeMaritalStatus(type: String){
let maritalStatusCell = userInfoTableView.cellForRow(at: IndexPath(row:0 , section:0))
maritalStatusCell?.textLabel?.text = String("Marital Status: \(type)")
}
}
SecondViewController.swift:
import UIKit
protocol SecondViewControllerProtocol {
func changeMaritalStatus(type: String)
}
class SecondViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var maritalStatusTableView: UITableView!
var maritalStatusArray: [String] = []
var statusDelegate : SecondViewControllerProtocol? = nil
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
maritalStatusArray = ["Single","Married","Divorced"]
self.maritalStatusTableView.register(UITableViewCell.self, forCellReuseIdentifier: "maritalStatuscell")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let maritalStatusInfoCell = tableView.dequeueReusableCell(withIdentifier: "maritalStatuscell", for: indexPath)
let infoLabel: UILabel = UILabel.init(frame: CGRect(x: 10, y: 5, width: 250, height: 50))
infoLabel.text = maritalStatusArray[indexPath.row]
maritalStatusInfoCell.addSubview(infoLabel)
return maritalStatusInfoCell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
statusDelegate?.changeMaritalStatus(type: maritalStatusArray[indexPath.row])
self.dismiss(animated: true, completion: nil)
}
}
GitHub link:
https://github.com/k-sathireddy/CustomDelegatesSwift
Output:-