I want make a filter for search (on a separate screen) and I think about how to transfer data for my second viewcontroller.
Is there a way to use something like pointers from C++? When all changes in my array (at second view) change in the first view, that is, in fact I do not need to copy data because I use a pointer. If I can't use that how can I transfer my array after change back at first view?
Use Delegation to pass data back to previous class,
From First Class,
class FirstClass: UIViewController, SecondClassDelegate {
#IBAction func goToSecondClass(_ sender: Any) {
performSegue(withIdentifier: "SecondClassId", sender: nil)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destination = segue.destination as? SecondClass {
destination.delegate = self
}
}
func finishPassing(stringPassed: String) {
print(stringPassed)
}
}
In Second Class,
protocol SecondClassDelegate {
func finishPassing(string: String)
}
class SecondClass: UIViewController {
#IBAction func btnPassDataPressed(_ sender: Any) {
var delegate: SecondClassDelegate?
delegate?.finishPassing(string: "Data passed from Second Class")
}
}
don't use pointer, transfer you array by NotificationCenter.
Three ways here:-
If you have to pass data to previous controller then use Custom Delegation.
If you have to pass data to next controller then, just assign data to next view controller variable.
You can get data by saving it in Userdafults.
Related
So I've got a viewcontroller in which there's a child container layout, I need to call a method in that child only when I press a button in the parent. How to do that?
our initial view controller should have a reference to the child container. make sure you save that reference in a var or let which is accessible to the whole class (define it in the very beginning of the view controller, outside of any functions).
then you can just call the method you need from the button press function by something like childContainer.method()
When you use a UIContainerView, Storyboard automatically sets up an embed segue. You can use prepareForSegue to get a reference to the child VC.
Here's a very simple example:
class MyChildViewController: UIViewController {
func funcInChild(_ val: String) -> Void {
print("funcInChild was called with: \(val)")
}
}
class MainViewController: UIViewController {
var childInContainer: MyChildViewController?
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let vc = segue.destination as? MyChildViewController {
childInContainer = vc
}
}
#IBAction func btnTapped(_ sender: Any?) -> Void {
childInContainer?.funcInChild("This is a test!")
}
}
I'm trying to send data from one ViewController to another with delegate, but can't seem to get the right instance
I've tried setting the delegate at different places within the receiving ViewController including ViewDidLoad, but the delegate in the sending ViewController is always nil.
From what I've learned, it's an average problem everybody seems to go through, and I've read quite a number of samples, tried them, but to no avail. I don't know if I'm leaving something out or not. Please shed some light if you will.
Below is what I ended up with.
The sending ViewController:
protocol CreateChatDelegate: class{
func appendChatData(_ sender: CreateChatViewController)
}
class CreateChatViewController: UIViewController {
weak var delegate: CreateChatDelegate!
#IBAction func createChat(_ sender: AnyObject) {
delegate?.appendChatData(self)
if delegate == nil {
print("delegate unsuccessful")
} else {
print("delegate successful")
}
}
The receiving ViewController:
class ViewController: UIViewController{
var createChatViewController: CreateChatViewController!
override func viewDidLoad() {
super.viewDidLoad()
...
}
}
extension ViewController: CreateChatDelegate {
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// get the reference to the ViewController
self.createChatViewController = segue.destination as? CreateChatViewController
// set it as delegate
self.createChatViewController?.delegate = self
print("ViewController: delegate successful")
}
}
func appendChatData(_ sender: CreateChatViewController) {
print("ViewController: CreateChatDelegate called")
}
}
this code outputs "delegate unsuccessful", because delegate is always nil
The method you are using is incorrect. You should use the new one:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
....
}
Notice the override keyword? if you don't see this when you are writing the viewController methods, It means that you are NOT calling the original method and misspelled the function signature.
NOTE: if you are targeting older iOS and using older Xcode, the method name may be different, you should write the name of the method and let the AutoComplete help you with the correct one.
To successsfuly configure segue you need to make sure that
1- Navigation is triggered by
self.performSegue(withIdentifier:"segue",sender:nil)
2- Force-unwrap
self.createChatViewController = segue.destination as! CreateChatViewController
as as? cast may fail silently for some reason
First make sure that prepareForSegue() method is called. Then make sure that it is called for the CreateChatViewController i.e.
if let destination = segue.destination as? CreateChatViewController {
//Do all the stuff there e.g.
destination.delegate = self
}
If your prepareForSegue() method is not called then set the action properly so it will fire the prepareForSegue() method then you will get the delegate value in the CreateChatViewController.
I've set up a simple Swift project to try and wrap my head around delegates & protocols. The goal is to pass data between two classes (SendingClass & ReceivingClass). Two buttons in the SendingClass are linked to the delegate which should trigger the Protocol conforming function in the ReceivingClass to execute. This doesn't work unfortunately, I suspect it has to do with where and how I am declaring the ReceivingClass as the delegate.
Appreciate your insights, i'm just starting out!
I've tried setting the delegate in various locations (presently within viewDidLoad, but cant get it to work).
let vc = SendingClass()
vc.statusDelegate = self
SendingClass.swift
import UIKit
protocol StatusDelegate {
func statusChanged(state: Bool, sender: String)
}
class SendingClass: UIViewController {
var statusDelegate : StatusDelegate?
#IBAction func button1Pressed(_ sender: UIButton) {
statusDelegate?.statusChanged(state: true, sender: "Button 1")
}
#IBAction func button2Pressed(_ sender: UIButton) {
statusDelegate?.statusChanged(state: false, sender: "Button 2")
}
}
ReceivingClass.swift
import Foundation
import UIKit
class ReceivingClass: UIViewController, StatusDelegate {
override func viewDidLoad() {
let vc = SendingClass()
vc.statusDelegate = self
}
func statusChanged(state: Bool, sender: String) {
print("Sender = \(sender) , State = \(state)")
}
}
Expected: the ReceivingClass protocol conforming function (func statusChanged) should execute each time the buttons are pressed within the SendingClass.
Actual: Nothing happens
I am using this..
// create extension in your receiving class
extension ReceivingClass: PopUpVCDelegate {
func statusChanged(state: Bool, sender: String) {
print("Sender = \(sender) , State = \(state)")
}
}
// on sending class, when you present your receiving class on any button click
eg.
let resultController = self.storyboard?.instantiateViewController(withIdentifier: "PopUpVCID") as? PopUpVC
resultController?.delegate = self
self.present(resultController!, animated: true, completion: nil)
//or if not have button add on viewdidload in receiving class
// here is full eg
How to get data from popup view controller to custom table view cell?
For protocol and delegate, you use it when u want to bring a value from 2nd VC (presented by 1st or pushed by 1st VC) to 1st VC, which is the original.
From your code, I dont see you presenting or pushing your 2nd VC. that's why it's not working. Hopefully I answered your doubt.
However if you still want to bring a value over from 1st VC to 2nd VC. In second VC, create a variable to receive it
var ReceivedData = String()
then from your first VC, when u are going to push it,
let vc = SendingClass()
vc.ReceivedData = "Whatever you want it to receive"
If you're using storyboard segues, maybe the view controller is instantiated from there so probably you have to use the prepareForSegue and get the destination view controller (which is already instantiated for you) in the ReceivingClass view controller:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
super.prepare(for: segue, sender: sender)
if let destination = segue.destination as? SendingClass {
destination.delegate = self
}
}
Also be careful with delegate patter: the delegate property should be declared as a weak property to avoid retain-cycle
weak var delegate: MyDelegate?
I have a source view controller and a destination view controller.
I would like to show data fetched from a url in the UI (destination) just after moving to this screen ("show" segue).
In order to do that, in the source VC I use "prepare for segue" method, where I call a function that returns an array with all the fetched data I want to show and pass it to the destination VC to be shown in a UITableView.
The problem is that many times the whole data is not fetched from the url, so I pass an empty array to the destination.
This is the code in the source VC:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destinationVc = segue.destination as?
ShowCharacterInfoViewController{
fetchCharacterArrayFromUrl(characterName: cellContent){ results in
destinationVc.array.append(contentsOf:results)
destinationVc.tabelView.reloadData()}
} }
I can't think of a proper solution.
You can do one of two things.
Load the data and only perform the segue after the function has returned the data.
Transition to the destination screen and have that controller load the data in viewWillAppear.
// Add a place to save the results
var saveResults: MyResultsType?
#IBAction func someButtonAction(_ sender: Any) {
// Consider putting a "Loading..." dialog here
fetchCharacterArrayFromUrl(characterName: cellContent){ results in
self.saveResults = results
DispatchQueue.main.async({
// Hide the "Loading..." dialog
performSegue(withIdentifier: "ID of your Segue", sender: sender) //
})
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destinationVc = segue.destination as? ShowCharacterInfoViewController {
// I'm not sure append() is really what you need here
destinationVc.array.append(contentsOf: savedResults)
destinationVc.tabelView.reloadData()
}
}
You need to update the UI stuff in main thread since you are executing backend call:-
DispatchQueue.main.async({
destinationVc.tabelView.reloadData()
})
I've got my EditorViewController that segues modally to my ModalViewController, and in the ModalViewController I have to pass some data back to the EditorViewController after the view is dismissed. I've looked at many tutorials about delegates and protocols, and I believe that's what I have to do to pass this information, but I can't seem to get the code right although I've followed the tutorials exactly. If anyone can see what's going wrong in here I would appreciate it. I'll post the code.
The protocol
protocol passColorBackDelegate {
func colorToChange(_ color: String)
}
The first view Controller
class EditorViewController: UIViewController, passColorBackDelegate {
func colorToChange(_ color: String) {
print("Hello")
}
The second view Controller file (the one with data to pass back to first), also has another class in it, I'm stingy with my files
class subView: UIView {
}
class ModalViewController: UIViewController {
var delegate: passColorBackDelegate?
#IBAction func changeColor(_ sender: UIButton) {
switch sender {
case blueColorButton: colorToChangeTo = "Blue"
case redColorButton: colorToChangeTo = "Red"
case greenColorButton: colorToChangeTo = "Green"
case purpColorButton: colorToChangeTo = "Purple"
default: print("error")
}
print(colorToChangeTo)
delegate?.colorToChange(colorToChangeTo)
self.dismiss(animated: true, completion: nil)
}
As you can see my protocol function doesn't include any of the data I need passed back yet, but the message still isn't printing, meaning the function isn't getting called. If anyone could tell me what I'm doing wrong I would appreciate it. Thanks
You will need to set the delegate before you perform the segue. Since it sounds like you're using Storyboards, this can be done in prepare(for segue):
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destinationVC = segue.destination as? ModalViewController {
destinationVC.delegate = self
}
}
Also, as Paul mentioned in the comments, capitalizing your protocols (PassColorBackProtocol) and classes (SubView) is the conventional style in Swift and helps other people understand your code.