Here is my PostListView.
struct PostListView: View {
@StateObject private var viewModel = PostViewModel(service: PostService())
var body: some View {
NavigationView {
VStack {
if viewModel.isLoading {
ProgressView()
} else if !viewModel.errorMessage.isEmpty {
Text(viewModel.errorMessage)
} else {
List(viewModel.posts) { post in
VStack(alignment: .leading) {
Text(post.title)
.font(.headline)
Text(post.body)
.font(.subheadline)
.foregroundColor(.gray)
}
}
}
}
.navigationTitle("Posts")
}
}
}
struct PostListView_Previews: PreviewProvider {
static var previews: some View {
let viewModel = PostViewModel(service: MockPostService())
return PostListView().environmentObject(viewModel)
}
}
Here is My ViewModel
class PostViewModel: ObservableObject {
@Published var posts: [PostModel] = []
@Published var isLoading: Bool = false
@Published var errorMessage: String = ""
private let service: ServiceProtocol
init(service: ServiceProtocol) {
self.service = service
Task {
await fetchPosts()
}
}
@MainActor func fetchPosts() async {
isLoading = true
await service.fetchData { [weak self] (result: Result<[PostModel], APIError>)in
DispatchQueue.main.async {
switch result {
case .success(let posts):
self?.posts = posts
case .failure(let error):
self?.errorMessage = "Failed to fetch posts: \(error.getErrorMessage())"
}
self?.isLoading = false
}
}
}
}
Here is my
class MockPostService: ServiceProtocol {
func fetchData(completion: @escaping (Result<[PostModel], APIError>) -> Void) async{
guard let jsonData = readJSONFromFile(named: "SamplePost") else {
completion(.failure(.invalidData))
return
}
do {
let decoder = JSONDecoder()
let sampleData = try decoder.decode([PostModel].self, from: jsonData)
completion(.success(sampleData))
} catch {
print("Error decoding JSON data: \(error)")
completion(.failure(.decodingError))
}
}
func readJSONFromFile(named fileName: String) -> Data? {
guard let filePath = Bundle.main.path(forResource: fileName, ofType: "json") else {
print("Error: JSON file not found.")
return nil
}
do {
let data = try Data(contentsOf: URL(fileURLWithPath: filePath))
return data
} catch {
print("Error reading JSON file: \(error)")
return nil
}
}
}
When I run this project It's working fine as expected. But the problem is in the preview. It also loads data from API, instead of Mcok Json.
For debugging purposes in PostListView, I replace the stateobject with a dummy JSON and run the project.
@StateObject private var viewModel = PostViewModel(service: MockPostService())
It's loading data from Mock JSON.
In summary, I want a preview that will load data from Mcok Json.
PostViewModelto come from the environment, use@EnvironmentObject, not@StateObjectviewModelas a dependency passed in the initializer, not created in theView