skip to Main Content

I have the a model with a published name property:

@MainActor class MyModel:ObservableObject {
    
    @Published private(set) var name = ""

    ....

}

I am wondering why sink works when used on model.$name and not on model.name.publisher.

model.$name
    .receive(on: RunLoop.main)
    .sink { name in
        ....            <-- it's called. works.
    }
    .store(in: &subs)

This does not get called:

model.name.publisher
    .receive(on: RunLoop.main)
    .sink { name in
        ....            <-- does not get called.
    }
    .store(in: &subs)

Can someone explain exactly why I have to use the $ sign in front of name and why name.publisher does not work?

2

Answers


  1. $name is how you access the underlying Publisher of the @Published property wrapper.
    This publisher will emit every time the name property mutates and probably that’s what you want.

    With model.name.publisher you get a Publisher that will emit each character of the String and then complete (It’s defined on a Sequence extension)
    If you have:

    @MainActor class MyModel:ObservableObject {
        
        @Published private(set) var name = "foo"
    
        ....
    
    }
    

    You will see f - o - o

    Login or Signup to reply.
  2. In this particular case, I understand why it’s confusing.

    $name refers to the publisher within the @Published property-wrapper. It is what you want.

    name.publisher is something within String. Fabio Felici’s answer explains it well. It will cycle through characters (it returns String.Element) of the current string, rather than new values of the string when it is swapped out. For that, use $name. (on which sink returns a String type for each change.)

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search