Call view controller method from custom class - ios

I have a custom class and a view controller.
My custom class:
class ChatManager:NSObject {
func messageArrived() {
//When Message arrives I am handling it from here
//I need something like that: Viewcontroller.updateTable()
}
}
When message arrives from internet I need to update tableview in view controller. So I mean I have to call a view controller method from messageArrived method. How can I do this ?

Here is a simple example of using delegate:
declare the delegate before your chat manager class
protocol ChatManagerDelegate {
func manageMessage()
}
when the message arrived, call the delegate method to handle it.
class ChatManager: NSObject {
var delegate: ChatManagerDelegate?
func messageArrived() {
self.delegate!.manageMessage()
}
}
in your view controller, remember to set the delegate of the chat manager to self.
class ViewController: ChatManagerDelegate {
var manager = ChatManager()
manager.delegate = self
func manageMessage() {
self.updateTable()
}
}

This would be a possible implementation:
ViewController:
class ViewController: UIViewController,ChatManagerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
let myChatManager = ChatManager()
myChatManager.delegate = self
}
func messageDidArrive() {
// Do Things here.
}
}
Chatmanager:
class ChatManager:NSObject {
var delegate:ChatManagerDelegate?
func messageArrived() {
//When Message arrives I am handling it from here
//I need something like that: Viewcontroller.updateTable()
}
}
Delegate-Protocol:
protocol ChatManagerDelegate{
func messageDidArrive()
}

Related

How to notify a change from a class to multiple ViewControllers?

I'm writing because I'd like to know what's the best method to notify a change from a class to multiple ViewControllers. At the moment I'm using delegate method but I'm sure It's not the best one for this purpose. I created a class where I receive data and after a bit of processing I need to send the processed message to some ViewControllers (any one shows a piece of that message.). At the moment I have a singleton for the class and I assign its delegate to a different ViewController when I load it through a menu. What's your suggestion to do this job?
Here is an example of my actual code:
import Foundation
protocol MyClassDelegate {
func receivedData(_ sender: MyClass)
}
class MyClass: NSObject {
// create the var for delegate
var delegate: MyClassDelegate?
// save the single instance
static private var instance: MyClass {
return sharedInstance
}
private let sharedInstance = MyClass()
static func getInstance() -> MyClass {
return instance
}
func processData() {
// at the end of the process
delegate?.receivedData(self)
}
}
class Menu: UIViewController {
private var containerView: UIView!
private let myClass = Myclass.getInstance()
private var vcOne = VcOne()
private var vcTwo = VcTwo()
override func viewDidLoad() {
super.viewDidLoad()
containerView = UIVIew()
// set containerView position and dimensions
}
func selectViewController(previous: UIViewController, next: UIViewController) {
// remove actual loaded ViewController
previous.willMove(toParent: nil)
previous.view.removeFromSuperView()
previous.removeFromParent()
// assign the delegate
myClass.delegate = next
// add the new ViewController
self.addChild(next)
slef.addSubView(next.view)
next.didMove(toParent: self)
}
}
class VcOne: UIViewController, MyClassDelegate {
func receivedData(_ sender: MyClass) {
// data received
}
}
class VcTwo: UIViewController, MyClassDelegate {
func receivedData(_ sender: MyClass) {
// data received
}
}
You can use NotificationCenter https://developer.apple.com/documentation/foundation/notificationcenter to broadcast a message. or use KVO. Generally I consider notification center much easier.
simple example:
https://www.hackingwithswift.com/example-code/system/how-to-post-messages-using-notificationcenter

Calling delegate methods from extension throws nill, but works on action event

