2015-02-24 65 views
1

我正在构建一个具有两个CoreData实体 - 锻炼和练习的应用程序。两者之间的关系是多对多的。Swift - 为相关CoreData实体分配值

该应用程序是一对基本的tableViewController,允许您将锻炼(workoutName)添加到锻炼实体,然后将锻炼添加到下一个tableViewController中的锻炼。我正在努力的是如何将每个练习重新分配给它在CoreData中产生的锻炼。基本上,我试图做的是在练习实体中添加newExercise(使用exerciseName变量)时,在Workouts实体中设置workoutName值。

我将workoutName作为锻炼tableViewController的锻炼传递给锻炼tableViewController作为var锻炼。

我也有多对多的关系,并在NSManagedObjects文件中设置为NSSets,但不知道如何使用它们。

下面是行使tableViewController设置:

import UIKit 
import CoreData 

class ExerciseMasterTableViewController: UITableViewController { 

// Declare workout variable 
var workout: Workouts! 

// Create an empty array of Exercises 
var exercises = [Exercises]() 

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

    fetchExercises() 
} 

func fetchExercises() { 
    let fetchRequest = NSFetchRequest(entityName: "Exercises") 

    // Create a sort descriptor object that sorts on the "exerciseName" 
    // property of the Core Data object 
    let sortDescriptor = NSSortDescriptor(key: "exerciseName", 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? [Exercises] { 
     exercises = 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 exercises, so return the count 
    return exercises.count 
} 

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

    // Get the Exercises for this index 
    let exercise = exercises[indexPath.row] 

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

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

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

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

     // 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 exercise = exercises[indexPath.row] 
} 

let addExerciseAlertViewTag = 0 
let addExerciseTextAlertViewTag = 1 


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

    var exerciseNameTextField: UITextField? 
    namePrompt.addTextFieldWithConfigurationHandler { 
     (textField) -> Void in 
     exerciseNameTextField = textField 
     textField.placeholder = "Exercise Name" 
    } 

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

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

func saveNewItem(exerciseName : String, workoutName: String) { 

    // Create the new exercise item 
    var newExercise = Exercises.createExerciseInManagedObjectContext(self.managedObjectContext!, exerciseName: exerciseName, workoutName: workoutName) 

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

    // Animate in the new row 
    // Use Swift's find() function to figure out the index of the newExercise 
    // after it's been added and sorted in our Exercises array 
    if let newExerciseIndex = find(exercises, newExercise) { 
     // Create an NSIndexPath from the newExerciseIndex 
     let newExerciseIndexPath = NSIndexPath(forRow: newExerciseIndex, inSection: 0) 
     // Animate in the insertion of this row 
     tableView.insertRowsAtIndexPaths([ newExerciseIndexPath ], 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 == "exerciseSettings" { 
     let ExerciseSettingsDetailViewController = segue.destinationViewController as UIViewController 
     let indexPath = tableView.indexPathForSelectedRow()! 
     let exercise = exercises[indexPath.row] 
     let destinationTitle = exercise.exerciseName 
     ExerciseSettingsDetailViewController.title = destinationTitle 
    } 
} 

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

} 

而且,这里是我的练习类中定义添加newExercise功能createExerciseInManagedObjectContext:

class func createExerciseInManagedObjectContext(moc: NSManagedObjectContext, exerciseName: String, workoutName: String) -> Exercises { 
    let newExercise = NSEntityDescription.insertNewObjectForEntityForName("Exercises", inManagedObjectContext: moc) as Exercises 

    newExercise.exerciseName = exerciseName 
    self.workouts.addObject(workoutName) 

    return newExercise 
} 

我可以传递将所选锻炼(锻炼名称)的字符串添加到此功能中,但不知道如何通过与锻炼实体的锻炼关系进行设置。

这里是我的练习实体:

import Foundation 
import CoreData 

class Exercises: NSManagedObject { 

@NSManaged var exerciseName: String 
@NSManaged var sets: NSNumber 
@NSManaged var reps: NSNumber 
@NSManaged var repWeight: NSNumber 
@NSManaged var barWeight: NSNumber 
@NSManaged var incrementWeight: NSNumber 
@NSManaged var workouts: NSSet 

class func createExerciseInManagedObjectContext(moc: NSManagedObjectContext, exerciseName: String, workoutName: String) -> Exercises { 
    let newExercise = NSEntityDescription.insertNewObjectForEntityForName("Exercises", inManagedObjectContext: moc) as Exercises 

    newExercise.exerciseName = exerciseName 
    newExercise.workouts.setByAddingObject(workoutName) 

    return newExercise 
} 

} 

这是我的锻炼实体:

import Foundation 
import CoreData 

class Workouts: NSManagedObject { 

@NSManaged var workoutName: String 
@NSManaged var sessions: NSSet 
@NSManaged var exercises: NSSet 

class func createWorkoutInManagedObjectContext(moc: NSManagedObjectContext, workoutName: String) -> Workouts { 
    let newWorkout = NSEntityDescription.insertNewObjectForEntityForName("Workouts", inManagedObjectContext: moc) as Workouts 
    newWorkout.workoutName = workoutName 

    return newWorkout 
} 

} 

回答

2

如果你建立模型正确,这两个实体将通过关系相互引用。您将实体添加到另一个实体,而不是它的名称(这是一个属性)。

核心数据应在您创建NSManagedObject子类时自动生成访问器。有了这些,添加一个新的(或现有的)锻炼,锻炼是非常简单的:

workout.addExercisesObject(newExercise) 

这是假设你的关系被称为exercises

所以最好将实际的锻炼对象传递给函数而不是名称。不要忘记保存。编辑:
为了这个工作,你有两种选择。

您可以让Xcode在Objective-C中生成NSManagedObject子类并自动配置桥接标头。然后你没有任何努力就可以获得访问器。

或者你必须自己实施它们。例如:

@objc(Exercise) 
class Exercise: NSManagedObject { 

@NSManaged var workouts: NSSet 

    func addWorkoutsObject(value: Workout!) { 
     var mutableWorkouts = self.workouts.mutableCopy() as! NSMutableSet 
     mutableWorkouts.addObject(value) 
     self.workouts = mutableWorkouts as NSSet 
    } 
} 

请注意,我没有添加键值编码调用,所以KVO将无法工作,除非您添加它们。

+0

谢谢,这听起来不错。我会添加到我的createExerciseInManagedObjectContext函数或saveNewItem函数? – Sean 2015-02-24 23:09:55

+0

嗯,只是在saveNewItem函数中试过这个,我得到'Workouts'没有名为'addExerciseObject'的成员? – Sean 2015-02-24 23:13:59

+0

这取决于关系名称。只要看看Workout.swift。 – Mundi 2015-02-24 23:26:21