I lately began studying UIKit and making an attempt to make one other mission for my resume programmatically fairly than storyboard. I began out with SwiftUI but it surely’s been advised to be taught UIKit and to have a UIKit mission on my resume. I am truthfully tremendous confused. I am retrieving knowledge and placing it right into a tableview which has a Favourite’s button. I’ve the performance of that when the person faucets the favourite’s button, the empty star is crammed in however I would really like the favorites to be displayed in a brand new view controller as a result of I’ve a tab bar with the info and the opposite is a favourite’s tab. My difficulty is the addDigimonToFavorites() methodology through which I attempted passing in a argument however obtained an error of [Digimon]to anticipated argument kind ‘Digimon’. Right here is my code to this point. Please let me know when you want another code.
View Controller
class ViewController: UIViewController {
// MARK: - Properties
personal let tableView: UITableView = {
let tableView = UITableView()
tableView.backgroundColor = .systemBackground
tableView.register(DigimonCell.self, forCellReuseIdentifier: DigimonCell.identifier)
return tableView
}()
personal let searchController = UISearchController(searchResultsController: nil)
var viewModel = DigimonViewModel()
// MARK: - Lifecycle
override func viewDidLoad() {
tremendous.viewDidLoad()
viewModel.delegate = self
viewModel.getDigimonData()
configureTableView()
setTableViewDelegates()
configNavBar()
configSearchBar()
}
// MARK: - SetupUI
func configureTableView() {
//View is the principle view of the view controller
view.addSubview(tableView)
tableView.body = view.bounds
tableView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
tableView.topAnchor.constraint(equalTo: view.topAnchor),
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor), t
ableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor)
])
}
func setTableViewDelegates() {
tableView.delegate = self
tableView.dataSource = self
}
func configNavBar() {
let look = UINavigationBarAppearance()
look.configureWithOpaqueBackground()
look.backgroundColor = .mainOrange()
look.titleTextAttributes = [.foregroundColor: UIColor.white]
navigationController?.navigationBar.standardAppearance = look
navigationController?.navigationBar.scrollEdgeAppearance = navigationController?.navigationBar.standardAppearance
navigationController?.navigationBar.tintColor = .white
navigationController?.navigationBar.barStyle = .black //bar fashion provides us the white standing bar/white textual content look
navigationController?.navigationBar.isTranslucent = false
navigationItem.title = "Digimon"
}
func configSearchBar() {
self.searchController.searchResultsUpdater = self
self.searchController.obscuresBackgroundDuringPresentation = false
self.searchController.hidesNavigationBarDuringPresentation = false
self.searchController.searchBar.placeholder = "Search Digimon"
self.searchController.searchBar.searchTextField.backgroundColor = .white
self.navigationItem.searchController = searchController
self.definesPresentationContext = false
self.navigationItem.hidesSearchBarWhenScrolling = false
}
// MARK: - Selectors
@objc func markAsFavorite(sender: UIButton) {
sender.isSelected = !sender.isSelected //Toggle the button state
print("That is my favourite Digimon")
//obtained an error of [Digimon]to anticipated argument kind 'Digimon'
addDigimonToFavorites(digimon: viewModel.characters)
}
func addDigimonToFavorites(digimon: Digimon) {
//Must append to the empty favorites
var favorites = Digimon(title: digimon.title, img: digimon.img, stage: digimon.stage)
PersistenceManager.updateWith(favourite: favorites, actionType: .add) { [weak self] error in
guard let self = self else { return }
}
}
}
// MARK: - Extension for TableView delegate and knowledge supply
extension ViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection part: Int) -> Int {
let inSearchMode = viewModel.inSearchMode(searchController)
return inSearchMode ? viewModel.filteredDigimon.depend : viewModel.characters.depend
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: DigimonCell.identifier, for: indexPath) as? DigimonCell else { fatalError("tableview couldn't dequeue digimoncell in viewcontroller")}
let inSearchMode = viewModel.inSearchMode(searchController)
let digimon = inSearchMode ? viewModel.filteredDigimon[indexPath.row] : viewModel.characters[indexPath.row]
cell.set(imageUrlString: digimon.img, label: digimon.title, stage: digimon.stage)
let favoriteButton = UIButton(kind: .customized)
favoriteButton.setImage(UIImage(systemName: "star"), for: .regular)
favoriteButton.setImage(UIImage(systemName: "star.fill")?.withTintColor(.orange, renderingMode: .alwaysOriginal), for: .chosen)
favoriteButton.body = CGRect(x: 0, y: 0, width: 50, top: 50)
favoriteButton.addTarget(self, motion: #selector(markAsFavorite), for: .touchUpInside)
cell.accessoryView = favoriteButton
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 110
}
}
// MARK: - Extension for ViewController to evolve to DigimonViewModelProtocol
extension ViewController: DigimonViewModelProtocol {
// MARK: - Digimon View Mannequin Protocol Strategies
func didFinish() {
tableView.reloadData()
}
func didFail(error: Error) {
print(error)
}
}
// MARK: - Extension for Search Controller Features
extension ViewController: UISearchResultsUpdating {
func updateSearchResults(for searchController: UISearchController) {
self.viewModel.updateSearchController(searchBarText: searchController.searchBar.textual content)
tableView.reloadData()
}
}
My FavoritesListVC
class FavoritesListViewController: UIViewController {
// MARK: - Properties
var favorites: [Digimon] = []
personal let tableView: UITableView = {
let tableView = UITableView()
tableView.backgroundColor = .systemBackground
tableView.register(FavoriteCell.self, forCellReuseIdentifier: FavoriteCell.identifier)
return tableView
}()
override func viewDidLoad() {
tremendous.viewDidLoad()
title = "Favorites"
navigationController?.navigationBar.prefersLargeTitles = true
configFavoritesTableView()
}
//ViewDidLoad solely will get known as as soon as. But when the person sees they haven't any favorites after which provides favorites and goes again to favorites listing will get known as then. All the time refreshing favorites
override func viewWillAppear(_ animated: Bool) {
tremendous.viewWillAppear(animated)
getFavorites()
}
func configFavoritesTableView() {
view.addSubview(tableView)
tableView.body = view.bounds
tableView.delegate = self
tableView.dataSource = self
tableView.removeExcessCells()
}
func getFavorites() {
PersistenceManager.retrieveFavorites { end in
change consequence {
case .success(let favorites):
self.favorites = favorites
DispatchQueue.most important.async {
self.tableView.reloadData()
self.view.bringSubviewToFront(self.tableView)
}
case .failure(let error):
fatalError("error")
}
}
}
}
// MARK: - Extension for the TableView
extension FavoritesListViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection part: Int) -> Int {
return favorites.depend
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: FavoriteCell.identifier, for: indexPath) as?
FavoriteCell else {
fatalError("Couldn't dequeue favoritecell")
}
//Get favorites
let favourite = favorites[indexPath.row]//IndexPath.row is grabbing the index from the array for that row
cell.setFave(favourite: favourite)
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 110
}
}
My Persistence Supervisor
enum PersistenceActionType {
case add
case take away
}
enum Keys {
static let favorites = "favorites"
}
enum PersistenceManager {
static personal let defaults = UserDefaults.customary
// MARK: - Retreive Favorites
static func retrieveFavorites(accomplished: @escaping (Consequence<[Digimon], Error>) -> Void) {
//When saving to defaults. Want to offer it a key title
guard let favoritesData = defaults.object(forKey: Keys.favorites) as? Information else { return
//First time use when there are not any favorites added. We do not need an error to show. Simply an empty array
accomplished(.success([]))
return
}
do {
let decoder = JSONDecoder()
let favorites = strive decoder.decode([Digimon].self, from: favoritesData)
accomplished(.success(favorites))
} catch {
fatalError("Unable to favourite")
}
}
// MARK: - Save Favorites
static func saveFavorites(favorites: [Digimon]) -> Error? {
do {
let encoder = JSONEncoder()
let encodedFavorites = strive encoder.encode(favorites)
defaults.set(encodedFavorites, forKey: Keys.favorites)
return nil //Returning nil as a result of there is no such thing as a Error
}catch {
fatalError("Unable to favourite")
}
}
static func updateWith(favourite: Digimon, actionType: PersistenceActionType, accomplished: @escaping (Error?) -> Void) {
//Want to succeed in within the person defaults and retrieve the array
retrieveFavorites { end in
change consequence {
case .success(var favorites):
change actionType {
case .add:
guard !favorites.accommodates(favourite) else {
accomplished("Already in favorites" as? Error)
return
}
favorites.append(favourite)
case .take away:
favorites.removeAll { $0.title == favourite.title && $0.img == favourite.img && $0.stage == favourite.stage} //Shorthand syntax $0 is every merchandise because it iterates by way of
}
case .failure(let error):
accomplished(error)
}
}
}
}