Return array to another ViewController in Swift - ios

I have two UIViewControllers and each one has an UITableView. Lets say that when I call from View-A to View-B, I take the cells which are marked in the UITableView in View-B and, after pressing a button I want to return an array with all the data selected from View-B to View-A, dismiss View-B and represent that information in the TableView of View-A.
How can I pass that array ? How do I have to reaload the data in View-A to show it after dimissing View-B ?
Any idea?
Thank you very much!!

protocol DataPasserDelegate {
func sendDatatoA(dataArrayFromB : Array<AnyObject>)
}
class ViewB: UIViewController {
var delegate: DataPasserDelegate!
var dataArrayB = Array<AnyObject>()
#IBAction func sendData(sender: Any){
self.dismiss(animated: true) {
self.delegate.sendDatatoA(dataArrayFromB: self.dataArrayB)
}
}
}
class ViewA: UIViewController, DataPasserDelegate {
#IBOutlet weak var tableViewA: UITableView!
var dataArrayA = Array<AnyObject>()
//MARK: - DataPasserDelegate
func sendDatatoA(dataArrayFromB: Array<AnyObject>) {
dataArrayA = dataArrayFromB
self.tableViewA.reloadData()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destVC = segue.destination as? ViewB{
destVC.delegate = self
}
}
}

So you can use prepareForSegue:
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
if (segue.identifier == "segueID") {
if let controller = segue.destination as? YourVC{
controller.array = yourArray
controller.tableView.reloadData()
}
}
}

You will need to use delegate for this. For more information on delegates you can go through my blog here.

Related

I'm trying to use a protocol and delegate pattern which will pass the data in my array back to the parent view controller

I am new to Xcode and am trying to save an array from secondViewController into the View controller. I have a a series of view controllers embedded in a navigation controller so when I click 'back' on the navigation bar I want to keep the data that was collected in an array 'collectionArray' and save to 'collectionArray2' . Here is the protocol delegate method I've tried:
This is in my ViewController where I want the array saved to :
import UIKit
class ViewController: UIViewController {
var collectionArray2: [String] = []
override func viewDidLoad() {
super.viewDidLoad()
let controller = secondViewController()
controller.delegate = self
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let first = segue.destination as! secondViewController
first.collectionArray.append(contentsOf: collectionArray2)
}
}
extension ViewController: PopupDelegate {
func popupSelectedView(array: [String]) {
collectionArray2.append(contentsOf: array)
}
}
This is my secondViewController where I want to take 'collectionArray':
import UIKit
protocol PopupDelegate: class{
func popupSelectedView(array: [String])
}
class secondViewController: UIViewController {
var exerciseButton: String!
var collectionArray: [String] = []
weak var delegate: PopupDelegate?
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func Exercisess(_ sender: UIButton){
exerciseButton = sender.currentTitle
collectionArray.append(exerciseButton!)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if self.isMovingFromParent {
delegate?.popupSelectedView(array: collectionArray)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let second = segue.destination as! FinalViewController
second.cellLabelArray.append(contentsOf: collectionArray)
}
}
Thank you
your problem is that your are referring to a difference instance of secondViewController. Don't set your delegate in viewDidLoad but when you prepare the segue:
override func viewDidLoad() {
super.viewDidLoad()
//let controller = secondViewController() REMOVE THIS
//controller.delegate = self REMOVE THIS
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let first = segue.destination as! secondViewController
first.collectionArray.append(contentsOf: collectionArray2)
first.delegate = self // set the delate here
}
}
by the way, you should name all your classes starting with capital letters, so it should be SecondViewController

Calling method in another view controller from modal view controller using a delegate

