【问题标题】:Saving Bool/ tableView Checkmark - 3rd time lucky保存 Bool/tableView 复选标记 - 第三次幸运
【发布时间】:2020-05-06 01:10:21
【问题描述】:

这是我第三次发布此问题,但尚未得到有效回复。

所以我有一个健身应用程序,用户在选择一个小区之前选择一个锻炼,在选择小区时,我希望它显示通过用复选标记来显示完成的单元格(包含练习)。这工作正常,但我正在努力解决如何在应用程序终止并重新启动时保存该复选标记。

下面我给出了一个锻炼模型和表格视图控制器的示例。

请有人尝试解决这个问题!

谢谢。

乔什

锻炼模型示例 -

import Foundation
class The600Workout {
    var workoutArray = [
        Workout(exercise: "Don't forget to warm up before every workout!", completed: false),
        Workout(exercise: "Start with little/ no weight and work your way up", completed: false),
        Workout(exercise: "------------------------------------------------------------------", completed: false),
        Workout(exercise: "Pull ups | 25 Reps", completed: false),
        Workout(exercise: "Lunges | 50 Reps (Low weight)", completed: false),
        Workout(exercise: "Calf Raises | 50 Reps (Low weight)", completed: false),
        Workout(exercise: "Shoulder press | 50 Reps (Low weight)", completed: false),
        Workout(exercise: "Push ups | 50 Reps", completed: false),
        Workout(exercise: "Shrugs | 50 Reps (Low weight)", completed: false),
        Workout(exercise: "Leg raises | 50 Reps", completed: false),
        Workout(exercise: "Bench press | 50 Reps (Low weight)", completed: false),
        Workout(exercise: "More Pull ups | 25 Reps", completed: false),
        Workout(exercise: "Squats | 50 Reps (Low weight)", completed: false),
        Workout(exercise: "Incline Bench press | 50 Reps (Low weight)", completed: false),
        Workout(exercise: "Bicep curls | 50 Reps (Low weight)", completed: false),
        Workout(exercise: "Tricep pull downs | 50 Reps (Low weight)", completed: false),
    ]
}

表格视图控制器

import UIKit
class workoutTableView: UIViewController, UITableViewDataSource, UITableViewDelegate {
    @IBOutlet weak var workoutTableView: UITableView!
    var navTitle: String = ""
    var workout = [Workout]()
    let tlabel = UILabel()
    override func viewDidLoad() {
        super.viewDidLoad()
        setWorkout()
        workoutTableView.delegate = self
        workoutTableView.dataSource = self
        tlabel.text = navTitle
        tlabel.textAlignment = .center
        tlabel.font = UIFont(name: "Arial Rounded MT Bold", size: 30)
        tlabel.adjustsFontSizeToFitWidth = true
        navigationItem.titleView = tlabel
    }
    func setWorkout() {
        if navTitle == "The 600 Workout" {
            workout = The600Workout().workoutArray
        }
        else if navTitle == "5 Days for Muscle" {
            workout = FiveDaysForMuscle().workoutArray
        }
        else if navTitle == "Marathon Ready" {
            workout = MarathonReady().workoutArray
        }
        else if navTitle == "HIIT @ Home" {
            workout = HIITAtHome().workoutArray
        }
        else if navTitle == "Get Strong" {
            workout = GetStrong().workoutArray
        }
        else if navTitle == "Body Weight Blast" {
            workout = BodyWeightBlast().workoutArray
        }
        else if navTitle == "Bands Pump" {
          workout = BandsPump().workoutArray
        }
        else if navTitle == "Quickie Warm up" {
            workout = QuickieWarmUp().workoutArray
        }
        else if navTitle == "The Best Circuit Workout" {
            workout = TheBestCircuit().workoutArray
        }
        else if navTitle == "The Gym HIIT Workout" {

            workout = GymHIIT().workoutArray
        }
        else if navTitle == "The Ultimate Workout" {
            workout = UltimateWorkout().workoutArray
        }
        else if navTitle == "Warm up For Weights" {
            workout = WarmUpForWeights().workoutArray
        }
        else if navTitle == "6 Day Bro Split" {
          workout = SixDayBroSplit().workoutArray
        }
        else if navTitle == "Explosive Workout" {
            workout = ExplosiveWorkout().workoutArray
        }
        else if navTitle == "Strength Circuit" {
            workout = StrengthCircuit().workoutArray
        }
        else if navTitle == "Killer Circuit" {    
            workout = KillerCircuit().workoutArray
        }
        else if navTitle == "Fitness Test" {
            workout = FitnessTest().workoutArray
        }
    }
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return workout.count
    }
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        workout[indexPath.row].completed = !workout[indexPath.row].completed
        tableView.cellForRow(at: indexPath)?.accessoryType = workout[indexPath.row].completed ?  .checkmark : .none
        tableView.deselectRow(at: indexPath, animated: false)
    }
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "prototypeCell", for: indexPath)
        cell.textLabel?.text = workout[indexPath.row].exercise
        cell.accessoryType = workout[indexPath.row].completed ?  .checkmark : .none
        cell.layer.borderWidth = 5
        cell.layer.cornerRadius = 20
        cell.layer.borderColor = #colorLiteral(red: 0, green: 0.3285208941, blue: 0.5748849511, alpha: 1)
        cell.textLabel?.textColor = UIColor.black
        cell.textLabel?.adjustsFontSizeToFitWidth = true
        cell.textLabel?.font = .boldSystemFont(ofSize: 15)
        return cell   
    }
}

