0

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.

5
  • If you want your PostViewModel to come from the environment, use @EnvironmentObject, not @StateObject Commented Aug 13, 2023 at 10:32
  • If I change my viewModel into EnvironmentObject then the preview is working. But I need viewModel as StateObject and in that case preview is loading data from live API. Commented Aug 13, 2023 at 12:39
  • Then you must take viewModel as a dependency passed in the initializer, not created in the View Commented Aug 13, 2023 at 13:14
  • 1
    You don’t need the async keyword, you aren’t using async/await. I suggest watching “Meet async/await” Commented Aug 13, 2023 at 13:51
  • I presume that the real function fetches the data from the network and is therefore async. The mock needs to replicate the function signature ven though it is not async itself. Commented Aug 13, 2023 at 20:37

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.