How to get self of parent in @propertyWrapper?

I'd like to handle changed @Published someVar only after a specified interval elapses between events. How can I get self of SomeStruct inside propertyWrapper?

private var cancellableSet: Set<AnyCancellable> = []

extension Published where Value: Equatable {
    init<S>(
        wrappedValue defaultValue: Value,
        for dueTime: S.SchedulerTimeType.Stride,
        scheduler: S,
        sink: @escaping (Value) -> () ) where S: Scheduler {
        self.init(initialValue: defaultValue)

        projectedValue
            .debounce(for: dueTime, scheduler: scheduler)
            .removeDuplicates()
            .sink(receiveValue: sink)
            .store(in: &cancellableSet)

    }
}

class SomeStruct {
    @Published(
        for: 0.5,
        scheduler: RunLoop.main,
        sink: { val in
            // how to get self of SomeStruct
            print(self.someVar2) //Error: Value of type '(SomeStruct) -> () -> SomeStruct' has no member 'someVar2'
        })
    var someVar = ""
    var someVar2 = ""
}

Officially? You cannot.

Unofficially? You can use underscored subscript - check out this test in the swift repo

Underscored stuff isn't official, there are no guarantees and can be removed at any time.

The problem here is that this property wrapped will be inlined into :

private var  _someVar:Published<String> = Published<String>(
     for:0.5, 
     schedule:RunLoop.main, 
     sink:{ val in
        // how to get self of SomeStruct
        print(self.someVar2) //Error: Value of type '(SomeStruct) -> () -> SomeStruct' has no member 'someVar2'
    })
var someVar:String{
     get{ _someVar.wrappedValue}
     set { _someVar.wrappedValue = newValue }
}

And self is not defined at that time. Because this occurs before the init phase.
From what I understood from : https://github.com/apple/swift-evolution/blob/master/proposals/0258-property-wrappers.md

@Lazy var foo = 1738
translates to:
private var _foo: Lazy = Lazy(wrappedValue: 1738)
var foo: Int {
get { return _foo.wrappedValue }
set { _foo.wrappedValue = newValue }
}

I can add Observe method and pass all parameters to there

private var cancellableSet: [String: AnyCancellable] = [:]

extension Published where Value: Equatable {
    init(wrappedValue defaultValue: Value) {
        self.init(initialValue: defaultValue)
    }
    
    mutating func Observe<S>(
        key: String,
        for dueTime: S.SchedulerTimeType.Stride,
        scheduler: S,
        sink: @escaping (Value) -> () ) where S: Scheduler {

        print(key)
        if cancellableSet[key] == nil {
            cancellableSet[key] =
                self.projectedValue
                    .debounce(for: 0.5, scheduler: RunLoop.main)
                    .removeDuplicates()
                    .sink(receiveValue: sink)
        }
    }
}

class SomeClass {
    @Published
    var someVar = "" {
        willSet {
            _someVar.Observe(key: #function, for: 0.5, scheduler: RunLoop.main) { val in
                print(val)
            }
        }
    }
    var someVar2 = ""
    
    func test() {
        someVar = "a"
        someVar = "ab"
        someVar = "abc"
    }
}

SomeClass().test()

I did get how to implement underscore subscript inside Published. Can you send some example? You can review my solution here.

I can't use get and set with property wrapper.

I'm not saying that's what you should do, I'm saying : "that's what the compiler does when you use a property wrapper.".

Is there a reason this is unofficial? Or a plan to make it official. It doesn't seem right that Apple can implement something like @Published but no-one else can.

(I'm assuming) there wasn't enough time for all the necessary bikeshedding before they had to release swift 5.1. If we tried to design good way to user self from property wrappers, then either we would miss the deadline for swift 5.1, or we would end up with a nonideal api for it. As Shigeru Miyamoto said: A delayed feature is eventually good, but a rushed feature is locked in the api forever.

It's in the future directions in the property wrappers proposal. The roadmap to making it official is just like every other swift feature: someone needs to make a new proposal, there would be lots of people trying to make that feature better, the proposal will be accepted, someone will implement these upgrades and then it will be official.

Everyone can implement something like that, you just cannot complain when stuff doesn't work 100% correctly, or breaks in the future.

1 Like

Everyone can implement something like that, you just cannot complain when stuff doesn't work 100% correctly, or breaks in the future.

Ah so its not like using a private API that gets you rejected from the AppStore?

Good comparison with Apple private apis! Underscored stuff is a private api of compiler/stdlib people.

I haven't heard about anyone's app being rejected for using underscored stuff, but I haven't heard about anyone using it in released apps, so I have no idea.

1 Like