简体   繁体   中英

Swift- UsersDefault Array not updating/reloading TableView when popViewController back

尝试显示 CS006 的示例:... when didSelectRowAt

I have a yearOne Class, fallQuarterCell Class as one view controller file and SearchPage Class as another view controller file. I'm trying to append the data array when the user pressed on a cell to the data array which I set in fallQuarterCell and assigned with UsersDefaults .

It does append to the data array but it only shows up when I'm moving from the view controller before yearOne / fallQuarterCell to yearOne / fallQuarterCell but when I go back using popViewController from SearchPage view controller, it does not show up and update the tableView . I tried to use viewWillAppear and all sorts but I'm still having trouble.

import UIKit

class yearOne: UICollectionViewController{

    let customCellIdentifier = "cellID"
    let customCellIdentifier2 = "cellID2"
    let customCellIdentifier3 = "cellID3"
    let customCellIdentifier4 = "cellID4"

    let quarters = [
        customLabel (title: "Fall Quarter"),
        customLabel (title: "Winter Quarter"),
        customLabel (title: "Spring Quarter"),
        customLabel (title: "Summer Quarter")
    ]

    let vc = fallQuarterCell()
    let vc2 = winterQuarterCell()
    let vc3 = springQuarterCell()
    let vc4 = summerQuarterCell()

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        collectionView.reloadData()
        vc.load()
        vc2.load()
        vc3.load()
        vc4.load()
        collectionView.reloadData()
    }


    override func viewDidLoad() {
        super.viewDidLoad()


        collectionView.dataSource = self
        collectionView.delegate = self

        self.collectionView!.register(fallQuarterCell.self, forCellWithReuseIdentifier: customCellIdentifier)//
        self.collectionView!.register(winterQuarterCell.self, forCellWithReuseIdentifier: customCellIdentifier2)
        self.collectionView!.register(springQuarterCell.self, forCellWithReuseIdentifier: customCellIdentifier3)
        self.collectionView!.register(summerQuarterCell.self, forCellWithReuseIdentifier: customCellIdentifier4)

        navigationItem.title = "Year One"
        navigationController?.navigationBar.prefersLargeTitles = true
        collectionView?.backgroundColor = .lightGray
        //navigationItem.prompt = "Click the + button to add courses, Swipe left on a course to delete."

    }

    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return quarters.count
    }

    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

        if (indexPath.row == 0){
            let cell1 = collectionView.dequeueReusableCell(withReuseIdentifier: customCellIdentifier, for: indexPath) as! fallQuarterCell
            cell1.layer.borderColor = UIColor.orange.cgColor
            cell1.layer.borderWidth = 2
            cell1.layer.cornerRadius = 5
            cell1.quarters = self.quarters[0]
            return cell1
        }
        else if (indexPath.row == 1){
            let cell2 = collectionView.dequeueReusableCell(withReuseIdentifier: customCellIdentifier2, for: indexPath) as! winterQuarterCell
            cell2.layer.borderColor = UIColor.blue.cgColor
            cell2.layer.borderWidth = 2
            cell2.layer.cornerRadius = 5
            cell2.quarters = self.quarters[1]
            return cell2
        }
        else if (indexPath.row == 2){
            let cell3 = collectionView.dequeueReusableCell(withReuseIdentifier: customCellIdentifier3, for: indexPath) as! springQuarterCell
            cell3.layer.borderColor = UIColor.green.cgColor
            cell3.layer.borderWidth = 2
            cell3.layer.cornerRadius = 5
            cell3.quarters = self.quarters[2]
            return cell3
        }
        else if (indexPath.row == 3){
            let cell4 = collectionView.dequeueReusableCell(withReuseIdentifier: customCellIdentifier4, for: indexPath) as! summerQuarterCell
            cell4.layer.borderColor = UIColor.red.cgColor
            cell4.layer.cornerRadius = 5
            cell4.quarters = self.quarters[3]
            return cell4
        }
        else{
            return UICollectionViewCell()
        }
    }

    @objc func buttonAction(sender: UIButton!) {
        switch sender.tag {
        case 0:
            let destination = SearchPage()
            destination.tag = sender.tag
            navigationController?.pushViewController(destination, animated: true)
        case 1:
            let destination = SearchPage()
            destination.tag = sender.tag
            navigationController?.pushViewController(destination, animated: true)
        case 2:
            let destination = SearchPage()
            destination.tag = sender.tag
            navigationController?.pushViewController(destination, animated: true)
        case 3:
            let destination = SearchPage()
            destination.tag = sender.tag
            navigationController?.pushViewController(destination, animated: true)
        default:
            let destination = SearchPage()
            destination.tag = sender.tag
            navigationController?.pushViewController(destination, animated: true)
        }

    }
}

extension yearOne : UICollectionViewDelegateFlowLayout{

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        let width = (view.frame.width - 30)
        return CGSize(width: width, height: 200)
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return 8
    }
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
        return 1
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
        UIEdgeInsets(top: 30, left: 10, bottom: 30, right: 10)
    }

}


class fallQuarterCell: UICollectionViewCell, UITableViewDelegate, UITableViewDataSource {

