Disclaimer: English is not my native tongue, but I’ll try my best to explain the problem.
In this image I have 2 Lists, top displays a list of PostModels and bottom a list of UserModels.
Both of which are taken from an API, I am trying to create a list where PostModels userId == UserModels id.
Expected Output: Is something like what you would see in a facebook post. Where you will see the user and text in the ListItem.
How do I achieve this?
Models
struct PostModel {
let id: Int
let userId: Int
let title: String
let body: String
}
struct UserModel {
let id: Int
let firstName: String
let lastName: String
let email: String
let image: String
}
//The 3rd model where I will store data taken from Post and User
struct PostWithUser {
let postUserId: Int
let userImg: String
let postUserName: String
let postTitle: String
let postBody: String
}
ViewModel
class DashboardViewModel: WebViewModel, ObservableObject {
var manager: UserManager = UserManager()
var postManager: PostManager = PostManager()
@Published var users: UsersModel = UsersModel(users: [UserModel(id: 0, firstName: "", lastName: "", email: "", image: "")])
@Published var posts: PostsModel = PostsModel(posts: [PostModel(id: 0,userId: 0, title: "", body: "")])
@Published var postsWithUser = [PostWithUser(postUserId: 0, userImg: "",postUserName: "", postTitle: "", postBody: "")]
func getUsers() {
manager.getUsers { [weak self] result in
switch result {
case .success(let usersModel):
DispatchQueue.main.async {
self?.users = usersModel
}
case .failure(let error):
print("Error: (error)")
}
}
}
func getPosts() {
postManager.getPosts { [weak self] result in
switch result {
case .success(let postsModel):
DispatchQueue.main.async {
self?.posts = postsModel
}
case .failure(let error):
print(error)
}
}
}
func getPostsWithUser() {
for post in self.posts.posts {
for user in self.users.users {
if user.id == post.userId {
let post = PostWithUser(postUserId: post.userId, userImg: user.image, postUserName: "(user.firstName) (user.lastName)", postTitle: post.title, postBody: post.body)
self.postsWithUser.append(post)
}
}
}
}
}
View
struct DashboardView: View {
@StateObject private var viewModel = DashboardViewModel()
var body: some View {
let users = viewModel.users.users
let posts = viewModel.posts.posts
let detailedPosts = viewModel.postsWithUser
VStack {
Text("Posts")
List {
ForEach(detailedPosts) { post in
Text(post.postTitle)
}
}.task {
viewModel.getPosts()
viewModel.getUsers()
viewModel.getPostsWithUser()
}
}
}
}
2
Answers
One solution is to look up the user using a function rather than creating a new type.
Where I have created an unknown user in an extension to
UserModel
And then use it in the view like
Note that since I don’t know what
UsersModel
looks like I changed it to an array in my code.FYI StateObject isn’t designed for legacy view model objects, in SwiftUI it’s the job of the View struct hierarchy to encapsulate view data.