Search code examples
iosswiftswiftuiios11combine

Swift/Combine- Assign a filtered object to a property on a class


I have a list of objects.

let arr = [[1, 2, 3, 4, 5]]

It lives in a repository.

class ArrayRepository: ObservableObject { 
     @Published let arr = [1,2,3,4,5]
} 

I have a class with a property that needs it assigned at initialization.

class MyClass: ObservableObject { 
    var id: String = ""
    var myProperty: Int? 
}

My class is created through an asynchronous process that is itself a repository.

class myClassRepository { 
   
    func buildClass -> MyClass { 
        myClassInstance = MyClass()
        self.arrayRepository.$arr.map { arr in 
            arr.filter{ $0 == someOther.Value }
        }.assign(to: \.myProperty, on: myClassInstance).store(in: &subscriptions)
       return myClassInstance
    }
} 

The problem is my pattern returns an array of elements that I cant make conform to to the singular property on the class? Whats the best way to get it out?

The error I get is essentially

Declared closure result '[Int]' is incompatible with contextual type 'Int??'

Solution

  • Due to a limitation of Swift's type system, you cannot currently assign to an Optional property with a non-Optional value. You can, however, create your own version of assign that does:

    func assign<Root: AnyObject>(to path: ReferenceWritableKeyPath<Root, Output?>, on root: Root) -> AnyCancellable {
        sink { [weak root] in root?[keyPath: path] = $0 }
    }
    

    This implementation also has the bonus of preventing a reference cycle.