2015-02-24 67 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