【问题标题】:Swift CoreData passing selected row value between UITableViewsSwift CoreData 在 UITableViews 之间传递选定的行值
【发布时间】:2015-02-21 21:13:12
【问题描述】:

我是 Swift 和编码的新手,才大约一个月,我正在尝试构建一些简单的 UItableViews 来设置一些 CoreData 属性。

我的 CoreData 实体的结构是锻炼实体和练习实体之间的多对多关系。 (我会发布一些图片,但我没有足够高的代表!)

我想要实现的是一个简单的设置菜单,用户可以在其中创建一个锻炼,然后使用顶部带有导航控制器的 tableViews 在该锻炼中创建一系列练习(就像 iOS 设置菜单一样)

目前我已经让它工作了,你可以添加一些锻炼,然后你可以去 Excercises tableView 添加一些锻炼。但是我无法做两件事:

1) 我如何确保当用户添加一个练习时,它被分配到他们从上一个 tableView 中选择的正确锻炼?

2) 如何确保锻炼表视图仅显示他们选择的锻炼锻炼?

我已经围绕该主题进行了大量阅读,并认为答案与从锻炼到练习的转接有关(通过使用委托将锻炼名称传递给练习表视图?然后使用 NSPredicate 来限制显示给所选锻炼的练习?

我不是 100% 确定,但我们将不胜感激任何帮助!

这是从锻炼到锻炼的代码:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
    if segue.identifier == "excerciseMaster" {
        let ExcerciseMasterTableViewController = segue.destinationViewController as UIViewController
        let indexPath = tableView.indexPathForSelectedRow()!
        let workout = workouts[indexPath.row]
        let destinationTitle = workout.workoutName
        ExcerciseMasterTableViewController.title = destinationTitle
    }
}

这是我的练习 tableViewController 的代码:

import UIKit
import CoreData

class ExcerciseMasterTableViewController: UITableViewController {

// Create an empty array of Excercises
var excercises = [Excercises]()

// Retreive the managedObjectContext from AppDelegate
let managedObjectContext = (UIApplication.sharedApplication().delegate as AppDelegate).managedObjectContext

override func viewDidLoad() {
    super.viewDidLoad()

    // Use optional binding to confirm the managedObjectContext
    if let moc = self.managedObjectContext {
    }

    fetchExcercises()
}

func fetchExcercises() {
    let fetchRequest = NSFetchRequest(entityName: "Excercises")

    // Create a sort descriptor object that sorts on the "excerciseName"
    // property of the Core Data object
    let sortDescriptor = NSSortDescriptor(key: "excerciseName", ascending: true)

    // Set the list of sort descriptors in the fetch request,
    // so it includes the sort descriptor
    fetchRequest.sortDescriptors = [sortDescriptor]

    if let fetchResults = managedObjectContext!.executeFetchRequest(fetchRequest, error: nil) as? [Excercises] {
        excercises = fetchResults
    }
}

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    // How many rows are there in this section?
    // There's only 1 section, and it has a number of rows
    // equal to the number of excercises, so return the count
    return excercises.count
}

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = self.tableView.dequeueReusableCellWithIdentifier("Excercise Cell", forIndexPath: indexPath) as UITableViewCell

    // Get the Excercises for this index
    let excercise = excercises[indexPath.row]

    // Set the title of the cell to be the title of the excercise
    cell.textLabel!.text = excercise.excerciseName
    cell.detailTextLabel!.text = "\(excercise.sets)x\(excercise.reps)"
    cell.accessoryType = UITableViewCellAccessoryType.DisclosureIndicator
    return cell
}

override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
    if(editingStyle == .Delete ) {
        // Find the Excercise object the user is trying to delete
        let excerciseToDelete = excercises[indexPath.row]

        // Delete it from the managedObjectContext
        managedObjectContext?.deleteObject(excerciseToDelete)

        // Refresh the table view to indicate that it's deleted
        self.fetchExcercises()

        // Tell the table view to animate out that row
        tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
        save()
    }
}

// MARK: UITableViewDelegate
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    let excercise = excercises[indexPath.row]
}

let addExcerciseAlertViewTag = 0
let addExcerciseTextAlertViewTag = 1


@IBAction func addExcerciseButton(sender: AnyObject) {
    var namePrompt = UIAlertController(title: "Add Excercise",
        message: "Enter Name",
        preferredStyle: .Alert)

    var excerciseNameTextField: UITextField?
    namePrompt.addTextFieldWithConfigurationHandler {
        (textField) -> Void in
        excerciseNameTextField = textField
        textField.placeholder = "Title"
    }

    namePrompt.addAction(UIAlertAction(title: "Ok",
        style: .Default,
        handler: { (action) -> Void in
            if let textField = excerciseNameTextField {
                self.saveNewItem(textField.text, workoutName: "Workout A")
            }
    }))

    self.presentViewController(namePrompt, animated: true, completion: nil)
}