    var data = UserDefaults.standard.object(forKey: "SavedArray") as? [String] ?? [String](){
        didSet {
            tableView.reloadData()
        }
    }

    func load(){
        if let loadeddata: [String] = UserDefaults.standard.object(forKey: "SavedArray") as? [String] {
            data = loadeddata
            tableView.reloadData()
        }
    }

    let cellId = "coursesName"

    let tableView:UITableView = {
        let tableView = UITableView()
        tableView.translatesAutoresizingMaskIntoConstraints = false
        tableView.backgroundColor = UIColor.white
        return tableView
    }()

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return data.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath)
        cell.textLabel?.text = data[indexPath.row]
        return cell
    }

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

    func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
        return true
    }

    func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
        if (editingStyle == .delete) {
            // handle delete (by removing the data from your array and updating the tableview)
            if (indexPath.row == 0){
                data.remove(at: 0)
                UserDefaults.standard.set(data, forKey: "SavedArray")
                self.tableView.reloadData()
            }
            else if (indexPath.row == 1){
                data.remove(at: 1)
                UserDefaults.standard.set(data, forKey: "SavedArray")
                self.tableView.reloadData()
            }
            else if (indexPath.row == 2){
                data.remove(at: 2)
                UserDefaults.standard.set(data, forKey: "SavedArray")
                self.tableView.reloadData()
            }
            else if (indexPath.row == 3){
                data.remove(at: 3)
                UserDefaults.standard.set(data, forKey: "SavedArray")
                self.tableView.reloadData()
            }
            else if (indexPath.row == 4){
                data.remove(at: 4)
                UserDefaults.standard.set(data, forKey: "SavedArray")
                self.tableView.reloadData()
            }
        }
    }

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        //add class information???
    }

    var quarters: customLabel? {
        didSet {
            guard let quarters = quarters else {return}
            quarterLabel.text = quarters.title
        }
    }

    override init(frame: CGRect){
        super.init(frame: frame)        
        addSubview(tableView)
        setupView()
    }

    func setupView(){

        tableView.delegate = self
        tableView.dataSource = self
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellId)

        self.backgroundColor = UIColor.white
        contentView.addSubview(quarterLabel)
        contentView.addSubview(addButton)

        quarterLabel.translatesAutoresizingMaskIntoConstraints = false
        quarterLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 10).isActive = true
        quarterLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 10).isActive = true

        addButton.translatesAutoresizingMaskIntoConstraints = false
        addButton.topAnchor.constraint(equalTo: quarterLabel.topAnchor, constant: -5).isActive = true
        addButton.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -10).isActive = true
        addButton.heightAnchor.constraint(equalToConstant: 25).isActive = true
        addButton.widthAnchor.constraint(equalToConstant: 25).isActive = true


        tableView.translatesAutoresizingMaskIntoConstraints = false
        tableView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 35).isActive = true
        tableView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 5).isActive = true
        tableView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -10).isActive = true
        tableView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -5).isActive = true

        // each collection view cell (row) = should display xxQuarter Array
        // call indexpath for the collection view and set the tableview to the collection view
        // quarterCell.indexPath

        //if(buttonAction) is cicked from searchPage(), then add the UI label
        //remove course function, add course function
    }

    let quarterLabel : UILabel = {
        let label = UILabel()//frame: CGRect(x: 15, y: -75, width: 300, height: 50))
        label.translatesAutoresizingMaskIntoConstraints = false
        label.textColor = UIColor.black
        label.font = UIFont.boldSystemFont(ofSize: 16)
        //label.textAlignment = .center
        return label
    }()

    let addButton : UIButton = {
        let button = UIButton()//frame: CGRect(x: 345, y: 10, width: 30, height: 30))
        button.setImage(UIImage(named: "addicon"), for: .normal)
        button.imageEdgeInsets = UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5)
        button.tag = 0
        button.addTarget(self, action: #selector(yearOne.buttonAction), for: .touchUpInside)
        return button
    }()
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

}

class winterQuarterCell: UICollectionViewCell, UITableViewDelegate, UITableViewDataSource {

    var data = UserDefaults.standard.object(forKey: "SavedArray2") as? [String] ?? [String](){
        didSet {
            tableView.reloadData()
        }
    }

    func load(){
        if let loadeddata: [String] = UserDefaults.standard.object(forKey: "SavedArray2") as? [String] {
            data = loadeddata
            tableView.reloadData()
        }
    }

    let cellId = "coursesName"

