15

I want to have an optional @ObservedObject in SwiftUI but I keep getting a compile time error of.

Property type 'AModel?' does not match that of the 'wrappedValue' property of its wrapper type 'ObservedObject'

Here is some minimum reproducible code.

import SwiftUI

public struct AView: View {
    
    //MARK: View Model
    //Error thrown here.
    @ObservedObject var model: AModel?
    
    //MARK: Body
    public var body: some View {
        Text("\(model?.value ?? 0)")
    }
    
    //MARK: Init
    public init() {
        
    }
    
}

class AModel: ObservableObject {
    let value: Int = 0
}
Jon Vogel
  • 5,244
  • 1
  • 39
  • 54
  • Why not making `value` optional in **AModel**, that would be more doable thing! – ios coder Apr 12 '21 at 18:58
  • I'm currently refactoring that way but I'd still like to know why this does not seem to work? – Jon Vogel Apr 12 '21 at 19:07
  • I know what you trying to do, And I guess you want have multi option on your custom View wether you have a model or not(nil), if is that what you want, we can solve the issue in other way. – ios coder Apr 12 '21 at 19:13
  • `Optional` is an enum - not a class, so it cannot conform to `ObservableObject`. – New Dev Apr 12 '21 at 20:17

2 Answers2

15

The technical reason is that Optional is not a class, so it cannot be conformed to ObservableObject.

But if you want to avoid refactoring the object itself - for example, if it's not in your control - you could do something like this:

struct AView: View {

    private struct Content: View {
       @ObservedObject var model: AModel
       var body: some View {
          Text("\(model.value)")
       }
    }

    var model: AModel?
    
    var body: some View {
       if let model = model {
          Content(model: model)
       } else {
          Text("0")
       }
    }    
}
New Dev
  • 48,427
  • 12
  • 87
  • 129
5

You actually want your init argument to be optional, not the struct property. In your case I would simply do:

import SwiftUI

public struct AView: View {
    
    //MARK: View Model
    @ObservedObject var model: AModel
    
    //MARK: Body
    public var body: some View {
        Text("\(model.value)")
    }
    
    //MARK: Init
    public init(model: AModel? = nil) {
        self.model = model ?? AModel()
    }
    
}

class AModel: ObservableObject {
    let value: Int = 0
}

melMass
  • 3,813
  • 1
  • 31
  • 30