【问题讨论】:

    标签: swift xcode uitableview data-persistence


    【解决方案1】:

    将单元格的当前状态(是否已选择)保存到 UserDefault。重新启动后,根据 UserDefaults 数据自动选择单元格。例如:

    var selectedCell = 0 // For declaration
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
            workout[indexPath.row].completed = !workout[indexPath.row].completed
            tableView.cellForRow(at: indexPath)?.accessoryType = workout[indexPath.row].completed ?  .checkmark : .none
            tableView.deselectRow(at: indexPath, animated: false)
    
            self.selectedCell = indexPath.row 
            UserDefaults.standart.set(self.selectedCell, forKey: "selectedCellIndex")
        }
    

    在 cellForRowAt:

    if indexPath.row == UserDefaults.standart.object(forKey: selectedCellIndex){
    //select this cell and whatever you want
    } else {
    //Other cells 
    }
    

    希望对你有帮助...

    【讨论】:

      【解决方案2】:

      为了能够分别保存每个练习的completed 状态,您必须重构数据模型。

      • 为整个模型创建一个 JSON 文件 - 例如命名为 WorkoutData.json - 并将其放入应用程序包中。该文件包含所有锻炼及其锻炼,并且将在首次启动时复制到 Documents 文件夹,或者如果您计划使用 reset 功能。 JSON文件的结构是

        [{"name":"The600Workout","exercises":
            [{"title":"Don't forget to warm up before every workout!", "completed": false},
            {"title":"Start with little/ no weight and work your way up", "completed": false},
            {"title":"------------------------------------------------------------------", "completed": false},
            {"title":"Pull ups | 25 Reps", "completed": false},
            {"title":"Lunges | 50 Reps (Low weight)", "completed": false},
            {"title":"Calf Raises | 50 Reps (Low weight)", "completed": false},
            {"title":"Shoulder press | 50 Reps (Low weight)", "completed": false},
            {"title":"Push ups | 50 Reps", "completed": false},
            {"title":"Shrugs | 50 Reps (Low weight)", "completed": false},
            {"title":"Leg raises | 50 Reps", "completed": false},
            {"title":"Bench press | 50 Reps (Low weight)", "completed": false},
            {"title":"More Pull ups | 25 Reps", "completed": false},
            {"title":"Squats | 50 Reps (Low weight)", "completed": false},
            {"title":"Incline Bench press | 50 Reps (Low weight)", "completed": false},
            {"title":"Bicep curls | 50 Reps (Low weight)", "completed": false},
            {"title":"Tricep pull downs | 50 Reps (Low weight)", "completed": false}]
        },
        {"name":"5 Days for Muscle","exercises": [ ... ]},
        {"name": ... [ ... ]},
        ...         
        ] 
        
      • 创建两个符合 Codable 且匹配 JSON 数据的结构

        struct Exercise : Codable {
            let title : String
            var completed : Bool
        }
        
        struct Workout : Codable {
            let name : String
            let exercises : [Exercise]
        }
        
      • viewDidLoad 中,使用计算属性获取Documents 文件夹中文件的URL

        var workoutDataURL : URL {
                return try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false).appendingPathComponent("WorkoutData.json")
        }
        

        并检查文件是否存在。如果不将文件从包复制到Documents

      • 使用JSONDecoder/JSONEncoder创建两种方法来加载和保存数据
      • 调用viewDidLoad中的load方法并重新加载表格视图
      • 每当用户选择单元格以更改completed 状态时,调用save 方法。
      • 您可以简单地使用workout = workoutArray.first{$0.name == navTitle}! 进行锻炼,而不是无穷无尽的if - else if 表达式
      • 删除所有锻炼课程。不再需要它们了。

      这是一个非常简单的解决方案。更有效的解决方案是使用像 Core data 这样的数据库。好处是您不需要将整个数据模型保存在内存中。

      【讨论】:

      • 如何创建 JSON 文件并将模型存储在其中?谢谢
      • 有两种方法: 1) 使用文本编辑器并使用 Find&Replace 构建 JSON(纯文本)(就像我在示例中快速完成的那样)。 2) 在代码中创建一个类数组,并使用JSONEncoder 对数组进行编码。这两种方法都简单明了。
      猜你喜欢
      • 2015-01-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多