我最近得到了帮助,让我的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)
}
}
}