Why I can't call a method stored in parent UIViewController from embedded UITableViewController? - ios

I have a parent ui view controller and it has a method responsible for printing data to the console:
func printSomeData() {
print("printing some data")
}
It also has a container with embedded UITableViewController. The table itself has a pull to refresh functionality implemented and it prints the string when user pulls the table:
func refresh(refreshControl: UIRefreshControl) {
print("Refreshing!!")
refreshControl.endRefreshing()
}
Now I want to call printsomeData from the refresh method.
This is what I try:
parent UIViewController:
class MainMenu: UIViewController, printing{
func printSomeData() {
print("some date")
}
}
embedded UITableViewController:
protocol printing{
func printSomeData()
}
class MainMenuTableViewController: UITableViewController {
var delegate: printing?
func refresh(refreshControl: UIRefreshControl) {
print("Refreshing!!")
if let _ = delegate{
delegate?.printSomeData()
}
refreshControl.endRefreshing()
}
But now when I pull the table I only see Refreshing!!, there is no way I could see printing some data. What am I doing wrong?

Where are you assigning the delegate?
And write the optional method call as a single line
delegate?.printSomeData()
or like that:
if self.delegate != nil {
self.delegate!.printSomeData()
}
Inside MainMenu
override func viewDidLoad() {
super.viewDidLoad()
// tableViewController is placeholder for `MainMenuTableViewController` reference
tableViewController.delegate = self
}
If i have understand you correctly and the MainMenu has a ContainerView with MainMenuTableViewController than should this solve your problem:
class MainMenu: UIViewController, Printer {
func printSomeData() {
print("some date")
}
}
protocol Printer {
func printSomeData()
}
class MainMenuTableViewController: UITableViewController {
var printer: Printer? {
guard let printer = self.parentViewController as? Printer else {
return nil
}
return printer
}
func refresh(refreshControl: UIRefreshControl) {
print("Refreshing!!")
printer?.printSomeData()
refreshControl.endRefreshing()
}
}

Related

Protocol-Delegate pattern not notifying View Controller

My Model saves data to Firestore. Once that data is saved, I'd like it to alert my ViewController so that a function can be called. However, nothing is being passed to my ViewController.
This is my Model:
protocol ProtocolModel {
func wasDataSavedSuccessfully(dataSavedSuccessfully:Bool)
}
class Model {
var delegate:ProtocolModel?
func createUserAddedRecipe(
docId:String,
completion: #escaping (Recipe?) -> Void) {
let db = Firestore.firestore()
do {
try db.collection("userFavourites").document(currentUserId).collection("userRecipes").document(docId).setData(from: recipe) { (error) in
print("Data Saved Successfully") // THIS OUTPUTS TO THE CONSOLE
// Notify delegate that data was saved to Firestore
self.delegate?.wasDataSavedSuccessfully(dataSavedSuccessfully: true)
}
}
catch {
print("Error \(error)")
}
}
}
The print("Data Saved Successfully") outputs to the console, but the delegate method right below it doesn't get called.
And this is my ViewController:
class ViewController: UIViewController {
private var model = Model()
override func viewDidLoad() {
super.viewDidLoad()
model.delegate = self
}
}
extension ViewController: ProtocolModel {
func wasDataSavedSuccessfully(dataSavedSuccessfully: Bool) {
if dataSavedSuccessfully == true {
print("Result is true.")
}
else {
print("Result is false.")
}
print("Protocol-Delegate Pattern Works")
}
}
Is there something I'm missing from this pattern? I haven't been able to notice anything different in the articles I've reviewed.
So I test your code and simulate something like that
import UIKit
protocol ProtocolModel {
func wasDataSavedSuccessfully(dataSavedSuccessfully:Bool)
}
class Model {
var delegate:ProtocolModel?
// I use this timer for simulate that firebase store data every 3 seconds for example
var timer: Timer?
func createUserAddedRecipe(
docId:String) {
timer = Timer.scheduledTimer(withTimeInterval: 3, repeats: true, block: { _ in
self.delegate?.wasDataSavedSuccessfully(dataSavedSuccessfully: true)
})
}
}
class NavigationController: UINavigationController {
var model = Model()
override func viewDidLoad() {
super.viewDidLoad()
model.delegate = self
// Call this method to register for network notification
model.createUserAddedRecipe(docId: "exampleId")
}
}
extension NavigationController: ProtocolModel {
func wasDataSavedSuccessfully(dataSavedSuccessfully: Bool) {
print(#function)
}
}
so you can see the result as image below, my delegate update controller that conform to that protocol.

Passing data to various view controllers via delegate

Struggling to learn the basics of passing data via delegates. I am trying to pass a string from my viewController to my viewController2 and print it. I am getting the error:
"Type ViewController2 has no member delagate" in my view controller 2.
I cannot figure out where I have gone wrong.
viewController 1:
protocol datadelagate {
func printThisString(string: String)
}
class ViewController: UIViewController {
var delegate: datadelagate?
override func viewDidLoad() {
delegate?.printThisString(string: "This was passed from first controller to second controller")
}
}
This is my viewController 2:
class ViewController2: UIViewController, datadelagate {
func printThisString(string: String) {
print(string)
}
override func viewDidLoad() {
super.viewDidLoad()
ViewController2.delagate = self
print(String.self)
}
}
If you want ViewController2 to print some value from ViewController, you might have to do it this way:
protocol datadelagate {
func printThisString(string: String)
func getStringFromVC1() -> String
}
class ViewController: UIViewController, datadelagate {
let someString: String = "From VC1"
func printThisString(string: String) {
print(string)
}
func getStringFromVC1() -> String {
return someString
}
override func viewDidLoad() {
ViewController2.delagate = self
}
}
class ViewController2: UIViewController {
var delegate: datadelagate?
override func viewDidLoad() {
super.viewDidLoad()
//This is how something from VC2 is sent to VC1's scope.
delegate?.printThisString(string: "Calling the delegate to print something from ViewController2 on first ViewController")
//The below call gets you some value from VC1. (This is what you wanted, I belive...)
print(delegate?.getStringFromVC1())
}
}
Now for some explanation:
For simple understanding, assume a delegate as a person who does some specific job (protocol).
You have a `delegate'
You ask your delegate to work with your friend, and your friend acknowledges. (assigns your delegate by You.delegate = self, where self is your friend)
Now, through your delegate, you can do something with your friend, by asking your delegate to do some job (defined in protocol).
EDIT
The code above won't work, as non-static data members are trying to be accessed without creating an instance
Working code
import UIKit
class ViewController2: UIViewController {
static let sharedInstance = ViewController2()
weak var delegate: DataDelagate?
override func viewDidLoad() {
super.viewDidLoad()
//This is how something from VC2 is sent to VC1's scope.
delegate?.printThis(string: "Calling the delegate to print something from ViewController2 on first ViewController")
//The below call gets you some value from VC1. (This is what you wanted, I belive...)
print(delegate?.getStringFromVC1() ?? "s")
}
}
class ViewController: UIViewController {
static let sharedInstance = ViewController2()
var someString: String = "From VC1"
override func viewDidLoad() {
super.viewDidLoad()
ViewController2.sharedInstance.delegate = self
}
}
extension ViewController: DataDelagate {
func printThis(string: String) {
print(string)
}
func getStringFromVC1() -> String {
return someString
}
}
protocol DataDelagate: AnyObject {
func printThis(string: String)
func getStringFromVC1() -> String
}

Delegate is nil in a Swift program

I'm practising how to communicate between two view controllers using protocol and delegate (in the xCode background even when I'm using protocol in my project I get the same problem, Delegate is nil), but the problem after setting everything it shows me that my delegate is nil and the sender VC does not send any data since the delegate is nil.
I have confirmed to the protocol and I have set the receiver VC as the delegate, but still can not see where the problem is.
The Protocol
protocol theCommunicationsStructionProtocol{
func dataToTransmit(Data: String)
}
The Sender VC
class TheSenderVC{
var delegate: theCommunicationsStructionProtocol?
func lookingForDelegate(){
self.delegate?.dataToTransmit(Data: "Data has been sent")
}
}
The Receiver VC
class TheReceiverVc1: theCommunicationsStructionProtocol{
var TheSenderVCObj = TheSenderVC()
func delegateLuncher(){
TheSenderVCObj.delegate = self
}
func dataToTransmit(Data: String) {
print("from VC1: \(Data)")
}
}
calling delegateLuncher() to set the delegate in the receiver VC
TheSenderVC().lookingForDelegate()
calling lookingForDelegate() from the sender VC to look for the
delegate and send it the data
TheReceiverVc1().delegateLuncher()
Note: I have tried accessing the delegate from the receiver VC using this way:
class TheReceiverVc1: theCommunicationsStructionProtocol{
var TheSenderVCObj: TheSenderVC?
func delegateLuncher(){
self.TheSenderVCObj?.delegate = self
}
func dataToTransmit(Data: String) {
print("from VC1: \(Data)")
}
}
but I still getting the same problem:
delegate is nil
Finally, I found the solution!
the problem is I was making instances of the TheSenderVC, instead of takling to the original TheSenderVC.
when I was making an object (an instance) of TheSenderVC the problem occurred! instead I have to access the original TheSenderVC, which means I have to use static :)
here is the old delegate set up
var delegate: theCommunicationsStructionProtocol?
from TheSenderVC
here is the new delegate set up
static var delegate: theCommunicationsStructionProtocol?
therefore the
func lookingForDelegate(){
self.delegate?.dataToTransmit(Data: "Data has been sent")
}
will be changed to
static func lookingForDelegate(){
self.delegate?.dataToTransmit(Data: "Data has been sent")
}
since now it includes a static property (delegate)
on the other hand, the The ReceiverVC1 should be changed from:
class TheReceiverVc1: theCommunicationsStructionProtocol{
var TheSenderVCObj = TheSenderVC()
func delegateLuncher(){
TheSenderVCObj.delegate = self
}
func dataToTransmit(Data: String) {
print("from VC1: \(Data)")
}
}
to:
class TheReceiverVc1: theCommunicationsStructionProtocol{
func delegateLuncher(){
TheSenderVC.delegate = self
}
func dataToTransmit(Data: String) {
print("from VC1: \(Data)")
}
}
accessing the delegate from the original TheSenderVC()
Where are you create the reference of TheSenderVCObj
replace var TheSenderVCObj: TheSenderVC? to var TheSenderVCObj = TheSenderVC()
let try below code:
class TheReceiverVc1: theCommunicationsStructionProtocol{
var TheSenderVCObj = TheSenderVC()
func delegateLuncher(){
self.TheSenderVCObj?.delegate = self
}
func dataToTransmit(Data: String) {
print("from VC1: \(Data)")
}
}
your TheSenderVCObj also nil according to your code.
NOTE: use proper naming conventions.
Because the TheReceiverVc1 was automatic deinit by ARC.
You need to save reference of the instance like that's:
class ViewController: UIViewController {
let theReceiverVc1: TheReceiverVc1 = TheReceiverVc1()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
theReceiverVc1.delegateLuncher()
}
}
Also make sure when you using delegate set it as weak var:
weak var delegate: theCommunicationsStructionProtocol?

Accessing UI operations from another class

I have a "Share on Facebook" button in my app at 3 different view controllers. So I wrote a class which name is "ShareCentral" and i want to do all sharing operations in this class. But for showing share dialog i need to pass uiviewcontroller to my ShareCentral class. I did like that:
class ShareCentral {
var UIVC: UIViewController
init(vc:UIViewController) {
self.UIVC = vc
}
func shareOnFacebook() {
var content = LinkShareContent(url: URL(string:userProfileLink)!)
do {
try ShareDialog.show(from: UIVC, content: content)
}catch (let error) {
print(error)
}
}
}
And this is my view controller:
class SettingsViewController: UIViewController {
let shareCentral = ShareCentral(vc: self)
#IBAction func shareButtonClicked(_ sender: AnyObject) {
self.shareCentral.shareOnFacebook()
}
}
I am getting following compiler error:
SettingsViewController.swift:40:41: Cannot convert value of type '(SettingsViewController) -> () -> (SettingsViewController)' to expected argument type 'UIViewController'
I know if i change the type of UIVC to "SettingsViewController" the problem will disappear. But as i said before i am gonna use this method in three different view controllers.
How can i resolve this problem?
Try this instead :
class ShareCentral {
unowned var UIVC: UIViewController
init(vc:UIViewController) {
self.UIVC = vc
}
func shareOnFacebook() {
var content = LinkShareContent(url: URL(string:userProfileLink)!)
do {
try ShareDialog.show(from: UIVC, content: content)
} catch (let error) {
print(error)
}
}
}
class SettingsViewController: UIViewController {
var shareVC: ShareVC!
override func viewDidLoad() {
super.viewDidLoad()
self.shareVC = ShareVC(vc: self)
}
#IBAction func shareButtonClicked(_ sender: AnyObject) {
self.shareCentral.shareOnFacebook()
}
}

unexpectedly found nil while unwrapping an Optional value On UILabel

In my project I have implemented a protocol which makes some URL call and return result, and my intent is to show result in UILabel. Following is my code :
protocol RestAPIResult
{
func retriveDriverInfo()
}
class RestAPICall : RestAPIResult
{
func retriveDriverInfo()
{
self.dashBoardViewController.getDriverInfo(driverProfile)
// calling another function of Next View for Lable Setup
}
}
getDriverInfo is in NextView which has Outlet of textVIew
class DashBoardViewController: UIViewController
{
override func viewDidLoad()
{
super.viewDidLoad()
restDeledate = RestAPICall()
restDeledate!.retriveDriverInfo()
// IF LABEL SET HERE NO ERROR
//totalTripLabel.text = "Testing" // NO ERROR
}
func getDriverInfo(driverInfoArray : NSArray)
{
totalTripLabel.text = "Testing" // HERE IS ERROR
}
}
If Text is set in ViewDidLoad() it doesn't crash. but when i tried to set value in delegate function it crash saying found null.
protocol RestAPIResult: NSObjectProtocol
{
func retriveDriverInfo(message: String)
}
class RestAPICall : RestAPIResult
{
override func viewDidLoad()
{
super.viewDidLoad()
//create an instance of your vc and
instance.delegate = self
//if you code for push vc then write this line there insatance.delegate = self
}
func retriveDriverInfo(message: String)
{
yourLbaelOutlet.text = message
}
}
class DashBoardViewController: UIViewController
{
weak var delegate: RestAPIResult!
override func viewDidLoad()
{
super.viewDidLoad()
}
func getDriverInfo(driverInfoArray : NSArray)
{
self.delegate.retriveDriverInfo(message: "youMessage")
}
}
*

Resources