Swift 保存Bool/tableView复选标记-第三次幸运
这是我第三次发布这些问题,目前还没有得到有效的回复 因此,我有一个健身应用程序,用户在将某项训练显示为“表格视图”之前选择了该训练,当选择某个单元格时,我希望该单元格(包含一项训练)通过选中标记将其显示为已完成。这很好,但我正在努力解决当应用程序终止并重新启动时如何保存复选标记的问题 下面我给出了一个训练模型和table view控制器的示例 请有人试着解决这个问题 多谢各位 乔希 训练模型示例-Swift 保存Bool/tableView复选标记-第三次幸运,swift,xcode,uitableview,data-persistence,Swift,Xcode,Uitableview,Data Persistence,这是我第三次发布这些问题,目前还没有得到有效的回复 因此,我有一个健身应用程序,用户在将某项训练显示为“表格视图”之前选择了该训练,当选择某个单元格时,我希望该单元格(包含一项训练)通过选中标记将其显示为已完成。这很好,但我正在努力解决当应用程序终止并重新启动时如何保存复选标记的问题 下面我给出了一个训练模型和table view控制器的示例 请有人试着解决这个问题 多谢各位 乔希 训练模型示例- import Foundation class The600Workout { var w
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
}
}
将单元格的当前状态(isSelected或not)保存到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
}
希望它有助于……能够分别保存每个练习的
完成状态,您必须重构数据模型
- 为整个模型创建一个JSON文件——例如名为
WorkoutData.JSON
——并将其放入应用程序包中。该文件包含所有训练及其练习,并将在首次启动或计划重置功能时复制到文档
文件夹。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")
}
并检查该文件是否存在。如果没有,请将文件从捆绑包复制到文档
- 使用
jsondeconder/jsonecoder
- 调用
viewDidLoad
中的load
方法并重新加载表视图
- 每当用户选择单元格以更改
completed
状态时,调用save
方法
- 与没完没了的
if-else if
表达式不同,您只需使用workout=workoutArray.first{$0.name==navTitle}即可获得训练代码>
- 删除所有训练课程。他们不再需要了
这是一个非常简单的解决方案。更有效的解决方案是使用类似于核心数据的数据库。好处是您不需要将整个数据模型保存在内存中。如何创建JSON文件并将模型存储在其中?感谢有两种方法:1)使用文本编辑器并使用Find&Replace构建JSON(纯文本)(就像我在示例中快速做的那样)。2) 在代码中创建类的数组,并使用jsonecoder
对数组进行编码。这两种方法都简单明了。