I am working to make an app that shows some companies in a collection view. I am fetching these companies from an API. I want to use MVVM and Protocol Oriented build. But when I run my app, the error occurs saying:
Property 'self.viewModel' not initialized at super.init call
How can I fix this error?
Here is my API Manager:
enum APIError : Error {
case URLError
case ConnectionError
}
class APIManager: APIProtocol {
func fetchData(completion : @escaping(Result<[Company],APIError>)->Void) {
guard let url = URL(string: "https://fakerapi.it/api/v1/companies? _quantity=20") else {return}
URLSession.shared.dataTask(with: url) { (data, _, error) in
guard let data = data else {
completion(.failure(.URLError))
return
}
DispatchQueue.main.async {
do {
let jsonData = try? JSONDecoder().decode(InitialData.self, from: data)
guard let jsonData = jsonData else {return}
print(jsonData.data)
completion(.success(jsonData.data))
}
}
}.resume()
}
}
And here is my API protocol:
protocol APIProtocol {
func fetchData(completion : @escaping(Result<[Company],APIError>)->Void)
}
I want to build a complex API manager. I don't think the problem is about APIManager.
Here is my ViewModel file:
class CompanyViewModel {
private let apiProtocol : APIProtocol
weak var output : CompanyViewModelOutput?
init(apiProtocol: APIProtocol) {
self.apiProtocol = apiProtocol
}
func fetchData() {
apiProtocol.fetchData { [weak self] result in
switch result {
case .success(let companyList):
self?.output?.fetchList(companyList: companyList)
print(companyList)
case .failure(let error):
print(error.localizedDescription)
}
}
}
}
And the output protocol:
protocol CompanyViewModelOutput : AnyObject {
func fetchList(companyList : [Company])
}
I want to fetch company list in viewmodel and make a cleaner view controller file.
Here is my view controller:
class ViewController: UIViewController, CompanyViewModelOutput {
func fetchList(companyList: [Company]) {
self.compList = companyList
}
var compList = [Company]() {
didSet {
self.collectionView.reloadData()
}
}
@IBOutlet weak var collectionView: UICollectionView!
private let viewModel : CompanyViewModel
init(viewModel: CompanyViewModel) {
self.viewModel = viewModel
super.init(nibName: nil, bundle: nil)
self.viewModel.output = self
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func viewDidLoad() {
super.viewDidLoad()
collectionView.delegate = self
collectionView.dataSource = self
// Do any additional setup after loading the view.
viewModel.fetchData()
}
}
extension ViewController : UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return compList.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! CompanyCell
cell.nameLabel.text = compList[indexPath.row].name
cell.countryLabel.text = compList[indexPath.row].country
return cell
}
}
I initialized all properties in sceneDelegate:
guard let scene = (scene as? UIWindowScene) else { return }
window = UIWindow(windowScene: scene)
let apiProtocol : APIProtocol = APIManager()
let viewModel = CompanyViewModel(apiProtocol: apiProtocol)
window?.rootViewController = ViewController(viewModel: viewModel)
window?.makeKeyAndVisible()
I don't understand why this error occurs. I am new at Swift and I am trying to learn protocol oriented programming. Can anyone help me with this?