Ol Sen
Ol Sen

Reputation: 3348

Declare property like @Publisher in swift version that doesnt support this feature using OpenCombine Framework

working on backward compatibility for an macOS App that does not make use of SwiftUI but makes use of Combine Framework feature @Published declarations that is also not available in this particular targeted System and also not in this Swift version. The feature set that Combine offers is mimicked with OpenCombine see Github framework and seems to work. But @Published declarations are not available (yet).

As this Swift @Published directive can't be expressed in code how could i (hopefully) declare such feature instead?

My thought is i could make use of the @propertyWrapper feature instead and implement some extra function to make it work..

for discussion..
in the OpenCombine.ObservableObject aka ObservableObject is some property

import OpenCombine
class SomeObservableClass : OpenCombine.ObservableObject {
    @Published var highlighted = false //where @Published feature is not available
}

and on the other side in a NSView subclass

import OpenCombine
class SomeViewController: NSViewController {
    private var cancellables = Set<AnyCancellable>()
    
    override var representedObject: Any? {
        didSet {
            guard let observedObject = representedObject as? SomeObservableClass,
                  isViewLoaded else { return }
            observedObject.$highlighted
                .receive(on: DispatchQueue.main)
                .sink { [weak self] newValue in
                    self?.overlayView.needsDisplay = true
                }
                .store(in: &cancellables)
        }
    }
}

and the following looks promising to me, at least it would allow to mimic "@Published" directive manually in some way. The propertyWrapper i would place in #if .. #endif marks to be able to have the same codebase for Swift that supports Combine & @Published features then

@propertyWrapper
struct Published<T> {
    var wrappedValue: T {
        willSet { /*...*/ }
        didSet { /*...*/ }
    }
    init(wrappedValue: T) {
        
        // * -- maybe magic here! -- */
        
        /* or do more specific stuff.. ^^
        switch (wrappedValue) {
        //case is Optional<Any>.Type :
            //break
        case is Bool :
            break
        case is Error :
            break
        case is Optional<Error>.Type :
            break
        default: break
        }
        */
        self.wrappedValue = wrappedValue
    }

}

Reminder: Combine is an Apple Framework that is heavily used in the SwiftUI Framework but of course also available without. So targeting SwiftUI solutions are not really desired as thats the whole point to be able to use the "Combine-Design-pattern" without SwiftUI. link to Github issue i opened

Reminder2: we also have preprocessor directives like #if !canImport(Combine) or similar to limit where it would be allowed to be applied

EDIT1: very likely my issue can also be some troubleing typealias rule. Because
typealias Published = OpenCombine.Published fixed the propertywrapper issue, instead i am facing the following

observedObject.$highlighted
    .receive(on: DispatchQueue.main) //<---- Argument type 'DispatchQueue' does not conform to expected type 'Scheduler'
    .sink { [weak self] newValue in
        self?.overlayView.needsDisplay = true
    }
    .store(in: &cancellables)

likewise typealias Scheduler = OpenCombine.Scheduler did not fix that as i assumed.

Upvotes: 2

Views: 307

Answers (1)

Ol Sen
Ol Sen

Reputation: 3348

for the moment it seems indeed some @propertyWrapper is the solution to allow some
@Publishedvar somethingToObserve : Type declaration in Xcode 11.3.1 targeting macOS10.14 with Swift 5.. in front to do the magic.

But also some little change of DispatchQue.main to DispatchQue.main.ocombine

import OpenCombine
import OpenCombineDispatch

and declaration of the observable

class SomeObservable: OpenCombine.ObservableObject 
{
   //...
   @Published var someobservable: MyType
   //...
}

and on the "receiver" side..

typealias Published = OpenCombine.Published

// and somewhere below...

someObserveable.$highlighted
    .receive(on: DispatchQueue.main.ocombine) 
    .sink { [weak self] newValue in
        self?.overlayView.needsDisplay = true
    }
    .store(in: &cancellables)

compiles flawless.

Upvotes: 0

Related Questions