【问题标题】:Xcode Beta 6 "Type of expression is ambiguous without more context" navigationlinkXcode Beta 6“没有更多上下文的表达式类型不明确”导航链接
【发布时间】:2019-08-20 19:57:05
【问题描述】:

自从今天早些时候更新到 Xcode Beta 6 后,我的应用程序将不再构建,它在 Beta 5 及更早版本中运行良好。

这是包含错误消息的文件中的代码,尽管我现在知道这并不一定意味着这就是错误的实际所在。

import SwiftUI

struct JobView_Table : View {

    @ObservedObject var jobList: JobDetailViewModel = JobDetailViewModel()

    var body: some View {

        NavigationView {

            List {
                ForEach($jobList.jobDetails) { job in
                    NavigationLink(destination: JobDetailHost(jobDetails: job)) { // ERROR: "Type of expression is ambiguous without more context"
                        JobView_List(jobDetails: job)
                    }
                }
            }

            .navigationBarTitle(Text("My Jobs"))
            .onAppear(perform: fetchData)
            .onAppear(perform: {
                print("Hello!")
            })

        }
    }

    private func fetchData() {
        return(jobList.updateDetails())
    }
}

包含数据的结构正确地符合以下协议。

struct JobDetails: Codable, Identifiable, Equatable, Hashable { 
    ...

    ...
}

这是向JobView_Table 提供数据的类。

import Foundation
import UIKit
import Combine

class JobDetailViewModel: ObservableObject, Identifiable {

    @Published var jobDetails: [JobDetails] = []

    func updateDetails() {
        self.jobDetails = DataManager().fetchJobList()
    }

}

最后是通过NavigationLink链接到的目标视图。

struct JobDetailHost: View {

    @Environment(\.editMode) var mode
    @Binding var jobDetails: JobDetails


    var body: some View {

        VStack {
            JobDetailView(jobDetails: jobDetails)
        }
        .navigationBarItems(trailing: EditButton())
    }

}

我注意到其他一些人似乎也有类似的问题,即在下面列出的两个问题中,但目前探索这些问题的答案对我没有帮助。 SwiftUI Xcode 11 beta 5 / 6: Type of expression is ambiguous without more context

SwiftUI: Why does ForEach($strings) (text: Binding) not build?

编辑:

我已经尝试实施 Fabian 的建议,这已经消除了错误,但是列表中没有填充任何内容。

这是调整后的List 代码,编译成功但运行应用程序时列表未填充。

List {
    ForEach(jobList.jobDetails.indexed(), id: \.1.id) { (index, job) in
            NavigationLink(destination: JobDetailHost(jobDetails: self.$jobList.jobDetails[index])) {
                        Text(job.jobName)
                    }
     }
}

下面不使用ForEach,丢弃NavigationLink,还是不行。

List(jobList.jobDetails.indexed(), id: \.1.id) { (index, job) in
                Text(job.jobName)
            }

【问题讨论】:

    标签: swift xcode swiftui


    【解决方案1】:

    我会引用macOS Catalina 10.15 Beta 6 Release Notes

    Binding 结构对 Collection 的条件一致性 协议被删除。 (51624798)

    如果你有如下代码:

    struct LandmarkList: View {
        @Binding var landmark: [Landmark]
    
        var body: some View {
            List(landmarks) { landmark in
                Toggle(landmark.value.name, isOn: landmark[\.isFavorite])
            }
        }
    }
    

    定义以下集合类型:

    struct IndexedCollection<Base: RandomAccessCollection>: RandomAccessCollection {
        typealias Index = Base.Index
        typealias Element = (index: Index, element: Base.Element)
    
        let base: Base
    
        var startIndex: Index { base.startIndex }
    
        var endIndex: Index { base.endIndex }
    
        func index(after i: Index) -> Index {
            base.index(after: i)
        }
    
        func index(before i: Index) -> Index {
            base.index(before: i)
        }
    
        func index(_ i: Index, offsetBy distance: Int) -> Index {
            base.index(i, offsetBy: distance)
        }
    
        subscript(position: Index) -> Element {
            (index: position, element: base[position])
        }
    }
    
    extension RandomAccessCollection {
        func indexed() -> IndexedCollection<Self> {
            IndexedCollection(base: self)
        }
    }
    

    然后,将您的代码更新为:

    struct LandmarkList: View {
        @Binding var landmarks: [Landmark]
    
        var body: some View { // Does often give error on id: \.1.id
            List(landmarks.indexed(), id: \.1.id) { (index, landmark) in
                Toggle(landmark.name, isOn: self.$landmarks[index].isFavorite)
            }
        }
    }
    

    您的代码也采用 Binding&lt;[JobDetails]&gt;$jobList.jobDetails,但 Binding&lt;[JobDetails]&gt; 不再符合 Collection 协议。

    但是请注意上面的解决方案,我遇到了 \.1.id 无法识别的情况,因为编译器不理解 \.1 是指 IndexedCollection 定义的元组中的第二个元素,但有可能我用错了。可以重写它,但是让它工作。

    使用 IndexedCollection 的示例

    struct AnotherIndexedView_NeedsEnv: View {
        @EnvironmentObject var modalManager: ModalManager
    
        var body: some View {
            ZStack {
                SwiftUI.ForEach(modalManager.modals.indexed()) { m in
                    ModalView(currentModal: self.$modalManager.modals[m.index]).environmentObject(self.modalManager)
                }
            }.onAppear(perform: {self.modalManager.fetchContent()})
        }
    }
    

    【讨论】:

    • 感谢您的帮助 Fabian。我已经更新了我的答案,试图让它发挥作用,但成功有限。代码现在在实现发行说明中的​​更改后编译,但列表现在不显示任何内容。我已更新我的答案以添加更改。
    • @JamesWoodcock 发行说明中的​​实现确实存在索引错误.. :P
    • 这有点无益...这就是您在答案的最后一部分中所说的内容。您对如何完成这项工作有什么建议吗?谢谢
    • 对了。将其更改为var endIndex: Index { base.endIndex }
    • 太棒了,现在按预期工作。 :) 非常感谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-03-05
    • 2019-11-03
    • 1970-01-01
    • 2022-11-23
    • 2021-05-17
    • 2019-04-23
    相关资源
    最近更新 更多