Reputation: 4733
I'm trying to recreate the UIKit below in SwiftUI using ForEach
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
}
}
Here is my model
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
}
So I have created an array in ViewModel
class PostViewModel: ObservableObject {
@Published var posts: [PostAble] = []
}
and I would like to iterate of this array with a ForEach and build up a list of views. Here is the code I wrote up
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)
}
}
}
}
}
Which gives me this error
Type '()' cannot conform to 'View'; only struct/enum/class types can conform to protocols
I understand the error and I know why it's failing but don't have another solution to rewrite. Can this be achieved with swiftUI?
Upvotes: 1
Views: 702
Reputation: 257711
Try the following. Tested with Xcode 11.4 / iOS 13.4.
Note: you created view model inside view, so make sure you fill it also in view, eg. in .onAppear, otherwise just declare to provide it externally
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!)
}
}
}
}
Upvotes: 1