How to use @_implements in a get only property?

I tried to override SwiftUI.View.body and add some test code, so I'd like to try using @_implements to redirect "var body: some View" to a custom protocol, but it looks like @_implements doesn't support get only properties?

I can find @_implements in the Swift source code for functions, and for type alias, but not for get only properties.

@_implements itself doesn't report an error, but the compiler gives me this error.

protocol TestableView {
    associatedtype Body: View
    var body: Body { get }
}

struct TestView: View, TestableView { // Type 'TestView' does not conform to protocol 'View'
                                      // Type 'TestView' does not conform to protocol 'TestableView'
    @_implements(SwiftUI.View, body)
    @ViewBuilder
    var testBody: some View {
        body
    }

    @_implements(TestableView, body)
    @ViewBuilder
    var body: some View {
        ...
    }
}
2 Likes

Did you ever figure this out? I'm looking to do something very similar and ended up with the exact same errors.

After doing a little bit of digging, I found out that @_implements does support get only variables (the name has to be different than the original requirement's name) but doesn't have automatic associatedtype resolving. For example, the following also doesn't compile:

protocol Foo {
    associatedtype T
    var a: T { get }
}

struct Bar: Foo { // 🛑 Type 'Bar' does not conform to protocol 'Foo'
    @_implements(Foo, a)
    var b: Int { 0 }
}

Adding a typealias for T resolves the issue for this case.

For your case, you need to specify the body directly. But, to not have your body type be 2000 characters long, I would suggest you extract the view:

protocol TestableView {
    associatedtype Body: View
    var body: Body { get }
}

struct TestView: View, TestableView {
    @_implements(View, Body)
    typealias BodyNormal = TestViewInternalNormal

    @_implements(TestableView, Body)
    typealias BodyTest = TestViewInternalTest

    @_implements(View, body)
    var swiftBody: TestViewInternalNormal {
        /* ... */
    }

    @_implements(TestableView, body)
    var testBody: TestViewInternalTest {
        /* ... */
    }
}

struct TestViewInternalNormal: View { /* ... */ }
struct TestViewInternalTest: View { /* ... */ }
1 Like