Reputation: 879
I'm stuck with a problem now and I need some help. Currently, I have two different view controllers in my project, VC1 and VC2. In the project, I have both a navigation bar and a tab bar.
In the VC1, I have a UIViewController class and it contains a UITableView and the tablaViewCell. Also, I add an array of liveEvents like below.
public var liveEvents: [LiveEvent] = [
LiveEvent(title: "aaaa"),
LiveEvent(title: "bbbbbb"),
LiveEvent(title: "ccccccc")
]
Then, from the cell, I added the segue to the VC2. In the VC2, I added the IBaction to barbutton item like below.
@IBOutlet weak var eventTitle: UITextField!
@IBAction func saveNewLiveEvent(_ sender: Any) {
if let eventTitle = eventTitle.text {
let vc = VC1()
vc.liveEvents.append(LiveEvent(title: eventTitle))
print("liveEvent: \(vc.liveEvents)")
navigationController?.popViewController(animated: true)
}
}
and I tried to append an event in the liveEvent array in the VC1.
In the console, I can see the new event is appended in VC2, however, when I add the print statement in the VC1, I don't see the new added value is appended (also, the new value is not reflected on the table view.) when I back from VC2 to VC1.
I was wondering how to append the value to an array which is in the different swift file.
If you know what I'm doing wrong, please let me know.
Upvotes: 0
Views: 940
Reputation: 613
Here is a solution for you. In short, you cannot create new instance of VC1
as you did in VC2
. You need existing instance which can be achieve using protocol
approach. Check the code. This will fix you issue.
// 1) Protocol to connect two controllers VC1 and VC2
// You can add protocol code in your VC1 class or you can create new .swift file and add there as well.
protocol LiveEventProtocol: AnyObject {
func addEvent(_ liveEvent: LiveEvent)
}
class VC1: UIViewController, LiveEventProtocol {
public var liveEvents: [LiveEvent] = [
LiveEvent(title: "aaaa"),
LiveEvent(title: "bbbbbb"),
LiveEvent(title: "ccccccc")
]
// 2) go to vc2 but don’t forget to set vc2.delegate = self
// ⭐️ That is the key here.
// `vc2.delegate = self` connects VC1 and VC2
func gotoVC2() {
let vc2 = VC2()
vc2.delegate = self
self.navigationController?.pushViewController(VC2(), animated: true)
}
// 3) Implementing protocol method.
// This is a method where VC2 will delegate work to VC1 to append liveEvent.
func addEvent(_ liveEvent: LiveEvent) {
self.liveEvents.append(liveEvent)
// now do your reload stuff.
}
}
class VC2: ViewController {
weak var delegate: LiveEventProtocol?
var eventTitle = UITextField(frame: .zero)
func saveNewLiveEvent() {
if let eventTitle = eventTitle.text {
// ❌ this is wrong.
// Reason,
// -> you are creating new instance of VC1
// -> Instead we need the existing instance of VC1.
// -> This can be achieve using protocol approach.
// let vc = VC1()
// vc.liveEvents.append(LiveEvent(title: eventTitle))
// ✅ this is correct way to do it.
// Here, we are justing passing LiveEvent value through delegate approach which is connected with VC1.
delegate?.addEvent(LiveEvent(title: eventTitle))
navigationController?.popViewController(animated: true)
}
}
}
Upvotes: 0
Reputation: 2882
You created a new instance of VC1
in VC2
, it’s not the same instance you pushed from. So, that’s the reason your table isn’t updating.
You can use delegation
approach to achieve your result. I have created a demo code for this, please check below.
TestController1 (or VC1)-
import UIKit
class LiveEvent{
var title:String
init(title:String) {
self.title = title
}
}
class TestController: UIViewController {
@IBOutlet weak var testTableView: UITableView!
public var liveEvents: [LiveEvent] = [
LiveEvent(title: "aaaa"),
LiveEvent(title: "bbbbbb"),
LiveEvent(title: "ccccccc")
]
override func viewDidLoad() {
super.viewDidLoad()
}
}
extension TestController:UITableViewDelegate,UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
liveEvents.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! TestTableCell
cell.eventLabel.text = liveEvents[indexPath.row].title
return cell
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let destinationVC = segue.destination as? TestControllerTwo
destinationVC?.delegate = self
}
}
extension TestController:AddEventsInVC1{
func addNewEvent(event: LiveEvent) {
liveEvents.append(event)
testTableView.reloadData()
}
}
TestController2 (or VC2)-
import UIKit
protocol AddEventsInVC1:AnyObject {
func addNewEvent(event:LiveEvent)
}
class TestControllerTwo: UIViewController {
weak var delegate:AddEventsInVC1?
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func addEventAndPop(_ sender: Any) {
delegate?.addNewEvent(event: LiveEvent(title: "I am New"))
navigationController?.popViewController(animated: true)
}
}
CustomCellClass-:
import UIKit
class TestTableCell: UITableViewCell {
@IBOutlet weak var eventLabel: UILabel!
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
}
}
The Storyboard
design is simple, I just have TableView with single cell
, having a label
in it.
I have connected segue in storyboard itself from cell
to VC2
for demo purpose.
Upvotes: 2