Swift 3 Xcode 8 UserDefaults Tableview到UIViewController

时间:2017-03-12 21:34:46

标签: ios swift xcode uitableview checkbox

我最近得到了帮助,让我的UIViewController中的复选框按钮状态保持不变(使用相应的png更改为bool值为true或false并使用UserDefaults保存,检查或取消选中)。

但是,由于项目的设置方式,复选框的状态会持续存在于UITableViewController中的每个项目中,这些项目将分隔到其自己的UIViewController,并带有复选框。因此,当我单击一个复选框时,它会检查UITableViewController中每个UIViewController中的相同复选框。

我不知道如何解决这个问题,因为CurrentGoalViewController(带有复选框的那个)被动态tableview所扰乱。任何帮助将不胜感激,谢谢。以下是相应视图的代码。

CurrentGoalsTableViewController(列出了所有目标的tableview)

import UIKit

class CurrentGoalsTableViewController: UITableViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        self.title = "Current Goals"

        //Setup a notification to let us know when the app is about to close, and that we should store the user items to persistence.
        //This will call the applicationDidEnterBackground() function in
        //this class
        NotificationCenter.default.addObserver(self, selector: #selector(UIApplicationDelegate.applicationDidEnterBackground(_:)), name: NSNotification.Name.UIApplicationDidEnterBackground, object: nil)

        do
        {
            //Try to load goalitems from persistence
            goals = try[Goal].readFromPersistence() //read values saved for goal text 
        }
        catch let error as NSError //catch errors
        {
            if error.domain == NSCocoaErrorDomain && error.code == NSFileReadNoSuchFileError
            {
                NSLog("No persistence file found, not necessarily an error")
            }
            else
            {
                let alert = UIAlertController(
                    title: "Error",
                    message: "Could not load the goal items",
                    preferredStyle: .alert)
                alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
                self.present(alert, animated: true, completion: nil)

                NSLog("Error loading from persistence: \(error)")
            }
        }

        // Uncomment the following line to preserve selection between presentations
        // self.clearsSelectionOnViewWillAppear = false

        // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
        // self.navigationItem.rightBarButtonItem = self.editButtonItem()
    }

     private var goalitems = [Goal]()

    @objc
    public func applicationDidEnterBackground(_ notification: NSNotification)
    {
        do
        {
            try goals.writeToPersistence() //save goalitems to persistence
        }
        catch let error
        {
            NSLog("Error writing to persistence: \(error)")
        }
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        tableView.reloadData() //reload data every time we come to this view
        self.tabBarController?.navigationItem.title = "Current Goals"
    }

    // MARK: - Table view data source

    override func numberOfSections(in tableView: UITableView) -> Int {
        // #warning Incomplete implementation, return the number of sections
        return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // #warning Incomplete implementation, return the number of rows
        return goals.count //count is amount of goalitems
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let currentGoal = goals[indexPath.row]
        let cell = tableView.dequeueReusableCell(withIdentifier: "basic", for: indexPath)
        cell.textLabel?.text = currentGoal.name 
        // Configure the cell...

        return cell //for each goalitem, return cell with goal name
    }

    override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
        if indexPath.row < goals.count {
            goals.remove(at: indexPath.row)
            tableView.deleteRows(at: [indexPath], with: .top)
        }
    }

    // MARK: - Navigation

    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        // Get the new view controller using segue.destinationViewController.
        // Pass the selected object to the new view controller.

        if let currentGoalViewController = segue.destination as? CurrentGoalViewController {
            if let indexPath = self.tableView.indexPathForSelectedRow {
                currentGoalViewController.currentGoal = goals[indexPath.row]
            } //segue from the clicked cell goalitem in CurrentGoalsTableViewController to the detail view of that item in CurrentGoalViewController
        }
    }
}

CurrentGoalViewController(带有复选框的视图)

import UIKit

let defaults = UserDefaults.standard

