Zorayr
Zorayr

Reputation: 24942

Group() not recognized as an opaque type in SwiftUI

I have a function with an if statement that in either case returns a Group(), however, SwiftUI compiler doesn't recognize it as the same type. What's going on?

Getting error:

Function declares an opaque return type, but the return statements in its body do not have matching underlying types

private func cellWithContact(_ contact: CNContact) -> some View {
    let displayName: String? = CNContactFormatter.string(from: contact, style: .fullName)
    if let displayName = displayName {
        return Group() {
            Text(displayName)
        }
    }
    return Group() {}
}

Upvotes: 1

Views: 181

Answers (3)

New Dev
New Dev

Reputation: 49590

Opaque types still require there to be a concrete single type specified by a callee, but in your function you have two different return types:

return Group { Text(displayName) } // Group<Text> type
// and also
return Group { }                   // Group<EmptyView> type

So, you need to either

  1. Use a type-erased AnyView:
return AnyView(Group { Text(displayName) }  // AnyView type
// ...
return AnyView(Group { })                   // AnyView type
  1. Ensure that they are the same type, by changing the empty one to:
return Group { Text("") }  // Group<Text> type, same as the other one
  1. Return a conditional (_ConditionalContent) view, which ViewBuilder creates automatically when encountering an if/else:
@ViewBuilder // this is required
func cellWithContact(_ contact: CNContact) -> some View {
   // ...
   if someCondition { // _ConditionalContent<Group<Text>, Group<EmptyView>> type
      Group { Text(...) }
   } else {
      Group { }
   }
}

Upvotes: 3

pawello2222
pawello2222

Reputation: 54586

Other answers are perfectly fine. Just wanted to mention that if you're using SwiftUI 2 / iOS 14 you can use control flow statements (like if-let) directly in a @ViewBuilder block:

@ViewBuilder
private func cellWithContact(_ contact: CNContact) -> some View {
    if let displayName = CNContactFormatter.string(from: contact, style: .fullName) {
        Text(displayName)
    }
}

And there’s no need to return EmptyView() which makes the code much cleaner.

Upvotes: 1

Asperi
Asperi

Reputation: 258107

Here is possible solution. Tested with Xcode 12 / iOS 14.

@ViewBuilder
private func cellWithContact(_ contact: CNContact) -> some View {
    let displayName: String? = CNContactFormatter.string(from: contact, style: .fullName)
    if let displayName = displayName {
        Text(displayName)
    } else {
        EmptyView()  // or `Group {}`, but it is the same
    }
}

Upvotes: 1

Related Questions