    let tableView:UITableView = {
        let tableView = UITableView()
        tableView.translatesAutoresizingMaskIntoConstraints = false
        tableView.backgroundColor = UIColor.white
        return tableView
    }()

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return data.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
       let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath)
       cell.textLabel?.text = data[indexPath.row]
       return cell
    }

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

    func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
        return true
    }

    func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
        if (editingStyle == .delete) {
            // handle delete (by removing the data from your array and updating the tableview)
            if (indexPath.row == 0){
                data.remove(at: 0)
                UserDefaults.standard.set(data, forKey: "SavedArray2")
                self.tableView.reloadData()
            }
            else if (indexPath.row == 1){
                data.remove(at: 1)
                UserDefaults.standard.set(data, forKey: "SavedArray2")
                self.tableView.reloadData()
            }
            else if (indexPath.row == 2){
                data.remove(at: 2)
                UserDefaults.standard.set(data, forKey: "SavedArray2")
                self.tableView.reloadData()
            }
            else if (indexPath.row == 3){
                data.remove(at: 3)
                UserDefaults.standard.set(data, forKey: "SavedArray2")
                self.tableView.reloadData()
            }
            else if (indexPath.row == 4){
                data.remove(at: 4)
                UserDefaults.standard.set(data, forKey: "SavedArray2")
                self.tableView.reloadData()
            }
        }
    }

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        //add class information???
    }

    var quarters: customLabel? {
        didSet {
            guard let quarters = quarters else {return}
            quarterLabel.text = quarters.title
        }
    }

    override init(frame: CGRect){
        super.init(frame: frame)
        addSubview(tableView)
        setupView()
    }

    func setupView(){

        tableView.delegate = self
        tableView.dataSource = self
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellId)

        self.backgroundColor = UIColor.white
        contentView.addSubview(quarterLabel)
        contentView.addSubview(addButton)

        quarterLabel.translatesAutoresizingMaskIntoConstraints = false
        quarterLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 10).isActive = true
        quarterLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 10).isActive = true

        addButton.translatesAutoresizingMaskIntoConstraints = false
        addButton.topAnchor.constraint(equalTo: quarterLabel.topAnchor, constant: -5).isActive = true
        addButton.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -10).isActive = true
        addButton.heightAnchor.constraint(equalToConstant: 25).isActive = true
        addButton.widthAnchor.constraint(equalToConstant: 25).isActive = true


        tableView.translatesAutoresizingMaskIntoConstraints = false
        tableView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 35).isActive = true
        tableView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 5).isActive = true
        tableView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -10).isActive = true
        tableView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -5).isActive = true

        // each collection view cell (row) = should display xxQuarter Array
        // call indexpath for the collection view and set the tableview to the collection view
        // quarterCell.indexPath

        //if(buttonAction) is cicked from searchPage(), then add the UI label
        //remove course function, add course function

    }

    let quarterLabel : UILabel = {
        let label = UILabel()//frame: CGRect(x: 15, y: -75, width: 300, height: 50))
        label.translatesAutoresizingMaskIntoConstraints = false
        label.textColor = UIColor.black
        label.font = UIFont.boldSystemFont(ofSize: 16)
        //label.textAlignment = .center
        return label
    }()

    let addButton : UIButton = {
        let button = UIButton()//frame: CGRect(x: 345, y: 10, width: 30, height: 30))
        button.setImage(UIImage(named: "addicon"), for: .normal)
        button.imageEdgeInsets = UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5)
        button.tag = 1
        button.addTarget(self, action: #selector(yearOne.buttonAction), for: .touchUpInside)
        return button
    }()


    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

}

....

}

Section of the SearchPage Class:

   let vc = fallQuarterCell()
    let vc2 = winterQuarterCell()
    let vc3 = springQuarterCell()
    let vc4 = summerQuarterCell()

    var tag: Int?

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){

        tableView.deselectRow(at: indexPath, animated: true)

        if (tag == 0){
            if (resultSearchController.isActive){
                vc.data.append(filteredCourses[indexPath.row])
                UserDefaults.standard.set(vc.data, forKey: "SavedArray")
                navigationController?.popViewController(animated: true)

            }
            else{
                vc.data.append(allCourses[indexPath.row] as! String)
                UserDefaults.standard.set(vc.data, forKey: "SavedArray")
                navigationController?.popViewController(animated: true)
            }
        }

        else if (tag == 1){
            if (resultSearchController.isActive){
                vc2.data.append(filteredCourses[indexPath.row])
                UserDefaults.standard.set(vc2.data, forKey: "SavedArray2")
                navigationController?.popViewController(animated: true)
            }
            else{
                vc2.data.append(allCourses[indexPath.row] as! String)
                UserDefaults.standard.set(vc2.data, forKey: "SavedArray2")
                navigationController?.popViewController(animated: true)
            }
        }
       .....
    }

It seems like you need to call your collectionView's reloadData() method here:

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        UserDefaults.standard.synchronize()
        vc.load()
        collectionView.reloadData()
    }

The reason is that when you go to the Select Courses page -> New ViewController is pushed on top of your yearOne and when you go back -> New ViewController is just removed from the view hierarchy and yearOne becomes a top one.

The collection view is not reloaded automatically since it was loaded already and not reloadData() is called.

But when you go back -> yearOne VC is destroyed. Then you open and create it again from the scratch and collection view loads new data from the defaults.

PS There are things that are not clear from the code provided:

  1. What you return as cell for your collection view in yearOne view controller.
  2. Why you are creating cells outside of UICollectionViewDataSource methods?
  3. Why you are creating NEW instatnces of yearOne and fallQuarterCell from SearchPage class?
  4. What you return as cell for your table view in fallQuarterCell class?
  5. No need to call viewWillAppear explicitly since it will be called when the yearOne is about to be shown on the screen.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM