当用户点击收藏夹按钮时,我如何将数据传递到具有表视图的新视图控制器?

问题描述 投票:0回答:1

我最近开始学习 UIKit 并尝试以编程方式而不是故事板的方式为我的简历制作另一个项目。我从 SwiftUI 开始,但有人建议我学习 UIKit 并在我的简历上有一个 UIKit 项目。老实说,我非常困惑。我正在检索数据并将其放入具有收藏夹按钮的表格视图中。我有这样的功能,当用户点击收藏夹的按钮时,空星被填充,但我希望收藏夹显示在新的视图控制器中,因为我有一个包含数据的标签栏,另一个是收藏夹的标签.我的问题是 addDigimonToFavorites() 方法,我尝试在该方法中传递参数但收到 [Digimon] 到预期参数类型“Digimon”的错误。到目前为止,这是我的代码。如果您需要任何其他代码,请告诉我。

视图控制器

class ViewController: UIViewController {

    
    // MARK: - Properties

    private let tableView: UITableView = {
        let tableView = UITableView()
        tableView.backgroundColor = .systemBackground
        tableView.register(DigimonCell.self, forCellReuseIdentifier: DigimonCell.identifier)
        return tableView
    }()
    
    private let searchController = UISearchController(searchResultsController: nil)
    

    var viewModel = DigimonViewModel()

    
    // MARK: - Lifecycle
    override func viewDidLoad() {
        super.viewDidLoad()

        viewModel.delegate = self
        viewModel.getDigimonData()
        configureTableView()
        setTableViewDelegates()
        configNavBar()
        configSearchBar()


    }
    
    
    
    // MARK: - SetupUI
    
    
    func configureTableView() {
        //View is the main view of the view controller
        view.addSubview(tableView)
        tableView.frame = 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 appearance = UINavigationBarAppearance()
        appearance.configureWithOpaqueBackground()
        appearance.backgroundColor = .mainOrange()
        appearance.titleTextAttributes = [.foregroundColor: UIColor.white]
        
        navigationController?.navigationBar.standardAppearance = appearance
        navigationController?.navigationBar.scrollEdgeAppearance = navigationController?.navigationBar.standardAppearance
        navigationController?.navigationBar.tintColor = .white
        navigationController?.navigationBar.barStyle = .black //bar style gives us the white status bar/white text 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("This is my favorite Digimon")
        
        //received an error of [Digimon]to expected argument type 'Digimon'
        addDigimonToFavorites(digimon: viewModel.characters)

    }
    
    func addDigimonToFavorites(digimon: Digimon) {
        //Need to append to the empty favorites
        var favorites = Digimon(name: digimon.name, img: digimon.img, level: digimon.level)

        PersistenceManager.updateWith(favorite: favorites, actionType: .add) { [weak self] error in
            guard let self = self else { return }

        }
    }
    
}






// MARK: - Extension for TableView delegate and data source

extension ViewController: UITableViewDelegate, UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

        let inSearchMode = viewModel.inSearchMode(searchController)

        return inSearchMode ? viewModel.filteredDigimon.count : viewModel.characters.count
        
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: DigimonCell.identifier, for: indexPath) as? DigimonCell else { fatalError("tableview could not 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.name, level: digimon.level)
        
        let favoriteButton = UIButton(type: .custom)
        favoriteButton.setImage(UIImage(systemName: "star"), for: .normal)
        favoriteButton.setImage(UIImage(systemName: "star.fill")?.withTintColor(.orange, renderingMode: .alwaysOriginal), for: .selected)
        favoriteButton.frame = CGRect(x: 0, y: 0, width: 50, height: 50)
        favoriteButton.addTarget(self, action: #selector(markAsFavorite), for: .touchUpInside)
        cell.accessoryView = favoriteButton
        

        return cell
    }
    
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 110
    }
}




// MARK: - Extension for ViewController to conform to DigimonViewModelProtocol
extension ViewController: DigimonViewModelProtocol {
    // MARK: - Digimon View Model Protocol Methods
    func didFinish() {
        tableView.reloadData()
    }
    
    func didFail(error: Error) {
        print(error)
    }
}



// MARK: - Extension for Search Controller Functions

extension ViewController: UISearchResultsUpdating {
    func updateSearchResults(for searchController: UISearchController) {
        self.viewModel.updateSearchController(searchBarText: searchController.searchBar.text)

        tableView.reloadData()
    }
}

我的最爱列表VC

class FavoritesListViewController: UIViewController {
    

    
    // MARK: - Properties
    var favorites: [Digimon] = []
    
    
    private let tableView: UITableView = {
        let tableView = UITableView()
        tableView.backgroundColor = .systemBackground
        tableView.register(FavoriteCell.self, forCellReuseIdentifier: FavoriteCell.identifier)
        
        return tableView
    }()

