【问题标题】:Question about View as Type Constraint in SwiftUI关于 SwiftUI 中 View 作为类型约束的问题
【发布时间】:2021-02-14 12:56:07
【问题描述】:

我正在尝试创建一个名为 Lesson 的类。每个课程对象应包含不同的课程页面(视图),以便每个课程卡片可以导航到不同的页面。

课程代码如下:

class Lesson<T: View>: Identifiable {
    let id = UUID()
    var lessonName: String
    var lessonPage: T
    
    init(lessonName: String,
         lessonPage: T = DefaultLessonPageView() as! T) {
        self.lessonName = lessonName
        self.lessonPage = lessonPage
    }
}

问题是编译下面的代码时出错:

struct ButtonPageView: View {
    var lesson: Lesson<View>

    var body: some View {
        NavigationLink(destination: lesson.lessonPage()) {
            some view here
        }
    }
}

错误如下:

协议类型'View'的值不能符合'View';只有结构/枚举/类类型可以符合协议

我应该怎么做才能解决这个问题?

【问题讨论】:

    标签: swift generics swiftui


    【解决方案1】:

    对于泛型,我们应该记住类型是在编译类型中推断出来的,因此在编写表达式时应该知道视图。所以 SwiftUI 使用 builder 模式来达到这个目的。

    这是一个演示如何通过支持通用页面和提供一些默认页面来解决它。

    使用 Xcode 12.4 / iOS 14.4 测试

    class Lesson<T: View>: Identifiable {
        let id = UUID()
        var lessonName: String
    
        var builder: (() -> T)?    // << optional builder
        
        @ViewBuilder
        func lessonPage() -> some View {   // ViewBuilder gives possibility
            if let page = builder?() {     // to provide default view
                page
            } else {
                DefaultLessonPageView()
            }
        }
        
        init(lessonName: String,
             lessonPage: (() -> T)? = nil) {  // by default no view
            self.lessonName = lessonName
            self.builder = lessonPage
        }
    }
    
    struct ButtonPageView<Page: View>: View {
        var lesson: Lesson<Page>
    
        var body: some View {
            NavigationLink(destination: lesson.lessonPage()) {
                Text("")
            }
        }
    }
    

    现在我们可以将它们用作

    var body: some View {
        // no view, so let compiler know
        ButtonPageView<Never>(lesson: Lesson(lessonName: "First"))
    
        // page type is inferred from builder
        ButtonPageView(lesson: Lesson(lessonName: "Second", lessonPage: {
            Text("Second Lesson")
        }))
    }
    

    【讨论】:

    • 我明白了。非常感谢。
    猜你喜欢
    • 1970-01-01
    • 2020-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多