Below is the code snippet, delegate never calls when XMPPStreamDelegate methods called periodically. Presence service delegate throws nil inside of extension but gives value when calling some action from another view controller.
public protocol PresenceServiceDelegate{
func didPresenceReceive()
}
class PresenceService: NSObject{
var delegate: PresenceServiceDelegate?
public override init()
delegate = self
}
}
extension PresenceService: XMPPStreamDelegate {
public func didReceive presence() // XMPPStrem delegate
// My Presence Service delegate not at all calling (delegate throws nil )
delegate?.didPresenceReceive()
}
}
class ViewController: UIViewController{
var presence = PresenceService()
func viewDidLoad() {
presence.delegate = self
}
}
extension ViewController: PresenceServiceDelegate {
public func didPresenceReceive(){
print("test")
}
}
The Below code works fine as expected. During XMPPStreamDelegate calls presenceservice delegate object throws nill and not recognised, here the below code calling instance of presenceservice's class which enabling it's own delegate instance and triggered value to the view controller as expected.
class PresenceService: NSObject{
var delegate: PresenceServiceDelegate?
public override init()
delegate = self
}
// Singleton instance
public class var sharedInstance : PresenceService {
struct PresenceServiceInstance {
static let instance = PresenceService()
}
return PresenceServiceInstance.instance
}
}
extension PresenceService: XMPPStreamDelegate {
public func didReceive presence() // XMPPStrem delegate
// My Presence Service delegate not at all calling (delegate throws nil )
PresenceServiceInstance.sharedInstance.delegate?.didPresenceReceive()
}
}

Weak delegate becomes nil

In my app I'm using delegates, so that I can read the data when ever it's ready.
I'm calling a delegate from two classes. Here is my code
protocol MyDelegate: class {
func getData()
}
class MyDelegateCalss {
weak var delegate: MyDelegate?
func loadData() {
// doing some actions
if(self.delegate != nil){
self.delegate!.getData!()
}
}
}
In one class I'm loading this method in tableview numberOfSections delegate method.
class A: UIViewController, MyDelegate {
func somefunc(){
let mydelegatecls : MyDelegateCalss = MyDelegateCalss()
mydelegatecls.delegate = self
mydelegatecls.loadData()
}
func getData(){
// Doing some actions
}
}
This method I'm loading from another calss.
class B: UIViewController, MyDelegate {
open func testfunc(){
let mydelegatecls : MyDelegateCalss = MyDelegateCalss()
mydelegatecls.delegate = self
mydelegatecls.loadData()
}
func getData(){
// doing some other stuff
}
}
class C: UIViewController {
func testfunc(){
let b : B = B()
b.testfunc()
}
}
Here from class A my delegate is working fine. and I'm able to see getData method is calling .
from Class B, the delegate becomes nil and unable to see getData method is called
If I make the delegate reference its working fine. But that will cause memory leak.
How can handle this case ?
Your delegate var is declared as weak. If nothing keep a strong reference on the object you assign as the delegate (implementing MyDelegate), your delegate will pass to nil as soon as the object is released (eg. the end of the scope where you instantiate it).
Some good read: https://cocoacasts.com/how-to-break-a-strong-reference-cycle/

delegate in swift 3 does not perform view related codes

In my project I have some delegates that works fine with returning data but I want to add some subview or do any anything in the delegate method on the receiving end nothing happen but the other codes that are in the same method are OK!
My other question is also realated to delegates :
This happens for some delegates. The delegate does not respond but I found a very strange fix on the web and I need to know why this happens and why this fix works!
My First View :
protocol SomeDelegate {
func someMethod()
}
class FirstViewClass {
//in init or didLoad method
var delegate: SomeDelegate?
// THIS DELEGATE WON'T WORK BUT WHEN I ADD THIS LINE IT WORKS FINE( IT STILL HAS THE ABOVE PROBLEM)
self.delegate = SecondViewClass()
//in some custom method
self.delegate?.someMethod();
}
My Second View:
class SecondViewClass : SomeDelegate {
var firstView = FirstViewClass()
// this is in init or didLoad method
firstView.delegate = self
//this is in some custom method
someMethod()
}
A simple working prototype:
protocol SomeDelegate {
func someMethod()
}
class FirstViewClass {
var delegate: SomeDelegate?
}
class SecondViewClass : SomeDelegate {
var firstView = FirstViewClass()
func someMethod() {
print("called via delegate")
}
}
var firstClass = FirstViewClass()
var secondClass = SecondViewClass()
firstClass.delegate = secondClass
firstClass.delegate?.someMethod()

