8

How to use delegate methods of singleton/shared class? There is one singleton class having some protocol defined but I'm not getting how to access the delegate functions in other classes.

Code snippet for a reference (swift):

protocol AClassDelegate
{
  func method1()
}

class A
{
   static let shared = A()

   override init() {
     //initialisation of member variables
   }

   var delegate: AClassDelegate
   func foo() {

   }
}


class B: AClassDelegate
{
   func bar() {
      // Note: not getting call to 'foo' method of class 'A'
      A.shared.delegate = self
      A.shared.foo()
   }
}

Is this implementation correct?

iTink
  • 129
  • 1
  • 13
  • 1
    Delegate should be always weak. – Oleg Gordiichuk Mar 23 '17 at 13:02
  • 2
    You should also add a private init() to your Class A to ensure it is always used as a singleton. As currently you could also declare A() which would not be a singleton. – totiDev Mar 23 '17 at 13:03
  • Advice: don't allow any class (like class B) to set the delegate of your singleton. Strongly consider passing in the delegate that the singleton uses at init() time. Your singleton calls delegate's method1 to get something done for it. Class B as the delegate should not be setting up (or calling really) the singleton. – Price Ringo Mar 23 '17 at 13:34
  • @Price, yes you are right! but I need to persist some data/calls of the class 'A' through out the app and also want delegation of data to calling classes, hence made it singleton. But to avoid this issue we can broadcast the information using push notification instead of delegates. right? – iTink Mar 23 '17 at 14:35

2 Answers2

14

First, I'd like to point to:

1- Creating a singleton Class should contains:

private init() {}

That leads to enforce to access the class only by using its shared instance.

2- As mentioned in Max's Answer, the delegate should be optional and has a weak reference.

3- The protocol should be a type of class, as follows:

protocol AClassDelegate: class

For more information, you might want to check this Q&A.


Now, let's assume -for testing purposes- that the method1() from AClassDelegate should be get called when calling foo() from A class:

protocol AClassDelegate: class {
    func method1()
}

class A {
    private init() {}
    static let shared = A()

    weak var delegate: AClassDelegate?

    func foo() {
        print(#function)

        delegate?.method1()
    }
}

Let's implement classes that conforms to AClassDelegate:

class B: AClassDelegate {
    func bar() {
        A.shared.delegate = self
        A.shared.foo()
    }

    func method1() {
        print("calling the delegate method B Class")
    }
}

class C: AClassDelegate {
    func bar() {
        A.shared.delegate = self
        A.shared.foo()
    }

    func method1() {
        print("calling the delegate method C Class")
    }
}

Output should be:

let b = B()
b.bar()
// this will print:
/*
 foo()
 calling the delegate method B Class
 */

let c = C()
c.bar()
// this will print:
/*
 foo()
 calling the delegate method C Class
 */
Ahmad F
  • 30,560
  • 17
  • 97
  • 143
5

It's almost correct. You don't take into account that the singleton lives forever (unless you destroy it somewhere), but its delegate may not. So in order to avoid crashes set the delegate property to weak and optional.

weak var delegate: AClassDelegate?

This way you shouldn't care if the delegate exists or not.

Max Pevsner
  • 4,098
  • 2
  • 18
  • 32