首页 文章

Swift CoreData在UITableViews之间传递选定的行值

提问于
浏览
2

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

我的CoreData实体的结构是Workouts Entity和Exercises Entity之间的多对多关系 . (我会发布一些图片,但我没有足够高的代表!)

我想要实现的是一个简单的设置菜单,用户可以在其中创建一个Workout,然后通过在顶部使用带有navigationController的tableViews在该Workout中创建一系列练习(就像iOS设置菜单一样)

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

1)如何确保当用户添加练习时将其分配给他们从之前的tableView中选择的正确锻炼?

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

我已经围绕这个主题做了很多阅读,并认为答案与从锻炼到练习的segue有关(通过使用委托将exerciseName传递给Exercises tableView?然后使用NSPredicate来限制练习显示到选择锻炼?

我不是百分百肯定,但任何帮助将不胜感激!

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

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
    }
}

这是我的Exercises 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.
}

}

1 回答

  • 0

    塞尔很接近 . 您的ExcerciseMasterTableViewController没有名为workout的属性 . 你需要添加

    var workout:Workout!
    

    到你的ExcerciseMasterTableViewController .

    你的seque看起来应该更像这样

    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
    
    • 为了确保只显示正确的练习,在viewDidLoad中将练习数组设置为workout.exercises . 请注意,workout.exercises应该是一个NSSet,因此您需要将您的集转换为数组,或者让练习的类型为NSSet而不是数组 .

相关问题