Function Overriding in iOS

I have created BaseClassviewController and all my controllers are derived from this controller. I am doing the following steps:
Set custom delegate in BaseClassViewController.
Implement all function of protocol in BaseClassViewController.
Then I am pushing HomeController derived from BaseClassViewController.
Again I am pushing DetailController also derived from BaseClassViewController.
Now when delegate function is called I should get control in DetailController but I am getting control in HomeController.
So my question is why its not calling top controller at navigation i.e DetailController and is it possible to call delegate functions in both controllers?
P.S I am overriding delegate functions in all child controllers.
EDIT: After reading answers and comments I think I have not been clear that much so adding following code snippet.
In Helper Class:
#objc protocol SampleDelegate: class
{
#objc optional func shouldCallDelegateMethod()
}
class SampleHelper: NSObject
{
var sampleDelegate:SampleDelegate!
static var sharedInstance = SampleHelper()
//It is triggered
func triggerDelegateMethod()
{
sampleDelegate!.shouldCallDelegateMethod()
}
func apiCall()
{
let urlString = URL(string: "https://google.com")
if let url = urlString {
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
if error != nil {
print(error)
} else {
if let usableData = data {
self. triggerDelegateMethod()
}
}
}
task.resume()
}
}
}
In BaseClass
class BaseClassViewController: UIViewController,SampleDelegate{
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool)
{
super.viewWillAppear(true)
SampleHelper.sharedInstance.delegate = self;
}
func shouldCallDelegateMethod()
{
//Override
}
}
In HomeController i.e 1st controller to be pushed
class HomeViewController: BaseClassViewController{
override func shouldCallDelegateMethod()
{
//
}
}
In DetailController i.e 2nd controller is pushed after HomeController from HomeController.
class DetailViewController: BaseClassViewController{
override func viewDidLoad()
{
super.viewDidLoad()
SampleHelper.sharedInstance.apiCall()
}
override func shouldCallDelegateMethod()
{
//
}
}
Now my question is when delegate is triggered from helper class it calls shouldCallDelegateMethod in HomeViewController but not in DetailViewController. But DetailViewController is at top of navigation array.
Also is there any possibility I can trigger same function in both controller at a time with delegate only?
In BaseClassviewController you should have a delegate variable/property.
In HomeController and DetailController you need to set that delegate variable/property to self if you want that class to be listening to the delegate callbacks.
The basic problem is that you are using delegate with a singleton.
Setting the delegate in viewWillAppear is not a good solution either. In short, when view controllers are being shown and hidden, the delegate on your singleton will changed all the time.
Don't use delegates with singletons. Use a completion callback. Otherwise you will keep running into problems.
func apiCall(onCompletion: (() -> Void)?) {
let urlString = URL(string: "https://google.com")
if let url = urlString {
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
if error != nil {
print(error)
} else if let usableData = data {
onCompletion?()
}
}
task.resume()
}
}
called as
SampleHelper.apiCall {
// do something
}
Edit 2
After you posted your code, i realize that you have used the singleton class for delegation.
Delegates allows an object to send a message to another object.
Answer for your query is "No". You can not trigger same function in both controller at a time with delegate.
If you really want to listen an event in both class at a time, i would suggest you to use NSNotificationCenter instead of delegate.
Thats not the correct way to achieve this. I think proper way to set delegate only in respective UIViewController rather than implementing that protocol on BaseViewController and then overriding in child classes. So your implementation should be like.
In HomeViewController
class HomeViewController: BaseClassViewController {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
SampleHelper.sharedInstance.delegate = self;
}
func shouldCallDelegateMethod() {
// Provide implementation
}
}
In DetailViewController
class DetailViewController: BaseClassViewController {
override func viewWillAppear(_ animated: Bool) {
super.viewDidLoad()
SampleHelper.sharedInstance.delegate = self;
}
func shouldCallDelegateMethod() {
// Provide implementation
}
}
Using this imeplementation you will be having only one-to-one communication design pattern, ensuring right UIViewController to be called.

Resources