    override func viewDidLoad() {
        super.viewDidLoad()


        title = "Favorites"

        navigationController?.navigationBar.prefersLargeTitles = true
        configFavoritesTableView()
        
    }
    
    
    //ViewDidLoad only gets called once. But if the user sees they have no favorites and then adds favorites and goes back to favorites list will get called then. Always refreshing favorites
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        getFavorites()
    }
    
    
    
    func configFavoritesTableView() {
        view.addSubview(tableView)
        tableView.frame = view.bounds 
        tableView.delegate = self
        tableView.dataSource = self
        tableView.removeExcessCells()
        
    }
    
    
    func getFavorites() {
        PersistenceManager.retrieveFavorites { result in
            switch result {
            case .success(let favorites):
                self.favorites = favorites
                DispatchQueue.main.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 section: Int) -> Int {
        return favorites.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: FavoriteCell.identifier, for: indexPath) as?
                FavoriteCell else {
            fatalError("Could not dequeue favoritecell")
        }
        
        //Get favorites
        let favorite = favorites[indexPath.row]//IndexPath.row is grabbing the index from the array for that row
        cell.setFave(favorite: favorite)
        return cell
    }
    
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 110
    }
}

我的持久性管理器

enum PersistenceActionType {
    case add
    case remove
}


enum Keys {
    static let favorites = "favorites"
}

enum PersistenceManager {
    static private let defaults = UserDefaults.standard

    // MARK: - Retreive Favorites

    static func retrieveFavorites(completed: @escaping (Result<[Digimon], Error>) -> Void) {
        //When saving to defaults. Need to give it a key name
        guard let favoritesData = defaults.object(forKey: Keys.favorites) as? Data else { return
            //First time use when there are no favorites added. We don't want an error to display. Just an empty array
            completed(.success([]))
            return
        }
        
        do {
            let decoder = JSONDecoder()
            let favorites = try decoder.decode([Digimon].self, from: favoritesData)
            completed(.success(favorites))
        
        } catch {
            fatalError("Unable to favorite")
        }
    }
    
    // MARK: - Save Favorites
    
  
    static func saveFavorites(favorites: [Digimon]) -> Error? {
        do {
            let encoder = JSONEncoder()
            let encodedFavorites = try encoder.encode(favorites)
            
            defaults.set(encodedFavorites, forKey: Keys.favorites)
            return nil //Returning nil because there is no Error
            
        }catch {
            fatalError("Unable to favorite")
        }
    }
    
   
    static func updateWith(favorite: Digimon, actionType: PersistenceActionType, completed: @escaping (Error?) -> Void) {
        //Need to reach in the user defaults and retrieve the array
        retrieveFavorites { result in
            switch result {
            case .success(var favorites):

        
                switch actionType {
                case .add:
                    guard !favorites.contains(favorite) else {
                        completed("Already in favorites" as? Error)
                        return
                    }
                    favorites.append(favorite)
                case .remove:
                    favorites.removeAll { $0.name == favorite.name && $0.img == favorite.img && $0.level == favorite.level} //Shorthand syntax $0 is each item as it iterates through
                }
                
            case .failure(let error):
               completed(error)
            }
        }
    }
}
ios swift uitableview uikit
1个回答
0
投票

错误消息“expected argument type 'Digimon', got '[Digimon]'”表示您正在尝试将 Digimon 对象数组传递给需要单个 Digimon 对象的函数。

在您的

markAsFavorite
函数中,当用户点击任何 Digimon 的收藏按钮时,您尝试将包含所有 Digimon 对象的
viewModel.characters
数组添加到收藏夹列表。相反,您需要将选定的 Digimon 对象添加到收藏夹列表中。

您可以通过访问包含收藏夹按钮的单元格行并使用它索引到适当的数组,

viewModel.characters
viewModel.filteredDigimon
,这取决于搜索栏是否处于活动状态,从而获取所选的 Digimon 对象。

@objc func markAsFavorite(sender: UIButton) {
    sender.isSelected = !sender.isSelected //Toggle the button state
    
    // Find the selected cell and get its corresponding Digimon
    guard let cell = sender.superview?.superview as? DigimonCell,
          let indexPath = tableView.indexPath(for: cell) else {
        return
    }
    let inSearchMode = viewModel.inSearchMode(searchController)
    let digimon = inSearchMode ? viewModel.filteredDigimon[indexPath.row] : viewModel.characters[indexPath.row]
    
    addDigimonToFavorites(digimon: digimon)
}

addDigimonToFavorites
函数中,您还需要将参数类型更改为数码宝贝对象数组,因为您将向收藏夹列表添加多个数码宝贝对象。这是该功能的更新版本:

func addDigimonToFavorites(digimon: [Digimon]) {
    // Append to the existing favorites array
    var favorites = PersistenceManager.retrieveFavorites()
    favorites.append(contentsOf: digimon)
    
    PersistenceManager.updateWith(favorites: favorites, actionType: .add) { [weak self] error in
        guard let self = self else { return }
        // Handle error or update UI as needed
    }
}

请注意,此函数检索现有的收藏夹列表,将选定的 Digimon 对象附加到其中,然后使用

PersistenceManager.updateWith
保存更新的列表。您可能还想更新您的
PersistenceManager
以处理一组
Digimon
对象而不是单个对象。

© www.soinside.com 2019 - 2024. All rights reserved.