9

Please read the question to the end as it seems to be the duplicate of many similar others but it is not. Most of the other questions use closures with let keyword to capture weak or unowned self before object init. I do not.

My code:

class Singleton : ObserverProtocol {

    static let shared = Singleton()

    private let obs : Observer = Observer.init()

    private init() { self.obs.responder = self }

    func observe(_ object : Any) {}

    fileprivate class Observer : NSObject {
        unowned var responder : ObserverProtocol!
        func observe(_ obj : Any) {
            self.responder.observe(obj)
        }
    }
}

fileprivate protocol ObserverProtocol : class {
    func observe(_ object : Any)
}

When I try to compile I get an error highlighted on unowned var responder : ObserverProtocol!

'unowned' may only be applied to class and class-bound protocol types, not 'ObserverProtocol!'

If I change unowned to weak I can compile.

There is clearly some concept about unowned that I don't understand, so I would appreciate if someone could explain it to me.

P.S. I am aware of multiple questions similar to this:

UIView, CMDeviceMotionHandler : unowned may only be applied to class and class-bound protocol types

But I suppose this is not my case.

iur
  • 2,056
  • 2
  • 13
  • 30

1 Answers1

16

As you already know, unowned cannot be optional but weak may be nil at some point.

From what I understand, unowned variable is different from implicitly unwrapping optionals. Implicit unwrapping is for variables, which may be nil, but we already know this variable is not nil at the exact point of access. However, unowned variable can never be nil at any point.

Thus, you can't use unowned constant of type ObserverProtocol!. You need to get rid of !.

But if you do get rid of !, Observer needs an initializer that initializes responder.

sCha
  • 1,454
  • 1
  • 12
  • 22
  • 2
    Yes. I totally forgot about this passage `An unowned reference is expected to always have a value. As a result, ARC never sets an unowned reference’s value to nil, which means that unowned references are defined using nonoptional types.` – iur Aug 29 '17 at 14:47
  • On a side note, imho this is one of the things that swift core team didn't think thru. Creation of interdependent objects. Their semiofficial answer is to use unwrapped optionals for such cases but it appears that it doesn't cover all of the possible use cases. Which forces you to use non-'swifty' workarounds or worsens clarity of intent. – iur Aug 29 '17 at 14:50
  • @iur I guess you are always welcome to participate in the Swift project since it's an open source. It sounds like an interesting topic to get started :) – sCha Aug 29 '17 at 14:56