class CurrentGoalViewController: UIViewController {

var currentGoal: Goal?

var uncheckedBox = UIImage(named: "checkbox") //unchecked checkbox png
var checkedBox = UIImage(named: "checkedbox") //checked checkbox png

var isboxclicked: Bool! 
var isbox2clicked: Bool!
var isbox3clicked: Bool!

@IBOutlet weak var progressView: UIProgressView!

var checkedBoxTotal = 0

@IBOutlet weak var goalCompletedLabel: UILabel! 
@IBOutlet weak var deadlineLabel: UILabel!

@IBOutlet weak var uncheckBox: UIButton! //one button for each goal
@IBOutlet weak var uncheckBox2: UIButton!
@IBOutlet weak var uncheckBox3: UIButton!

private var checkMarkItems = [CheckmarkItem]()

@IBAction func clickBox(_ sender: UIButton) {
    if isboxclicked == true {
        isboxclicked = false  //if box is checked, when you click on it it unchecks
        defaults.set(isboxclicked, forKey:"checkboxstatus") //set bool for UserDefaults
        uncheckBox.setImage(uncheckedBox, for: UIControlState.normal) //set image of checkbox to unchecked image
        checkedBoxTotal = checkedBoxTotal - 1 //Amount of checkboxes checked is one less
        defaults.set(checkedBoxTotal, forKey: "checkboxtotal") //save amount of checkbox total

        showCompleteLabel()
        progressView.progress = Float(checkedBoxTotal)/Float(3) 

        defaults.set(progressView.progress, forKey:"progressviewprogress")
    } else {
        isboxclicked = true //if not checked, check it
        defaults.set(isboxclicked, forKey: "checkboxstatus")
        uncheckBox.setImage(checkedBox, for:UIControlState.normal)
        checkedBoxTotal = checkedBoxTotal + 1
        defaults.set(checkedBoxTotal, forKey: "checkboxtotal")
        progressView.progress = Float(checkedBoxTotal)/Float(3)
        showCompleteLabel()
        defaults.set(progressView.progress, forKey:"progressviewprogress")
        }
}

@IBAction func clickBox2(_ sender: UIButton) { //second checkbox, same logic as first
    if isbox2clicked == true {
        isbox2clicked = false

        sender.setImage(#imageLiteral(resourceName: "checkbox"), for: UIControlState.normal)
        defaults.set(isbox2clicked, forKey: "checkboxstatus2")
        checkedBoxTotal = checkedBoxTotal - 1
        defaults.set(checkedBoxTotal, forKey: "checkboxtotal")

        progressView.progress = Float(checkedBoxTotal)/Float(3)
        showCompleteLabel()

        defaults.set(progressView.progress, forKey:"progressviewprogress")
    } else {
        isbox2clicked = true
        defaults.set(isbox2clicked, forKey: "checkboxstatus2")

        sender.setImage(#imageLiteral(resourceName: "checkedbox"), for:UIControlState.normal)
        checkedBoxTotal = checkedBoxTotal + 1

        defaults.set(checkedBoxTotal, forKey: "checkboxtotal")

        progressView.progress = Float(checkedBoxTotal)/Float(3)
        showCompleteLabel()

        defaults.set(progressView.progress, forKey:"progressviewprogress")
    }
}

@IBAction func clickBox3(_ sender: UIButton) { //third checkbox, same logic
    if isbox3clicked == true {
        isbox3clicked = false
        sender.setImage(#imageLiteral(resourceName: "checkbox"), for: UIControlState.normal)
        defaults.set(isbox3clicked, forKey: "checkboxstatus3")
        checkedBoxTotal = checkedBoxTotal - 1
        defaults.set(checkedBoxTotal, forKey: "checkboxtotal")
        progressView.progress = Float(checkedBoxTotal)/Float(3)
        showCompleteLabel()
        defaults.set(progressView.progress, forKey:"progressviewprogress")

    } else {

        isbox3clicked = true
        sender.setImage(#imageLiteral(resourceName: "checkedbox"), for:UIControlState.normal)

        defaults.set(isbox3clicked, forKey: "checkboxstatus3")
        checkedBoxTotal = checkedBoxTotal + 1

        defaults.set(checkedBoxTotal, forKey: "checkboxtotal")

        progressView.progress = Float(checkedBoxTotal)/Float(3)
        showCompleteLabel()

        defaults.set(progressView.progress, forKey:"progressviewprogress")              
    }
}

func showCompleteLabel() { 
    if checkedBoxTotal == 3 { //if amount of boxes checked is 3, show goal complete label
        goalCompletedLabel.isHidden = false
    }
    else { //otherwise, hide it
        goalCompletedLabel.isHidden = true
    }
}

@IBOutlet weak var currentGoalNameLabel: UILabel!

@IBOutlet weak var goalPoint1Label: UILabel!

@IBOutlet weak var goalPoint2Label: UILabel!

@IBOutlet weak var goalPoint3Label: UILabel!


override func viewDidLoad() {
    super.viewDidLoad()

    self.title = "Current Goal"
    //boxes are initially unchecked
    isboxclicked = false 
    isbox2clicked = false
    isbox3clicked = false

    goalCompletedLabel.isHidden = true //goal completed label originally hidden
}

override func viewWillAppear(_ animated: Bool) {
    //loading state of checkbox
    isboxclicked = defaults.bool(forKey: "checkboxstatus")
    //if state is clicked, set checkbox to checked image
    if isboxclicked == true {
        uncheckBox.setImage(checkedBox, for: .normal)
    }
    //same logic as checkbox one
    isbox2clicked = defaults.bool(forKey: "checkboxstatus2")
    if isbox2clicked == true {
        uncheckBox2.setImage(checkedBox, for: .normal)
    }
    //same logic as checkbox two
    isbox3clicked = defaults.bool(forKey: "checkboxstatus3")
    if isbox3clicked == true {
        uncheckBox3.setImage(checkedBox, for: .normal)
    }
    //amount of checkboxes checked loaded
    checkedBoxTotal = defaults.integer(forKey: "checkboxtotal")
    //progress value loaded
    progressView.progress = defaults.float(forKey: "progressviewprogress")

    if let g = currentGoal { //text label values loaded into current CurrentGoalViewController 

        currentGoalNameLabel.text = g.name
        goalPoint1Label.text = g.goalPoint1
        goalPoint2Label.text = g.goalPoint2
        goalPoint3Label.text = g.goalPoint3
        deadlineLabel.text = g.deadline
    }
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}


/*
// MARK: - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    // Get the new view controller using segue.destinationViewController.
    // Pass the selected object to the new view controller.
}
*/
}

目标类(文字标签)

    import Foundation

    var goals = [Goal]()

    class Goal: NSObject, NSCoding {

        var name: String
        var goalPoint1: String
        var goalPoint2: String
        var goalPoint3: String
        var deadline: String

        init(name: String, goalPoint1: String, goalPoint2: String, goalPoint3: String, deadline: String)
        {
            self.name = name
            self.goalPoint1 = goalPoint1
            self.goalPoint2 = goalPoint2
            self.goalPoint3 = goalPoint3
            self.deadline = deadline
        }

        required init?(coder aDecoder: NSCoder)
        {
            if let name = aDecoder.decodeObject(forKey: "name") as? String {
                self.name = name
            }
            else {
                return nil
            }

            if let goalPoint1 = aDecoder.decodeObject(forKey: "goalPoint1") as? String {
                self.goalPoint1 = goalPoint1
            }
            else {
                return nil
            }

            if let goalPoint2 = aDecoder.decodeObject(forKey: "goalPoint2") as? String {
                self.goalPoint2 = goalPoint2
            }
            else {
                return nil
            }

            if let goalPoint3 = aDecoder.decodeObject(forKey: "goalPoint3") as? String {
                self.goalPoint3 = goalPoint3
            }
            else {
                return nil
            }

            if let deadline = aDecoder.decodeObject(forKey: "deadline") as? String {
                self.deadline = deadline
            }
            else {
                return nil
            }
        }

        func encode(with aCoder: NSCoder) {
            aCoder.encode(self.name, forKey: "name")
            aCoder.encode(self.goalPoint1, forKey: "goalPoint1")
            aCoder.encode(self.goalPoint2, forKey: "goalPoint2")
            aCoder.encode(self.goalPoint3, forKey: "goalPoint3")
            aCoder.encode(self.deadline, forKey: "deadline")
        }
    }

    //Creates an extension of the Collection type (aka an Array),
    //but only if it is an array of Goal objects
    extension Collection where Iterator.Element == Goal
    {
        //Builds the persistence URL. This is a location inside the
        //"Application Support" directory for the App.
        private static func persistencePath() -> URL?
        {
            let url = try? FileManager.default.url(
                for: .applicationSupportDirectory,
                in: .userDomainMask,
                appropriateFor: nil,
                create: true)

            return url?.appendingPathComponent("goalitems.bin")
        }

        //Write the array to persistence
        func writeToPersistence() throws
        {
        if let url = Self.persistencePath(), let array = self as? NSArray
        {
        let data = NSKeyedArchiver.archivedData(withRootObject: array)
            try data.write(to: url)
        }
        else {
            throw NSError(domain: "com.example.Goal", code: 10 , userInfo: nil)
            }
        }

        //Read the array from persistence
        static func readFromPersistence() throws -> [Goal]
        {
            if let url = persistencePath(), let data = (try Data(contentsOf: url) as Data?)
            {
                if let array = NSKeyedUnarchiver.unarchiveObject(with: data) as? [Goal]
                {
                    return array
                }
                else
                {
                    throw NSError(domain: "com.example.Goal", code: 11, userInfo: nil)
                }
            }
            else
            {
                throw NSError(domain: "com.example.Goal", code: 12, userInfo: nil)       
            }
        }
    }

0 个答案:

没有答案