With the new @Observable
macro, setting up MVVM in SwiftUI has become much simpler. We shall explain the setup by trying to build the following page:
1. Setup ViewModel
struct User { let name: String let profileImgUrl: String } struct ChatMessage { var message: String } struct HomePageChat: Identifiable { let id = UUID() let sender: User var latestMessage: ChatMessage } @Observable class HomePageViewModel { var chats: [HomePageChat] = [] init() { setupDummyData() } private func setupDummyData() { let userA = User(name: "Tim Cook", profileImgUrl: "https://www.apple.com/leadership/images/bio/tim-cook_image.png.og.png?1685138662136") let messageA = ChatMessage(message: "Hello! Tim Cook here, how are you doing?") let chatA = HomePageChat(sender: userA, latestMessage: messageA) let userB = User(name: "Craig Federighi", profileImgUrl: "https://www.apple.com/leadership/images/bio/craig_federighi_image.png.og.png?1685171686562") let messageB = ChatMessage(message: "I am Craig Federighi, who are you?") let chatB = HomePageChat(sender: userB, latestMessage: messageB) self.chats = [chatA, chatB] } }
Note that all we need to do is to mark our HomePageViewModel
with @Observable
macro to make our viewModel observable by SwiftUI views.
2. Setup Views
struct HomePageView: View { @Environment(HomePageViewModel.self) private var viewModel var body: some View { NavigationView { VStack { List(viewModel.chats) { chat in HomePageCellView(chat: chat) } .listStyle(.sidebar) } .navigationTitle("Chats") .navigationBarTitleDisplayMode(.large) } } } #Preview { HomePageView() .environment(HomePageViewModel()) }
struct HomePageCellView: View { let chat: HomePageChat var body: some View { HStack { VStack(alignment: .leading) { AsyncImage(url: URL(string: chat.sender.profileImgUrl)) { image in image .resizable() .scaledToFill() } placeholder: { ProgressView() } .frame(width: 50, height: 50) .clipShape(Circle()) .clipShape(Circle()) } VStack(alignment: .leading) { Text(chat.sender.name) .bold() .padding(.bottom, 1) Text(chat.latestMessage.message) .foregroundStyle(.gray) .font(.system(size: 12)) .fixedSize(horizontal: false, vertical: true) } .padding(.leading, 6) Spacer() VStack { Text("Yesterday") .foregroundStyle(.gray) .font(.system(size: 12)) Spacer() } } .padding(.leading, 0) .padding(.vertical, 6) .frame(height: 60) } }
Top comments (0)