使用 SwiftUI 的 For Each 来确定将哪个视图添加到列表中

Using SwiftUI's For Each to determine which View to Add to the List

我正在尝试使用 ForEach 在 SwiftUI 中重新创建下面的 UIKit

func configureCell(for post: MediaPost, in tableview: UITableView) -> UITableViewCell {
    if let post = post as? TextPost {
        let cell = tableview.dequeueReusableCell(withIdentifier: CellType.text) as! TextPostCell
        return cell
    } else{
        guard let post = post as? ImagePost  else { fatalError("Unknown Cell") }
        return cell
    }
}

这是我的模型

protocol PostAble {
    var id:UUID { get }
}

struct MediaPost: PostAble,Identifiable {
    let id = UUID()
    let textBody: String?
    let userName: String
    let timestamp: Date
    let uiImage: UIImage?
}


struct RetweetMediaPost: PostAble,Identifiable {
    let id = UUID()
    let userName: String
    let timestamp: Date
    let post: MediaPost
}

所以我在 ViewModel 中创建了一个数组

class PostViewModel: ObservableObject {
  @Published var posts: [PostAble] = []
}

我想用 ForEach 迭代这个数组并建立一个视图列表。 这是我写的代码

struct PostListView: View {
    @ObservedObject var postViewModel = PostViewModel()
    var body: some View {
        List {
            ForEach(postViewModel.posts, id: \.id) { post in
                if let post = post as? MediaPost {
                    PostView(post: post)
                } else {
                    guard let post = post as Retweet else { fatalError("Unknown Type") }
                    RetweetView(post: post)
                }

            }
        }
    }
}

这给了我这个错误

Type '()' cannot conform to 'View'; only struct/enum/class types can conform to protocols

我明白这个错误,我知道它失败的原因,但没有其他解决方案可以重写。 这可以用 swiftUI 实现吗?

尝试以下操作。使用 Xcode 11.4 / iOS 13.4.

测试

注意:您在视图中创建了视图模型,因此请确保您也在视图中填充它,例如。在.onAppear中,否则声明对外提供即可

struct PostListView: View {
    @ObservedObject var postViewModel = PostViewModel()
    // @ObservedObject var postViewModel: PostViewModel  // for external !!

    var body: some View {
        List {
            ForEach(postViewModel.posts, id: \.id) { post in
                self.view(for: post)
            }
        }
    }

    private func view(for post: PostAble) -> some View {
        let mediapost = post as? MediaPost
        let retweet = post as? RetweetMediaPost
        return Group {
            if mediapost != nil {
                PostView(post: mediapost!)
            }
            if retweet != nil {
                RetweetView(post: retweet!)
            }
        }
    }
}