SwiftUi with Combine part 2

Kushal Dave
3 min readOct 9, 2019

--

In the First Part we created and displayed list with static dummy data now in this part we will get the data by api from viewmodel using Combine

Lets Start Phase 2 of the app

  • We already have ui created in last part(you can find it here) so in this part we will focus on using combine
  • If you are doing this hands on made sure you have latest code from last part before starting it
  • Now we will be calling this api to get a list of 10 random users
  • We will need to make changes in model class ,in the model we will only add the data we are displaying to user to keep the codebase clean
  • Also make sure to temporarily comment out ui classes as they will cause errors due to changes in model class
  • We will need to add 3 more model classes to map all the required data from api
  • Here one important thing to do in UserModel class is to add typealias to refer list of UserModels
  • You can find all the model classes here
  • You can checkout the diff here

Now lets start the fun Part

  • Create a viewmodel class UsersViewModel.swift
  • Add import combine at the top and extend the viewmodel with ObservableObject
  • Now add this to make pass changes in value of list to the subscribers everytime it is changed
public let willChange = PassthroughSubject<UsersViewModel, Never>()@Published private(set) var users:usersList = [UserModel](){didSet {willChange.send(self)}}
  • And thats it , with this little code the subscribers of this viewmodel will receive the changes in list as soon as they are made
  • Now inside the viewmodel create a function called fetchData() which will call api
  • After getting the response assign the value of list to our users , one important thing to take care here is to make sure you assign the value in main thread
  • The final code in viewmodel should look like this
import Foundationimport Combinepublic class UsersViewModel : ObservableObject {public let willChange = PassthroughSubject<UsersViewModel, Never>()@Published private(set) var users:usersList = [UserModel](){didSet {willChange.send(self)}}func fetchData() {let urlJSON = “https://randomuser.me/api/?results=10"guard let url = URL(string: urlJSON) else {return}URLSession.shared.dataTask(with: url) { (data, response, error) inguard let data = data else {return}guard error == nil else {return}do {let jsonDecoder = JSONDecoder()let responseModel = try jsonDecoder.decode(Users.self, from: data)DispatchQueue.main.async {self.users = responseModel.results!}// for user in self.users{// debugPrint(user.cell)// }} catch let error {debugPrint(error)}}.resume()}}
  • Now lets go back to contentview class and get the list from viewmodel
  • Add import compile statement
  • In contentView add this statement to subscribe to viewmodel
@ObservedObject var viewModel: UsersViewModel = UsersViewModel()

and thats it

  • Now just call the fetchUsers method of viewmodel when the navigationview appears so at end of navigationview add
.onAppear {self.viewModel.fetchData()}
  • Now all thats left is to uncomment the ui code from ContentView and ContentItemView and change data according to our new model
in List change users to viewModel.users
in KfImage change self.user.imageUrl to self.user.picture.thumbnail!

and so on for all 3 texts

Thats it for part 2

Thank you for reading! Feel free to say hi or share your thoughts on Twitter @that_kushal_guy or in the responses below!

You can checkout the full project source code on github here

If you loved it or if helped you in any way do share your love with claps (1 ,2 , 3 …. 40?), or if you face any problem running it or anything related to the topic do share it in response below , if you have an more optimised solution share that too

--

--