I am using a modal segue to create a view controller that I want to dismiss and then call a method in the origin view controller. I have used a protocol/delegate pattern but for some reason the method is never called. The code is below: Please note that I removed a lot of non-relevant code to keep it clean here
Thanks!!
VC1:
final class WorkoutViewController: UIViewController, StartWorkoutButtonDelegate {
weak var dataSource: WorkoutViewControllerDataSource!
private var workout: Workout!
private var workoutDataViewController: WorkoutDataViewController?
private var workoutFinishViewController: WorkoutFinishViewController?
private let workoutFinishViewControllerSegueIdentifier = "Workout Finish View Controller Segue"
#IBOutlet private var primaryActionButton: UIButton!
#IBOutlet private var pageControl: UIPageControl!
// MARK: - Handling View Lifecycle
override func viewDidLoad() {
super .viewDidLoad()
let workoutType = dataSource.workoutType(for: self)
workout = Workout(workoutType: workoutType, managedObjectContext: persistentContainer.viewContext)
setPrimaryActionButtonLabel()
}
// MARK: - Handling Storyboard Segues
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
super.prepare(for: segue, sender: sender)
if let destinationWorkoutFinishViewController = segue.destination as? WorkoutFinishViewController {
workoutFinishViewController = destinationWorkoutFinishViewController
}
}
// MARK: - Managing Start and Pause
#IBAction func startOrPauseWorkout() {
if workout.isPaused {
startWorkout()
} else {
pauseWorkout()
}
}
}
VC 2:
protocol StartWorkoutButtonDelegate: AnyObject {
func startOrPauseWorkout()
}
class WorkoutFinishViewController: UIViewController {
weak var delegate: StartWorkoutButtonDelegate?
#IBAction func startWorkout() {
self.delegate?.startOrPauseWorkout()
self.dismiss(animated: true, completion: nil)
}
#IBAction func finishWorkout() {
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
Here set the delegate
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
super.prepare(for: segue, sender: sender)
if let destinationWorkoutFinishViewController = segue.destination as? WorkoutFinishViewController {
destinationWorkoutFinishViewController.delegate = self
}
}

Change Label text in a ContainerView on click of a button from other class (Uiviewcontroller)