func saveNewItem(excerciseName : String, workoutName: String) {
    // Create the new excercise item
    var newExcercise = Excercises.createExcerciseInManagedObjectContext(self.managedObjectContext!, name: excerciseName)
    println(excerciseName)
    println(workoutName)

    // Update the array containing the table view row data
    self.fetchExcercises()

    // Animate in the new row
    // Use Swift's find() function to figure out the index of the newExcercise
    // after it's been added and sorted in our Excercises array
    if let newExcerciseIndex = find(excercises, newExcercise) {
        // Create an NSIndexPath from the newExcerciseIndex
        let newExcerciseIndexPath = NSIndexPath(forRow: newExcerciseIndex, inSection: 0)
        // Animate in the insertion of this row
        tableView.insertRowsAtIndexPaths([ newExcerciseIndexPath ], withRowAnimation: .Automatic)
        save()
    }
}

func save() {
    var error : NSError?
    if(managedObjectContext!.save(&error) ) {
        println(error?.localizedDescription)
    }
}

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
    if segue.identifier == "excerciseSettings" {
        let ExcerciseSettingsDetailViewController = segue.destinationViewController as UIViewController
        let indexPath = tableView.indexPathForSelectedRow()!
        let excercise = excercises[indexPath.row]
        let destinationTitle = excercise.excerciseName
        ExcerciseSettingsDetailViewController.title = destinationTitle
    }
}

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

}

【问题讨论】:

    标签: ios uitableview swift core-data segue


    【解决方案1】:

    1.segue 已接近。您的 ExcerciseMasterTableViewController 没有名为锻炼的属性。你需要添加

    var workout:Workout!
    

    到您的 ExcerciseMasterTableViewController。

    你的序列应该看起来更像这样

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
    if segue.identifier == "excerciseMaster" {
        let desitnationController = segue.destinationViewController as ExcerciseMasterTableViewController
        let indexPath = tableView.indexPathForSelectedRow()!
        let workout = workouts[indexPath.row]
        destinationController.workout = workout
        let destinationTitle = workout.workoutName
        desitnationController.title = destinationTitle // Usually you would put this in the viewDidLoad method of the destinationController
    }
    

    }

    然后在你的 ExcerciseMasterTableViewController 中添加练习时,只需设置它们的锻炼属性

    workout.exercises = exercises // See note in #2
    
    1. 为确保只显示正确的练习,在 viewDidLoad 中将练习数组设置为锻炼.练习。请注意,锻炼.exercises 应该是一个 NSSet,因此您需要将您的集合转换为数组,或者让练习的类型为 NSSet 而不是数组。

    【讨论】:

    • 感谢您抽出宝贵时间查看此内容。看起来segue很好,但我无法让锻炼.锻炼=锻炼工作。我已将它添加到我创建新练习的下方的 saveNewItem 函数中,但 Xcode 抛出一个错误,指出 Workouts 没有名为练习的成员。这可能是因为它没有识别出锻炼实体和锻炼实体之间的关系吗?我已将锻炼设置为以锻炼为父母,所以它应该可以工作吗?
    • 我也不确定将练习数组设置为锻炼所需的编码 - 我会更改我声明的原始练习变量吗?谢谢
    • 这种关系可能存在于您的数据模型中,但是您是否更新了 Workout 类以具有锻炼属性(反之亦然)?如果您对此不熟悉,最简单的方法是删除您的托管对象类文件并让 Xcode 创建新的。为此,请单击您的 xcdatamodeld,然后单击编辑器>创建 NSManagedObject 子类,然后检查您想要的那些
    • 正如您将在新的 NSManagedObject 子类中看到的,Workout 的练习属性是一个 NSSet。因此,您分配给锻炼的锻炼属性必须是 NSSet。集合不适合显示数据,因此我建议将您的练习属性保留为数组,但是当您准备好保存它时,请创建一个临时 NSSet(有一个 setFromArray 初始化程序)。
    • 抱歉,我刚刚注意到这是一个多对多的关系。当您生成新的 NSManagedObject 子类时,您会看到有两种方法可以在多对多关系中添加和删除对象。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-11
    • 1970-01-01
    • 2019-08-12
    • 2015-03-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多