// Define it like this:
func itemView(@Binding _ user: User) -> some View { ... }
// Call it like this:
List($model.users) { $user in
itemView($_: $user) // 👈👈 🐞 Compiler error here: Extraneous argument label '$_:' in call
}
// omit parameter label call should work ...
// but as of Xcode Version 13.0 beta 4 (13A5201i), the above do not compile
// this works:
// Define it like this:
func itemView(@Binding user: User) -> some View { ... }
// Call it like this:
List($model.users) { $user in
itemView($user: $user)
}
// Or call it this way:
List($model.users, rowContent: itemView($user:)) // 👈👈 💥 this cause preview to crash, sim okay
import SwiftUI
struct User: Identifiable {
let id = UUID()
var name: String
var isContacted = false
}
final class Model: ObservableObject {
@Published var users: [User]
init(_ users: [User]) {
self.users = users
}
}
struct ContentView: View {
@EnvironmentObject private var model: Model
// 0) instead of the following, which works
// would like to extract the `rowContent` closure to a separate func
var bodyOG: some View {
List($model.users) { $user in
//
// 1) **** want to extract the following to a func itemView(...)
//
VStack {
HStack {
Text(user.name)
Spacer()
Toggle("User has been contacted", isOn: $user.isContacted)
.labelsHidden()
}
Text("Contacted: \(user.isContacted ? "Yes" : "No")")
}
}
}
// 2) I want this way
var body: some View {
// this does not work
// rowContent signature is <#T##(Binding<Data.Element>) -> RowContent#>
// List($model.users, rowContent: itemView) // Compile error: Cannot convert value of type '(User) -> some View' to expected argument type '(Binding<[User]>.Element) -> some View' (aka '(Binding<User>) -> some View')
// this also doesn't work
List($model.users) { $user in
itemView($user)
}
}
// 3) *** what's the correct thing to do here?
// what should the function signature be using SE-0293 syntax?
func itemView(@Binding _ user: User) -> some View { // Compile error: Property type 'Binding<[User]>.Element' (aka 'Binding<User>') does not match 'wrappedValue' type 'User'
VStack {
HStack {
Text(user.name)
Spacer()
Toggle("User has been contacted", isOn: $user.isContacted)
.labelsHidden()
}
Text("Contacted: \(user.isContacted ? "Yes" : "No")")
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
let data = [
User(name: "Larry"),
User(name: "Curly"),
User(name: "Moe")
]
ContentView()
.environmentObject(Model(data))
}
}
I don't have beta access to mess around with the new toys, but that seems weird. Since user is a Binding and the projectedValue of a Binding (which I think is what $user means) should give you the binding itself, I would expect $user to be a valid reference. Maybe I'm misunderstanding how it is supposed to work. My knowledge of Binding is mostly academic rather than practical.
The rowContent closure parameter is a Binding<User>. The magic happen with SE-0293: if you name the parameter as $user, which is still a Binding<User>, SE-0293 then defines user as $user.wrappedValue.
How to write a func for the rowContent closure? Seems to me this should work:
func itemView(_ user: Binding<User>) -> some View {
why is this compile error:
Property type 'Binding<[User]>.Element' (aka 'Binding<User>') does not match 'wrappedValue' type 'User'
AFAICT, you want to pass in Binding<User>, which is an API wrapper, and use a wrapped User on callee side. In that case, the function signature should look like this:
func itemView(@Binding _ user: User) -> some View {
// `_user` is `Binding<User>`
// `$user` is `Binding<User>`
// `user` is `User`
}
and the call site could look like this:
// `x` is `Binding<User>`
itemView($_: x)
Technically, you're passing the projectedValue when using this syntax. It is a little confusing in case of Binding because its projected value has the same type as the storage. Let's say we have a wrapper:
struct Storage {
var projectedValue: Projected
var wrappedValue: Wrapped
init(projectedValue: Projected) { ... }
init(wrappedValue: Wrapped) { ... }
}
and a function:
function a(@Storage x: ...) {
// `_x` is `Storage`
// `$x` is `Projected`
// `x` is `Wrapped`
}
Then you can to pass the storage's projected value or wrapped value. In both cases, the language uses the appropriate initializer to create a newStorage:
Does the compiler generate two different function signatures?
I was hoping to do this (So that I can avoid adding one extra closure and call itemView directly):
List($model.users, rowContent: itemView)
// Compile error: Cannot convert value of type '(User) -> some View' to expected argument type '(Binding<[User]>.Element) -> some View' (aka '(Binding<User>) -> some View')
but this does not compile. I wish there is something like this:
List($model.users, rowContent: itemView[use the $ version of this])
We can't create this issue for you right now, it could be due to unsupported content you've entered into one or more of the issue fields. If this situation persists, contact your administrator as they'll be able to access more specific information in the log file.
Odd compiler error:
import SwiftUI
struct User: Identifiable {
let id = UUID()
var name: String
var isContacted = false
}
final class Model: ObservableObject {
@Published var users: [User]
init(_ users: [User]) {
self.users = users
}
}
struct ContentView: View {
@EnvironmentObject private var model: Model
var body: some View {
List($model.users) { $user in
itemView(user: $user) // 👈 very odd, no compile error here, but error over at the func definition!
itemView($user: $user) // change the previous line to this the error below goes away
}
}
// there is nothing wrong with this, but if the call site is wrong, compiler error here
// this erroneous error message makes to look like the func definition here is wrong, but it's fine
func itemView(@Binding user: User) -> some View { // 👈 why compile error here? => Property type 'Binding<User>' does not match 'wrappedValue' type 'User'
// fix the call site, this error goes away
EmptyView()
}
}
Property wrappers that declare an init(projectedValue:) initializer are inferred to be API-level wrappers. These wrappers become part of the function signature, and the property wrapper is initialized at the call-site of the function.
=======
Bug #1:itemView($_: $user) do not compile:
import SwiftUI
struct User: Identifiable {
let id = UUID()
var name: String
var isContacted = false
}
final class Model: ObservableObject {
@Published var users: [User]
init(_ users: [User]) {
self.users = users
}
}
struct ContentView: View {
@EnvironmentObject private var model: Model
var body: some View {
List($model.users) { $user in
itemView($_: $user) // 👈👈 🐞 Compiler error here: Extraneous argument label '$_:' in call
}
}
func itemView(@Binding _ user: User) -> some View {
EmptyView()
}
}
Bug #2: Xcode SwiftUI preview crash, run in sim is fine:
import SwiftUI
struct User: Identifiable {
let id = UUID()
var name: String
var isContacted = false
}
final class Model: ObservableObject {
@Published var users: [User]
init(_ users: [User]) {
self.users = users
}
}
struct ContentView: View {
@EnvironmentObject private var model: Model
var body: some View {
List($model.users, rowContent: itemView($user:)) // 👈👈 💥 this cause preview to crash
// this works:
List($model.users) { $user in
itemView($user: $user)
}
}
func itemView(@Binding user: User) -> some View {
EmptyView()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
let data = [
User(name: "Larry"),
User(name: "Curly"),
User(name: "Moe")
]
ContentView()
.environmentObject(Model(data))
}
}
This one maybe problem with SwiftUI preview and how it interact with SE-0293.
Crash log
CompileDylibError: Failed to build ContentView.swift
Check the issue navigator for any compilation errors.
Apple Swift version 5.5 (swiftlang-1300.0.27.6 clang-1300.0.27.2)
While evaluating request ASTLoweringRequest(Lowering AST to SIL for file "/Users/mateo/Library/Developer/Xcode/DerivedData/PreviewCrashForFuncWPropWrapperParam-dwnrppkkgaqzyibjpemqiooqvwqg/Build/Intermediates.noindex/Previews/PreviewCrashForFuncWPropWrapperParam/Intermediates.noindex/PreviewCrashForFuncWPropWrapperParam.build/Debug-iphonesimulator/PreviewCrashForFuncWPropWrapperParam.build/Objects-normal/x86_64/ContentView.2.preview-thunk.swift")
While silgen emitFunction SIL function "@$s36PreviewCrashForFuncWPropWrapperParam11ContentViewV0abcdefg1_a12Replacement_hI2_2E15__preview__body33_7817697A203B92A1C9DFE2D362513A75LLQrvg".
for getter for __preview__body (at /Users/mateo/Library/Developer/Xcode/DerivedData/PreviewCrashForFuncWPropWrapperParam-dwnrppkkgaqzyibjpemqiooqvwqg/Build/Intermediates.noindex/Previews/PreviewCrashForFuncWPropWrapperParam/Intermediates.noindex/PreviewCrashForFuncWPropWrapperParam.build/Debug-iphonesimulator/PreviewCrashForFuncWPropWrapperParam.build/Objects-normal/x86_64/ContentView.2.preview-thunk.swift:28:49)
While silgen closureexpr SIL function "@$s36PreviewCrashForFuncWPropWrapperParam11ContentViewV0abcdefg1_a12Replacement_hI2_2E15__preview__body33_7817697A203B92A1C9DFE2D362513A75LLQrvgAC04itemI04userQr7SwiftUI7BindingVyAA4UserVG_tFQOy_Qo_ANcACcfu_".
for expression at [/Users/mateo/Library/Developer/Xcode/DerivedData/PreviewCrashForFuncWPropWrapperParam-dwnrppkkgaqzyibjpemqiooqvwqg/Build/Intermediates.noindex/Previews/PreviewCrashForFuncWPropWrapperParam/Intermediates.noindex/PreviewCrashForFuncWPropWrapperParam.build/Debug-iphonesimulator/PreviewCrashForFuncWPropWrapperParam.build/Objects-normal/x86_64/ContentView.2.preview-thunk.swift:28:40 - line:28:55] RangeText="itemView($user:"