I got small containerView with UILabel on main app screen. I got UIButton on main UIViewController. I want to change text of label that belongs to containerView class by clicking button in UIViewController.
I try to make it with delegation, but for some reason i got a mistake (Unwraping optional)...
I try to make it with Protocol, bud method "addText" in ContView dont works((((((
class ViewController: UIViewController {
var delegate: DelegateProtocol?
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func button(_ sender: Any) {
delegate?.addText(String2: "123")
}}
///////////////////////////////////////////////////////////////////////
protocol DelegateProtocol {
func addText(String2: String)
}
//////////////////////////////////////////////////////////////////////
class ContViewController: UIViewController, DelegateProtocol {
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "con" {
let vc = segue.destination as! ViewController
vc.delegate = self
}
}
func addText(String2: String) {
label.text = String2
}
#IBOutlet weak var label: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
}
first make an global variable in your view controller
private var viewController: YourVC?
then give your container view segue an identifier and do follwing
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "yourviewcontroller Segue identifiew" { //your container view segue identifier
viewController = segue.destination as? SelectedImageVC
}
}
now you can use you viewController to access label in your containerview controller like
if let controller = viewController {
controller.yourlabel.text = "text you want"
}

store segued data on a separate viewcontroller (swift4)

My code takes text from a textfield and segues to a separate view controller. The problem is that it can only store 1 segue entry. The new one replace the old every time the button is pressed. How on vc2 can I store every new entry to the segue.
VC
import UIKit
class ViewController: UIViewController {
#IBOutlet var txt: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func pressButton(_ sender: Any) {
if txt.text != "" {
performSegue(withIdentifier: "segue", sender: self)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let secondController = segue.destination as! twoViewController
secondController.myString = txt.text!
}
}
twoVC
import UIKit
class twoViewController: UIViewController {
#IBOutlet var labelSmtih: UILabel!
var myString = String()
override func viewDidLoad() {
super.viewDidLoad()
labelSmtih.text = myString
}
}
If the second view controller is a UISplitViewController for example you should be able to append the text of the button to the label, by doing something in the lines of:
#IBAction func pressButton(_ sender: Any) {
if txt.text != "" {
performSegue(withIdentifier: "segue", sender: self)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let secondController = segue.destination as! twoViewController
secondController.myString += txt.text!
}
}
If you really have a separated view controller it will probably lose the data once you go back to the first VC. In that case, I suggest you save the current text of the label on viewWillDisappear of the 2nd VC and then retrieve this on the prepareforsegue function on the first VC. More info here: Swift: How to store user preferences?

View Controller delegate returns nil

My code is below. When I press the 'Done' or 'Cancel' buttons, it doesn't work as I want. I did some debugging, and delegate is nil even though I set it. Please help - thanks.
class ViewController: UIViewController,EditViewControllerDelegate {
#IBOutlet weak var label: UILabel!
//页面跳转时
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "EditView" {
//通过seque的标识获得跳转目标
let controller = segue.destinationViewController as! EditViewController
//设置代理
controller.delegate = self
//将值传递给新页面
controller.oldInfo = label.text
}
}
func editInfo(controller:EditViewController, newInfo:String){
label.text = newInfo
//关闭编辑页面
controller.presentingViewController!.dismissViewControllerAnimated(true, completion: nil)
}
func editInfoDidCancer(controller:EditViewController){
//关闭编辑页面
controller.presentingViewController!.dismissViewControllerAnimated(true, completion: nil)
}
}
import UIKit
protocol EditViewControllerDelegate {
func editInfo(controller:EditViewController, newInfo:String)
func editInfoDidCancer(controller:EditViewController)
}
class EditViewController: UIViewController {
#IBOutlet weak var textField: UITextField!
var delegate:EditViewControllerDelegate?
var oldInfo:String?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
if oldInfo != nil{
textField.text = oldInfo
}
}
#IBAction func done(sender: AnyObject) {
delegate?.editInfo(self, newInfo: textField.text!)
}
#IBAction func cancel(sender: AnyObject) {
delegate?.editInfoDidCancer(self)
}
}
Try this,
class ViewController: UIViewController,EditViewControllerDelegate {
var controller: EditViewController?
#IBOutlet weak var label: UILabel!
//页面跳转时
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "EditView" {
//通过seque的标识获得跳转目标
controller = segue.destinationViewController as! EditViewController
//设置代理
controller.delegate = self
//将值传递给新页面
controller.oldInfo = label.text
}
}
func editInfo(controller:EditViewController, newInfo:String){
label.text = newInfo
//关闭编辑页面
controller.presentingViewController!.dismissViewControllerAnimated(true, completion: nil)
}
func editInfoDidCancer(controller:EditViewController){
//关闭编辑页面
controller.presentingViewController!.dismissViewControllerAnimated(true, completion: nil)
}
}
import UIKit
protocol EditViewControllerDelegate {
func editInfo(controller:EditViewController, newInfo:String)
func editInfoDidCancer(controller:EditViewController)
}
class EditViewController: UIViewController {
#IBOutlet weak var textField: UITextField!
var delegate:EditViewControllerDelegate?
var oldInfo:String?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
if oldInfo != nil{
textField.text = oldInfo
}
}
#IBAction func done(sender: AnyObject) {
delegate?.editInfo(self, newInfo: textField.text!)
}
#IBAction func cancel(sender: AnyObject) {
delegate?.editInfoDidCancer(self)
}
}
I’m not able to tell from your code how you are handling the opening of EditViewController from your ViewController.
I’m guessing that your prepareForSegue:sender: is not getting called resulting in the delegate not getting set. To fix this, you will need to add a performSegueWithIdentifier:sender: call at the point where the segue needs to happen as in
self.performSegueWithIdentifier("EditView", sender: self)
You should replace whatever code is performing the opening of EditViewController with that call.
I have an app the uses showViewController:sender: to open up a second view controller from the first one even though there is a Show segue defined in my storyboard. The segue in my storyboard doesn’t get used in that case and prepareForSegue:sender: is never called as a result.
If I replace my
showViewController(myVC, sender: self)
with
performSegueWithIdentifier("mySegue", sender: self)
then prepareForSegue:sender: will get called. If I am setting a delegate, like you are, in prepareForSegue:sender:, the delegate will get set before the segue happens.

Resources