核心数据不保存 - UITableViewCell 返回 nil
CoreData not saving - TableViewCell returning nill
这是我的代码:
import UIKit
import CoreData
class ExerciseViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
override func viewDidLoad() {
super.viewDidLoad()
//sets stepper configs
setsStepper.wraps = false
setsStepper.autorepeat = true
setsStepper.continuous = true
setsStepper.tintColor = UIColor.redColor()
setsStepper.minimumValue = 0
setsStepper.maximumValue = 500
setsStepper.value = 0
//reps stepper configs
repsStepper.wraps = false
repsStepper.autorepeat = true
repsStepper.continuous = true
repsStepper.tintColor = UIColor.orangeColor()
repsStepper.minimumValue = 0
repsStepper.maximumValue = 500
repsStepper.value = 0
exerciseTableView.reloadData()
}
var moc = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
var fetchedResultsController: NSFetchedResultsController?
@IBOutlet var exerciseTableView: UITableView!
@IBOutlet var dayName: UITextField!
@IBOutlet var exerciseName: UITextField!
@IBOutlet var setsStepper: UIStepper!
@IBOutlet var repsStepper: UIStepper!
@IBOutlet var setsNumber: UILabel!
@IBOutlet var repsNumber: UILabel!
var daysArray = [String]()
var namesArray = [String]()
var setsArray = [Int]()
var repsArray = [Int]()
func appendDaysToArray() {
let dayLabel = dayName.text
daysArray.append(dayLabel)
let entityDescription = NSEntityDescription.entityForName("TrainingDay", inManagedObjectContext: moc!)
let trainingday = TrainingDay(entity: entityDescription!, insertIntoManagedObjectContext: moc)
trainingday.day = dayName.text
var error: NSError?
moc?.save(&error)
if let err = error {
var status = err.localizedFailureReason
println("\(status)")
} else {
println("Day #\(dayName.text) saved successfully!")
}
}
func appendNamesToArray () {
let nameLabel = exerciseName.text
namesArray.append(nameLabel)
let entityDescription = NSEntityDescription.entityForName("TrainingDetails", inManagedObjectContext: moc!)
let trainingdetails = TrainingDetails(entity: entityDescription!, insertIntoManagedObjectContext: moc)
trainingdetails.exerciseName = exerciseName.text
var error: NSError?
moc?.save(&error)
if let err = error {
var status = err.localizedFailureReason
println("\(status)")
} else {
println("Exercise: #\(exerciseName.text) saved successfully!")
}
}
func appendNumberToSets () {
let numberOfSets = setsNumber.text?.toInt()
setsArray.append(numberOfSets!)
let entityDescription = NSEntityDescription.entityForName("TrainingDetails", inManagedObjectContext: moc!)
let trainingdetails = TrainingDetails(entity: entityDescription!, insertIntoManagedObjectContext: moc)
trainingdetails.setsNumber = setsNumber.text!
var error: NSError?
moc?.save(&error)
if let err = error {
var status = err.localizedFailureReason
println("\(status)")
} else {
println("Exercise: #\(setsNumber.text) saved successfully!")
}
}
func appendNumberOfReps () {
let numberOfReps = repsNumber.text?.toInt()
repsArray.append(numberOfReps!)
let entityDescription = NSEntityDescription.entityForName("TrainingDetails", inManagedObjectContext: moc!)
let trainingdetails = TrainingDetails(entity: entityDescription!, insertIntoManagedObjectContext: moc)
trainingdetails.repsNumber = repsNumber.text!
var error: NSError?
moc?.save(&error)
if let err = error {
var status = err.localizedFailureReason
println("\(status)")
} else {
println("Exercise: #\(repsNumber.text) saved successfully!")
}
}
@IBAction func doneButton(sender: AnyObject) {
println("\(dayName.text)")
appendDaysToArray()
println("\(exerciseName.text)")
appendNamesToArray()
println("\(setsNumber.text)")
appendNumberToSets()
println("\(repsNumber.text)")
appendNumberOfReps()
exerciseTableView.reloadData()
}
@IBAction func setsStepperAction(sender: UIStepper) {
println("\(Int(sender.value))")
setsNumber.text = Int(sender.value).description
}
@IBAction func repsStepper(sender: UIStepper) {
println("\(Int(sender.value))")
repsNumber.text = Int(sender.value).description
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return namesArray.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellIdentifier = "exerciseCell"
var cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier) as? UITableViewCell
if cell == nil {
cell = UITableViewCell(style: UITableViewCellStyle.Value2, reuseIdentifier: cellIdentifier)
}
let row = indexPath.row
let name = namesArray[indexPath.row]
let numberReps = repsArray[indexPath.row]
let numberSets = setsArray[indexPath.row]
cell!.textLabel!.text = name
cell?.detailTextLabel?.text = "Sets: #\(numberSets) Reps: #\(numberReps)"
return cell!
}
}
和
class ViewExercisesViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, NSFetchedResultsControllerDelegate {
override func viewDidLoad() {
fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchTrainingDetails(), managedObjectContext: moc!, sectionNameKeyPath: nil, cacheName: nil)
fetchedResultsController?.delegate = self
fetchedResultsController?.performFetch(nil)
self.viewExerciseTableView.reloadData()
sundayButton.frame = CGRectMake(-30,150,125,125)
sundayButton.addTarget(self, action: "sundayButtonTouch:", forControlEvents: UIControlEvents.TouchDown)
sundayButton.setImage(imageSunday, forState: .Normal)
sundayButton.imageEdgeInsets = UIEdgeInsetsMake(30,30,30,30)
self.view.addSubview(sundayButton)
mondayButton.frame = CGRectMake(120,150,125,125)
mondayButton.addTarget(self, action: "mondayButtonTouch:", forControlEvents: UIControlEvents.TouchDown)
mondayButton.setImage(imageMonday, forState: .Normal)
mondayButton.imageEdgeInsets = UIEdgeInsetsMake(30,30,30,30)
self.view.addSubview(mondayButton)
tuesdayButton.frame = CGRectMake(270,150,125,125)
tuesdayButton.addTarget(self, action: "tuesdayButtonTouch:", forControlEvents: UIControlEvents.TouchDown)
tuesdayButton.setImage(imageTuesday, forState: .Normal)
tuesdayButton.imageEdgeInsets = UIEdgeInsetsMake(30,30,30,30)
self.view.addSubview(tuesdayButton)
wednesdayButton.frame = CGRectMake(-30,250,125,125)
wednesdayButton.addTarget(self, action: "wednesdayButtonTouch:", forControlEvents: UIControlEvents.TouchDown)
wednesdayButton.setImage(imageWednesday, forState: .Normal)
wednesdayButton.imageEdgeInsets = UIEdgeInsetsMake(30,30,30,30)
self.view.addSubview(wednesdayButton)
thursdayButton.frame = CGRectMake(70,250,125,125)
thursdayButton.addTarget(self, action: "thursdayButtonTouch:", forControlEvents: UIControlEvents.TouchDown)
thursdayButton.setImage(imageThursday, forState: .Normal)
thursdayButton.imageEdgeInsets = UIEdgeInsetsMake(30,30,30,30)
self.view.addSubview(thursdayButton)
fridayButton.frame = CGRectMake(170,250,125,125)
fridayButton.addTarget(self, action: "fridayButtonTouch:", forControlEvents: UIControlEvents.TouchDown)
fridayButton.setImage(imageFriday, forState: .Normal)
fridayButton.imageEdgeInsets = UIEdgeInsetsMake(30,30,30,30)
self.view.addSubview(fridayButton)
saturdayButton.frame = CGRectMake(270,250,125,125)
saturdayButton.addTarget(self, action: "saturdayButtonTouch:", forControlEvents: UIControlEvents.TouchDown)
saturdayButton.setImage(imageSaturday, forState: .Normal)
saturdayButton.imageEdgeInsets = UIEdgeInsetsMake(30,30,30,30)
self.view.addSubview(saturdayButton)
}
//VAR AND LET
var sundayButton = UIButton.buttonWithType(UIButtonType.Custom) as! UIButton
var imageSunday = UIImage(named: "day.png")
var mondayButton = UIButton.buttonWithType(UIButtonType.Custom) as! UIButton
var imageMonday = UIImage(named: "day.png")
var tuesdayButton = UIButton.buttonWithType(UIButtonType.Custom) as! UIButton
var imageTuesday = UIImage(named: "day.png")
var wednesdayButton = UIButton.buttonWithType(UIButtonType.Custom) as! UIButton
var imageWednesday = UIImage(named: "day.png")
var thursdayButton = UIButton.buttonWithType(UIButtonType.Custom) as! UIButton
var imageThursday = UIImage(named: "day.png")
var fridayButton = UIButton.buttonWithType(UIButtonType.Custom) as! UIButton
var imageFriday = UIImage(named: "day.png")
var saturdayButton = UIButton.buttonWithType(UIButtonType.Custom) as! UIButton
var imageSaturday = UIImage(named: "day.png")
@IBOutlet var viewExerciseTableView: UITableView!
var moc = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
var fetchedResultsController: NSFetchedResultsController?
// FUNCTIONS
func sundayButtonTouch(sender: UIButton!) {
println("future event will be added, button working fine - sunday")
}
func mondayButtonTouch(sender: UIButton!) {
println("future event will be added, button working fine - monday")
}
func tuesdayButtonTouch(sender: UIButton!) {
println("future event will be added, button working fine - tuesday")
}
func wednesdayButtonTouch(sender: UIButton!) {
println("future event will be added, button working fine - wednesday")
}
func thursdayButtonTouch(sender: UIButton!) {
println("future event will be added, button working fine - thursday")
}
func fridayButtonTouch(sender: UIButton!) {
println("future event will be added, button working fine - friday")
}
func saturdayButtonTouch(sender: UIButton!) {
println("future event will be added, button working fine - saturday")
}
// FETCH REQUEST METHODS
func fetchTrainingDay() -> NSFetchRequest {
let fetchRequest = NSFetchRequest(entityName: "TrainingDay")
// let predicate = NSPredicate(format: "day == %@")
let sortDescriptor = NSSortDescriptor(key: "day", ascending: true)
fetchRequest.predicate = nil
fetchRequest.sortDescriptors = [sortDescriptor]
fetchRequest.fetchBatchSize = 20
return fetchRequest
}
func fetchTrainingDetails() -> NSFetchRequest {
let fetchRequest = NSFetchRequest(entityName: "TrainingDetails")
fetchRequest.predicate = nil
let sortDescriptor1 = NSSortDescriptor(key: "exerciseName", ascending: true)
let sortDescriptor2 = NSSortDescriptor(key: "repsNumber", ascending: true)
let sortDescriptor3 = NSSortDescriptor(key: "setsNumber", ascending: true)
fetchRequest.sortDescriptors = [sortDescriptor1, sortDescriptor2, sortDescriptor3]
fetchRequest.fetchBatchSize = 20
return fetchRequest
}
//TABLE VIEW DELEGATE METHODS
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return fetchedResultsController?.sections?[section].numberOfObjects ?? 0
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellIdentifier = "exCell"
var cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier) as? UITableViewCell
if let exCell = fetchedResultsController?.objectAtIndexPath(indexPath) as? TrainingDetails {
println("THE ERROR IS HERE #\(exCell.exerciseName) \(exCell.repsNumber) \(exCell.setsNumber)")
cell!.textLabel?.text = exCell.exerciseName
cell?.detailTextLabel?.text = "Sets: #\(exCell.setsNumber) Reps: #\(exCell.repsNumber)"
}
return cell!
}
// MARK: NSFetchedResultsControllerDelegate
func controllerWillChangeContent(controller: NSFetchedResultsController) {
self.viewExerciseTableView.beginUpdates()
}
func controller(controller: NSFetchedResultsController,
didChangeObject anObject: AnyObject,
atIndexPath indexPath: NSIndexPath?,
forChangeType type: NSFetchedResultsChangeType,
newIndexPath: NSIndexPath?)
{
switch(type) {
case .Insert:
if let newIndexPath = newIndexPath {
viewExerciseTableView.insertRowsAtIndexPaths([newIndexPath],
withRowAnimation:UITableViewRowAnimation.Fade)
}
case .Delete:
if let indexPath = indexPath {
viewExerciseTableView.deleteRowsAtIndexPaths([indexPath],
withRowAnimation: UITableViewRowAnimation.Fade)
}
case .Update:
break
case .Move:
if let indexPath = indexPath {
if let newIndexPath = newIndexPath {
viewExerciseTableView.deleteRowsAtIndexPaths([indexPath],
withRowAnimation: UITableViewRowAnimation.Fade)
viewExerciseTableView.insertRowsAtIndexPaths([newIndexPath],
withRowAnimation: UITableViewRowAnimation.Fade)
}
}
}
}
func controller(controller: NSFetchedResultsController,
didChangeSection sectionInfo: NSFetchedResultsSectionInfo,
atIndex sectionIndex: Int,
forChangeType type: NSFetchedResultsChangeType)
{
switch(type) {
case .Insert:
viewExerciseTableView.insertSections(NSIndexSet(index: sectionIndex),
withRowAnimation: UITableViewRowAnimation.Fade)
case .Delete:
viewExerciseTableView.deleteSections(NSIndexSet(index: sectionIndex),
withRowAnimation: UITableViewRowAnimation.Fade)
default:
break
}
}
func controllerDidChangeContent(controller: NSFetchedResultsController) {
viewExerciseTableView.endUpdates()
}
}
和
import Foundation
import CoreData
class TrainingDetails: NSManagedObject {
@NSManaged var exerciseName: String
@NSManaged var setsNumber: String
@NSManaged var repsNumber: String
@NSManaged var relationship2: NSManagedObject
}
逻辑是这样的:在"ExerciseViewController"中,我在CoreData中放了一些东西,这个视图工作正常。现在,在 ViewExercisesViewController 中,我应该检索 exerciseName 并将其设置为单元格的文本标签,但它就在此处崩溃:println("THE ERROR IS HERE #\(exCell.exerciseName) \(exCell.repsNumber) \(exCell.setsNumber)")
。似乎我没有正确检索它,但我确定它被保存在 CoreData 中。
有人知道吗?我有一个应用程序可以做类似的事情,但是这个不工作。
感谢您的帮助,我期待着找出问题所在。
编辑 -> 图片有挤压错误:
编辑 2
这样做:
导致这个:
最终编辑 -> 解决方案
正如汤姆所说,这样做:
func appendTrainingDetails () {
let nameLabel = exerciseName.text
namesArray.append(nameLabel)
let numberOfSets = setsNumber.text?.toInt()
setsArray.append(numberOfSets!)
let numberOfReps = repsNumber.text?.toInt()
repsArray.append(numberOfReps!)
let entityDescription = NSEntityDescription.entityForName("TrainingDetails", inManagedObjectContext: moc!)
let trainingdetails = TrainingDetails(entity: entityDescription!, insertIntoManagedObjectContext: moc)
trainingdetails.exerciseName = exerciseName.text
trainingdetails.setsNumber = setsNumber.text!
trainingdetails.repsNumber = repsNumber.text!
var error: NSError?
moc?.save(&error)
if let err = error {
var status = err.localizedFailureReason
println("\(status)")
} else {
println("Exercise: #\(exerciseName.text) saved successfully!")
println("Number of sets: #\(setsNumber.text) saved successfully!")
println("Number of reps: #\(repsNumber.text) saved successfully!")
}
}
通过这些方法,让我修正了我做错的地方!非常非常感谢!!
在你的函数 appendNumberOfReps()
中,你似乎使用点语法将它添加到 TrainingDay
对象(不确定你在哪里定义它,虽然我假设它是一个 NSManagedObject?) .在您的核心数据实体 TrainingDay
中,创建一个名为 repsNumber
的属性,我假设我们可以将其设置为 String
并试试这个:
// Save To Core Data
let entityDescription = NSEntityDescription.entityForName("TrainingDay", inManagedObjectContext: moc!)
let trainingday = NSManagedObject(entity: entityDescription!, insertIntoManagedObjectContext: moc)
var error: NSError?
moc?.save(&error)
trainingday.setValue(repsNumber.text!, forKey: "repsNumber")
if !moc.save(&error) {
println("Could not save \(error)")
} else {
println("Exercise: #\(repsNumber.text) saved successfully!")
}
然后为了正确设置您的 table,最简单的方法是通过读取数组的计数和数据来设置它们。因此,也许您可以调用 Core Data 来 return 数据,然后将它们附加到名为 var repsArray: String = []
:
的数组中
// Fetch From Core Data
let trainingFetchRequest = NSFetchRequest(entityName:"TrainingDay")
let fetchedResults = moc.executeFetchRequest(trainingFetchRequest, error: &error) as? [NSManagedObject]
if let results = fetchedResults {
if results.count > 0 {
for index in 0...results.count-1 {
let match = results[index] as NSManagedObject
repsArray.append(match.valueForKey("repsNumber") as! String)
}
}
}
然后通过使用 repsArray
(仅作为示例)到 return 行计数可能更容易计算 table 中应该有多少行:
func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int {
return repsArray.count
}
然后只要你有正确的table单元格class(例如下面的CustomCell
)和在Interface Builder中创建的标签名称(例如repNumberLabel
下面)然后附加到 CustomCell
,你可以只使用 indexPath.Row 来处理你构建的数组:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("cell") as? CustomCell
if !(cell != nil) {
cell = CustomCell(style: .Subtitle, reuseIdentifier: "cell")
}
cell?.repNumberLabel.text = self.repsArray[indexPath.row]
}
希望这对您已经尝试过的内容有所帮助,并且不是多余的!这就是我尝试保存到核心数据然后检索数据以在 table 单元格中使用时对我有用的方法。
这是正在发生的事情...
您的方法 appendNumberToSets()
、appendNumberOfReps()
和 appendNamesToArray()
都有以下代码:
let entityDescription = NSEntityDescription.entityForName("TrainingDetails", inManagedObjectContext: moc!)
let trainingdetails = TrainingDetails(entity: entityDescription!, insertIntoManagedObjectContext: moc)
这意味着 其中每一个 都在创建 TrainingDetails
的新实例。然而,
appendNumberToSets()
仅 为 setsNumber
属性 设置一个值
appendNamesToArray()
仅 为 exerciseName
属性 设置一个值
appendNumberOfReps()
仅 为 repsNumber
属性 设置一个值
在所有这三种方法中,您都在创建新的 TrainingDetails
实例,但将大部分属性保留为 nil 值。 那没问题 只是稍后您尝试在同一实例上查找 exerciseName
、setsNumber
和 repsNumber
。由于 none 个实例具有所有三个值,因此您的应用程序崩溃了。
这是因为 Core Data 知道可选值是什么,Swift 也知道 "optional" 是什么意思,但是 这些不是同样的事情。 Core Data 不关心您是否将这些属性保留为 nil 值,但 Swift 会。这两种想法的冲突导致了你的问题。
你应该做什么:
- 如果这些值应该是可选的,也就是说,它们可以为零,你应该改变你的
TrainingDetails
class来使它们Swift 选项。看起来您正在使用 Xcode 生成的代码,但 该代码是错误的 并且完全可以修复它。然后编译器会强制你检查属性是否有值,你不会崩溃。
- 如果这些值不应该是可选的,也就是说,任何
TrainingDetails
都必须具有这些属性中的每一个的值,您应该做两件事。首先,编辑您的核心数据模型。对于这些属性中的每一个,取消选中模型编辑器中的 "Optional" 框。这样 Core Data 就会知道 nil 是不允许的,如果你有意外的 nil,它会阻止你保存更改。其次,您需要将上述三种方法更改为 (a) 始终为所有属性赋值,或 (b) 重复使用相同的 TrainingDetails
实例,而不是在每个方法中创建一个新实例(选择取决于您的要求,因此由您决定哪个是正确的。
这是我的代码:
import UIKit
import CoreData
class ExerciseViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
override func viewDidLoad() {
super.viewDidLoad()
//sets stepper configs
setsStepper.wraps = false
setsStepper.autorepeat = true
setsStepper.continuous = true
setsStepper.tintColor = UIColor.redColor()
setsStepper.minimumValue = 0
setsStepper.maximumValue = 500
setsStepper.value = 0
//reps stepper configs
repsStepper.wraps = false
repsStepper.autorepeat = true
repsStepper.continuous = true
repsStepper.tintColor = UIColor.orangeColor()
repsStepper.minimumValue = 0
repsStepper.maximumValue = 500
repsStepper.value = 0
exerciseTableView.reloadData()
}
var moc = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
var fetchedResultsController: NSFetchedResultsController?
@IBOutlet var exerciseTableView: UITableView!
@IBOutlet var dayName: UITextField!
@IBOutlet var exerciseName: UITextField!
@IBOutlet var setsStepper: UIStepper!
@IBOutlet var repsStepper: UIStepper!
@IBOutlet var setsNumber: UILabel!
@IBOutlet var repsNumber: UILabel!
var daysArray = [String]()
var namesArray = [String]()
var setsArray = [Int]()
var repsArray = [Int]()
func appendDaysToArray() {
let dayLabel = dayName.text
daysArray.append(dayLabel)
let entityDescription = NSEntityDescription.entityForName("TrainingDay", inManagedObjectContext: moc!)
let trainingday = TrainingDay(entity: entityDescription!, insertIntoManagedObjectContext: moc)
trainingday.day = dayName.text
var error: NSError?
moc?.save(&error)
if let err = error {
var status = err.localizedFailureReason
println("\(status)")
} else {
println("Day #\(dayName.text) saved successfully!")
}
}
func appendNamesToArray () {
let nameLabel = exerciseName.text
namesArray.append(nameLabel)
let entityDescription = NSEntityDescription.entityForName("TrainingDetails", inManagedObjectContext: moc!)
let trainingdetails = TrainingDetails(entity: entityDescription!, insertIntoManagedObjectContext: moc)
trainingdetails.exerciseName = exerciseName.text
var error: NSError?
moc?.save(&error)
if let err = error {
var status = err.localizedFailureReason
println("\(status)")
} else {
println("Exercise: #\(exerciseName.text) saved successfully!")
}
}
func appendNumberToSets () {
let numberOfSets = setsNumber.text?.toInt()
setsArray.append(numberOfSets!)
let entityDescription = NSEntityDescription.entityForName("TrainingDetails", inManagedObjectContext: moc!)
let trainingdetails = TrainingDetails(entity: entityDescription!, insertIntoManagedObjectContext: moc)
trainingdetails.setsNumber = setsNumber.text!
var error: NSError?
moc?.save(&error)
if let err = error {
var status = err.localizedFailureReason
println("\(status)")
} else {
println("Exercise: #\(setsNumber.text) saved successfully!")
}
}
func appendNumberOfReps () {
let numberOfReps = repsNumber.text?.toInt()
repsArray.append(numberOfReps!)
let entityDescription = NSEntityDescription.entityForName("TrainingDetails", inManagedObjectContext: moc!)
let trainingdetails = TrainingDetails(entity: entityDescription!, insertIntoManagedObjectContext: moc)
trainingdetails.repsNumber = repsNumber.text!
var error: NSError?
moc?.save(&error)
if let err = error {
var status = err.localizedFailureReason
println("\(status)")
} else {
println("Exercise: #\(repsNumber.text) saved successfully!")
}
}
@IBAction func doneButton(sender: AnyObject) {
println("\(dayName.text)")
appendDaysToArray()
println("\(exerciseName.text)")
appendNamesToArray()
println("\(setsNumber.text)")
appendNumberToSets()
println("\(repsNumber.text)")
appendNumberOfReps()
exerciseTableView.reloadData()
}
@IBAction func setsStepperAction(sender: UIStepper) {
println("\(Int(sender.value))")
setsNumber.text = Int(sender.value).description
}
@IBAction func repsStepper(sender: UIStepper) {
println("\(Int(sender.value))")
repsNumber.text = Int(sender.value).description
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return namesArray.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellIdentifier = "exerciseCell"
var cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier) as? UITableViewCell
if cell == nil {
cell = UITableViewCell(style: UITableViewCellStyle.Value2, reuseIdentifier: cellIdentifier)
}
let row = indexPath.row
let name = namesArray[indexPath.row]
let numberReps = repsArray[indexPath.row]
let numberSets = setsArray[indexPath.row]
cell!.textLabel!.text = name
cell?.detailTextLabel?.text = "Sets: #\(numberSets) Reps: #\(numberReps)"
return cell!
}
}
和
class ViewExercisesViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, NSFetchedResultsControllerDelegate {
override func viewDidLoad() {
fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchTrainingDetails(), managedObjectContext: moc!, sectionNameKeyPath: nil, cacheName: nil)
fetchedResultsController?.delegate = self
fetchedResultsController?.performFetch(nil)
self.viewExerciseTableView.reloadData()
sundayButton.frame = CGRectMake(-30,150,125,125)
sundayButton.addTarget(self, action: "sundayButtonTouch:", forControlEvents: UIControlEvents.TouchDown)
sundayButton.setImage(imageSunday, forState: .Normal)
sundayButton.imageEdgeInsets = UIEdgeInsetsMake(30,30,30,30)
self.view.addSubview(sundayButton)
mondayButton.frame = CGRectMake(120,150,125,125)
mondayButton.addTarget(self, action: "mondayButtonTouch:", forControlEvents: UIControlEvents.TouchDown)
mondayButton.setImage(imageMonday, forState: .Normal)
mondayButton.imageEdgeInsets = UIEdgeInsetsMake(30,30,30,30)
self.view.addSubview(mondayButton)
tuesdayButton.frame = CGRectMake(270,150,125,125)
tuesdayButton.addTarget(self, action: "tuesdayButtonTouch:", forControlEvents: UIControlEvents.TouchDown)
tuesdayButton.setImage(imageTuesday, forState: .Normal)
tuesdayButton.imageEdgeInsets = UIEdgeInsetsMake(30,30,30,30)
self.view.addSubview(tuesdayButton)
wednesdayButton.frame = CGRectMake(-30,250,125,125)
wednesdayButton.addTarget(self, action: "wednesdayButtonTouch:", forControlEvents: UIControlEvents.TouchDown)
wednesdayButton.setImage(imageWednesday, forState: .Normal)
wednesdayButton.imageEdgeInsets = UIEdgeInsetsMake(30,30,30,30)
self.view.addSubview(wednesdayButton)
thursdayButton.frame = CGRectMake(70,250,125,125)
thursdayButton.addTarget(self, action: "thursdayButtonTouch:", forControlEvents: UIControlEvents.TouchDown)
thursdayButton.setImage(imageThursday, forState: .Normal)
thursdayButton.imageEdgeInsets = UIEdgeInsetsMake(30,30,30,30)
self.view.addSubview(thursdayButton)
fridayButton.frame = CGRectMake(170,250,125,125)
fridayButton.addTarget(self, action: "fridayButtonTouch:", forControlEvents: UIControlEvents.TouchDown)
fridayButton.setImage(imageFriday, forState: .Normal)
fridayButton.imageEdgeInsets = UIEdgeInsetsMake(30,30,30,30)
self.view.addSubview(fridayButton)
saturdayButton.frame = CGRectMake(270,250,125,125)
saturdayButton.addTarget(self, action: "saturdayButtonTouch:", forControlEvents: UIControlEvents.TouchDown)
saturdayButton.setImage(imageSaturday, forState: .Normal)
saturdayButton.imageEdgeInsets = UIEdgeInsetsMake(30,30,30,30)
self.view.addSubview(saturdayButton)
}
//VAR AND LET
var sundayButton = UIButton.buttonWithType(UIButtonType.Custom) as! UIButton
var imageSunday = UIImage(named: "day.png")
var mondayButton = UIButton.buttonWithType(UIButtonType.Custom) as! UIButton
var imageMonday = UIImage(named: "day.png")
var tuesdayButton = UIButton.buttonWithType(UIButtonType.Custom) as! UIButton
var imageTuesday = UIImage(named: "day.png")
var wednesdayButton = UIButton.buttonWithType(UIButtonType.Custom) as! UIButton
var imageWednesday = UIImage(named: "day.png")
var thursdayButton = UIButton.buttonWithType(UIButtonType.Custom) as! UIButton
var imageThursday = UIImage(named: "day.png")
var fridayButton = UIButton.buttonWithType(UIButtonType.Custom) as! UIButton
var imageFriday = UIImage(named: "day.png")
var saturdayButton = UIButton.buttonWithType(UIButtonType.Custom) as! UIButton
var imageSaturday = UIImage(named: "day.png")
@IBOutlet var viewExerciseTableView: UITableView!
var moc = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
var fetchedResultsController: NSFetchedResultsController?
// FUNCTIONS
func sundayButtonTouch(sender: UIButton!) {
println("future event will be added, button working fine - sunday")
}
func mondayButtonTouch(sender: UIButton!) {
println("future event will be added, button working fine - monday")
}
func tuesdayButtonTouch(sender: UIButton!) {
println("future event will be added, button working fine - tuesday")
}
func wednesdayButtonTouch(sender: UIButton!) {
println("future event will be added, button working fine - wednesday")
}
func thursdayButtonTouch(sender: UIButton!) {
println("future event will be added, button working fine - thursday")
}
func fridayButtonTouch(sender: UIButton!) {
println("future event will be added, button working fine - friday")
}
func saturdayButtonTouch(sender: UIButton!) {
println("future event will be added, button working fine - saturday")
}
// FETCH REQUEST METHODS
func fetchTrainingDay() -> NSFetchRequest {
let fetchRequest = NSFetchRequest(entityName: "TrainingDay")
// let predicate = NSPredicate(format: "day == %@")
let sortDescriptor = NSSortDescriptor(key: "day", ascending: true)
fetchRequest.predicate = nil
fetchRequest.sortDescriptors = [sortDescriptor]
fetchRequest.fetchBatchSize = 20
return fetchRequest
}
func fetchTrainingDetails() -> NSFetchRequest {
let fetchRequest = NSFetchRequest(entityName: "TrainingDetails")
fetchRequest.predicate = nil
let sortDescriptor1 = NSSortDescriptor(key: "exerciseName", ascending: true)
let sortDescriptor2 = NSSortDescriptor(key: "repsNumber", ascending: true)
let sortDescriptor3 = NSSortDescriptor(key: "setsNumber", ascending: true)
fetchRequest.sortDescriptors = [sortDescriptor1, sortDescriptor2, sortDescriptor3]
fetchRequest.fetchBatchSize = 20
return fetchRequest
}
//TABLE VIEW DELEGATE METHODS
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return fetchedResultsController?.sections?[section].numberOfObjects ?? 0
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellIdentifier = "exCell"
var cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier) as? UITableViewCell
if let exCell = fetchedResultsController?.objectAtIndexPath(indexPath) as? TrainingDetails {
println("THE ERROR IS HERE #\(exCell.exerciseName) \(exCell.repsNumber) \(exCell.setsNumber)")
cell!.textLabel?.text = exCell.exerciseName
cell?.detailTextLabel?.text = "Sets: #\(exCell.setsNumber) Reps: #\(exCell.repsNumber)"
}
return cell!
}
// MARK: NSFetchedResultsControllerDelegate
func controllerWillChangeContent(controller: NSFetchedResultsController) {
self.viewExerciseTableView.beginUpdates()
}
func controller(controller: NSFetchedResultsController,
didChangeObject anObject: AnyObject,
atIndexPath indexPath: NSIndexPath?,
forChangeType type: NSFetchedResultsChangeType,
newIndexPath: NSIndexPath?)
{
switch(type) {
case .Insert:
if let newIndexPath = newIndexPath {
viewExerciseTableView.insertRowsAtIndexPaths([newIndexPath],
withRowAnimation:UITableViewRowAnimation.Fade)
}
case .Delete:
if let indexPath = indexPath {
viewExerciseTableView.deleteRowsAtIndexPaths([indexPath],
withRowAnimation: UITableViewRowAnimation.Fade)
}
case .Update:
break
case .Move:
if let indexPath = indexPath {
if let newIndexPath = newIndexPath {
viewExerciseTableView.deleteRowsAtIndexPaths([indexPath],
withRowAnimation: UITableViewRowAnimation.Fade)
viewExerciseTableView.insertRowsAtIndexPaths([newIndexPath],
withRowAnimation: UITableViewRowAnimation.Fade)
}
}
}
}
func controller(controller: NSFetchedResultsController,
didChangeSection sectionInfo: NSFetchedResultsSectionInfo,
atIndex sectionIndex: Int,
forChangeType type: NSFetchedResultsChangeType)
{
switch(type) {
case .Insert:
viewExerciseTableView.insertSections(NSIndexSet(index: sectionIndex),
withRowAnimation: UITableViewRowAnimation.Fade)
case .Delete:
viewExerciseTableView.deleteSections(NSIndexSet(index: sectionIndex),
withRowAnimation: UITableViewRowAnimation.Fade)
default:
break
}
}
func controllerDidChangeContent(controller: NSFetchedResultsController) {
viewExerciseTableView.endUpdates()
}
}
和
import Foundation
import CoreData
class TrainingDetails: NSManagedObject {
@NSManaged var exerciseName: String
@NSManaged var setsNumber: String
@NSManaged var repsNumber: String
@NSManaged var relationship2: NSManagedObject
}
逻辑是这样的:在"ExerciseViewController"中,我在CoreData中放了一些东西,这个视图工作正常。现在,在 ViewExercisesViewController 中,我应该检索 exerciseName 并将其设置为单元格的文本标签,但它就在此处崩溃:println("THE ERROR IS HERE #\(exCell.exerciseName) \(exCell.repsNumber) \(exCell.setsNumber)")
。似乎我没有正确检索它,但我确定它被保存在 CoreData 中。
有人知道吗?我有一个应用程序可以做类似的事情,但是这个不工作。
感谢您的帮助,我期待着找出问题所在。
编辑 -> 图片有挤压错误:
编辑 2
这样做:
导致这个:
最终编辑 -> 解决方案
正如汤姆所说,这样做:
func appendTrainingDetails () {
let nameLabel = exerciseName.text
namesArray.append(nameLabel)
let numberOfSets = setsNumber.text?.toInt()
setsArray.append(numberOfSets!)
let numberOfReps = repsNumber.text?.toInt()
repsArray.append(numberOfReps!)
let entityDescription = NSEntityDescription.entityForName("TrainingDetails", inManagedObjectContext: moc!)
let trainingdetails = TrainingDetails(entity: entityDescription!, insertIntoManagedObjectContext: moc)
trainingdetails.exerciseName = exerciseName.text
trainingdetails.setsNumber = setsNumber.text!
trainingdetails.repsNumber = repsNumber.text!
var error: NSError?
moc?.save(&error)
if let err = error {
var status = err.localizedFailureReason
println("\(status)")
} else {
println("Exercise: #\(exerciseName.text) saved successfully!")
println("Number of sets: #\(setsNumber.text) saved successfully!")
println("Number of reps: #\(repsNumber.text) saved successfully!")
}
}
通过这些方法,让我修正了我做错的地方!非常非常感谢!!
在你的函数 appendNumberOfReps()
中,你似乎使用点语法将它添加到 TrainingDay
对象(不确定你在哪里定义它,虽然我假设它是一个 NSManagedObject?) .在您的核心数据实体 TrainingDay
中,创建一个名为 repsNumber
的属性,我假设我们可以将其设置为 String
并试试这个:
// Save To Core Data
let entityDescription = NSEntityDescription.entityForName("TrainingDay", inManagedObjectContext: moc!)
let trainingday = NSManagedObject(entity: entityDescription!, insertIntoManagedObjectContext: moc)
var error: NSError?
moc?.save(&error)
trainingday.setValue(repsNumber.text!, forKey: "repsNumber")
if !moc.save(&error) {
println("Could not save \(error)")
} else {
println("Exercise: #\(repsNumber.text) saved successfully!")
}
然后为了正确设置您的 table,最简单的方法是通过读取数组的计数和数据来设置它们。因此,也许您可以调用 Core Data 来 return 数据,然后将它们附加到名为 var repsArray: String = []
:
// Fetch From Core Data
let trainingFetchRequest = NSFetchRequest(entityName:"TrainingDay")
let fetchedResults = moc.executeFetchRequest(trainingFetchRequest, error: &error) as? [NSManagedObject]
if let results = fetchedResults {
if results.count > 0 {
for index in 0...results.count-1 {
let match = results[index] as NSManagedObject
repsArray.append(match.valueForKey("repsNumber") as! String)
}
}
}
然后通过使用 repsArray
(仅作为示例)到 return 行计数可能更容易计算 table 中应该有多少行:
func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int {
return repsArray.count
}
然后只要你有正确的table单元格class(例如下面的CustomCell
)和在Interface Builder中创建的标签名称(例如repNumberLabel
下面)然后附加到 CustomCell
,你可以只使用 indexPath.Row 来处理你构建的数组:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("cell") as? CustomCell
if !(cell != nil) {
cell = CustomCell(style: .Subtitle, reuseIdentifier: "cell")
}
cell?.repNumberLabel.text = self.repsArray[indexPath.row]
}
希望这对您已经尝试过的内容有所帮助,并且不是多余的!这就是我尝试保存到核心数据然后检索数据以在 table 单元格中使用时对我有用的方法。
这是正在发生的事情...
您的方法 appendNumberToSets()
、appendNumberOfReps()
和 appendNamesToArray()
都有以下代码:
let entityDescription = NSEntityDescription.entityForName("TrainingDetails", inManagedObjectContext: moc!)
let trainingdetails = TrainingDetails(entity: entityDescription!, insertIntoManagedObjectContext: moc)
这意味着 其中每一个 都在创建 TrainingDetails
的新实例。然而,
appendNumberToSets()
仅 为setsNumber
属性 设置一个值
appendNamesToArray()
仅 为exerciseName
属性 设置一个值
appendNumberOfReps()
仅 为repsNumber
属性 设置一个值
在所有这三种方法中,您都在创建新的 TrainingDetails
实例,但将大部分属性保留为 nil 值。 那没问题 只是稍后您尝试在同一实例上查找 exerciseName
、setsNumber
和 repsNumber
。由于 none 个实例具有所有三个值,因此您的应用程序崩溃了。
这是因为 Core Data 知道可选值是什么,Swift 也知道 "optional" 是什么意思,但是 这些不是同样的事情。 Core Data 不关心您是否将这些属性保留为 nil 值,但 Swift 会。这两种想法的冲突导致了你的问题。
你应该做什么:
- 如果这些值应该是可选的,也就是说,它们可以为零,你应该改变你的
TrainingDetails
class来使它们Swift 选项。看起来您正在使用 Xcode 生成的代码,但 该代码是错误的 并且完全可以修复它。然后编译器会强制你检查属性是否有值,你不会崩溃。 - 如果这些值不应该是可选的,也就是说,任何
TrainingDetails
都必须具有这些属性中的每一个的值,您应该做两件事。首先,编辑您的核心数据模型。对于这些属性中的每一个,取消选中模型编辑器中的 "Optional" 框。这样 Core Data 就会知道 nil 是不允许的,如果你有意外的 nil,它会阻止你保存更改。其次,您需要将上述三种方法更改为 (a) 始终为所有属性赋值,或 (b) 重复使用相同的TrainingDetails
实例,而不是在每个方法中创建一个新实例(选择取决于您的要求,因此由您决定哪个是正确的。