iosswiftcore-datacorestore

CoreStore insert array as relationship objects while updating data model


I have next code to update my workout:

func addMuscleGroups(muscleGroups: [MusclEntity], toWorkout: WorkoutEntity, completion: @escaping (ResultInfo<WorkoutEntity>) -> Void) {

        CoreStore.perform(
            asynchronous: { (transaction) -> WorkoutEntity? in
                let workout = transaction.edit(toWorkout)!

                for muscle in muscleGroups {
                    let editedMuscle = transaction.edit(muscle)!
                    workout.muscles?.insert(editedMuscle)
                }

                return workout
        },

            success: { (transactionWorkout) in // here we have muscles for transactionWorkout

                guard let unwrappedTransactionWorkout = transactionWorkout else {
                    return
                }

                let workout = CoreStore.fetchExisting(unwrappedTransactionWorkout) // there are no muscles objects

                guard let unwrappedWorkout = workout else {
                    return
                }

                completion(.data(unwrappedWorkout))
        },
            failure: { (error) in
                completion(.error(StackedError.internalFetchingDataError(message: error.debugDescription)))
        })

    }

But as I see I have inserted muscles while perform asynchronous block, but then when I do fetchExisting there are no muscles which were added in asynchronous block.

EDITED:

As I figured out there is missing relationships inverse in workout.muscles, now I added it and looks like CoreStore update workout entity correctly.

But now I have another problem if I call function few times:

  1. first call

addMuscleGroups([1, 2, 3, 4, 5]...) print(unwrappedWorkout.muscles) [1, 2, 3, 4, 5]

  1. second call addMuscleGroups([1, 2, 3, 4, 5, 6, 7]...)

    print(unwrappedWorkout.muscles) [6, 7]

(to simplify example I used 1, 2, 3, 4, 5, 6, 7 numbers), but there are MusclEntity objects actually

so as a result of second call of addMuscleGroups function unwrappedWorkout.muscles has two muscle objects instead of 7.

I've added short video:

https://www.screencast.com/t/63cRGKpk0Q


Solution

  • I answered your question at CoreStore's github as well.

    This would be the general behavior of NSManagedObjects with regards to to-many properties.

    First, as you have found out, the inverse relationship is important.

    Second, Set is not recommended for unordered @NSManaged properties. Using NSSet is recommended instead. In that note, to-many relationships are treated as immutable, which means you cannot insert objects directly to the NSSet value. There are two ways you can insert values.

    1. Assigning a new NSSet directly:
    var muscles = (workout.muscles as! Set<MusclEntity>?) ?? []
    muscles.insert(newMuscle)
    workout.muscles = muscles as NSSet
    
    1. Use KVO mutable accessors (creates an NSMutableSet proxy for you):
    workout.mutableSetValueForKey(#keyPath(WorkoutEntity.muscles)) 
        .addObject(newMuscle)