0

I'm learning Cocoa and following an example in Aaron Hillegass's book (Chapter 32 Core Data Relationships) and can't get it working for my own app.

I have a core data model that consists of a parent object with a to-many relationship to children but mine is an ordered set unlike in the book which is a basic NSMutableSet.

Each of the objects, parent and child, have associated NSArrayControllers and I've developed a document-based app in the Interface Builder with buttons and bindings that add/remove child objects (called perceptrons in my case) from the selected parent (called a layer). That's all working.

Now I want to intercept the add and remove methods so that I can do my own coding things whenever a child is added or removed.

In the Hillegass book he does this by creating the NSManagedObjects subclasses and then implementing addEmployeesObject: and removeEmployeesObject: methods in the code. So that's what I tried.

Here is my child subclass created by the XCode Editor:

#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>

@class Network, Perceptron;

@interface Layer : NSManagedObject

@property (nonatomic, retain) Network *network;
@property (nonatomic, retain) NSOrderedSet *perceptrons;
@end

@interface Layer (CoreDataGeneratedAccessors)

- (void)insertObject:(Perceptron *)value inPerceptronsAtIndex:(NSUInteger)idx;
- (void)removeObjectFromPerceptronsAtIndex:(NSUInteger)idx;
- (void)insertPerceptrons:(NSArray *)value atIndexes:(NSIndexSet *)indexes;
- (void)removePerceptronsAtIndexes:(NSIndexSet *)indexes;
- (void)replaceObjectInPerceptronsAtIndex:(NSUInteger)idx withObject:(Perceptron *)value;
- (void)replacePerceptronsAtIndexes:(NSIndexSet *)indexes withPerceptrons:(NSArray *)values;
- (void)addPerceptronsObject:(Perceptron *)value;
- (void)removePerceptronsObject:(Perceptron *)value;
- (void)addPerceptrons:(NSOrderedSet *)values;
- (void)removePerceptrons:(NSOrderedSet *)values;
@end

And here are the two methods I implemented in Layer.m as per the text book:

- (void)addPerceptronsObject:(Perceptron *)value
{
    NSLog(@"Network '%@' layer %lu is adding perceptron %lu", [[self network] name], [self indexInNetwork], [value indexInLayer]);
    NSSet *s = [NSSet setWithObject:value];
    [self willChangeValueForKey:@"perceptrons"
                withSetMutation:NSKeyValueUnionSetMutation
                   usingObjects:s];
    [[self primitiveValueForKey:@"perceptrons"] addObject:value];
    [self didChangeValueForKey:@"perceptrons"
     withSetMutation:NSKeyValueUnionSetMutation
                  usingObjects:s];
}

- (void)removePerceptronsObject:(Perceptron *)value
{
    NSLog(@"Network '%@' layer %lu is removing perceptron %lu", [[self network] name], [self indexInNetwork], [value indexInLayer]);
    NSSet *s = [NSSet setWithObject:value];
    [self willChangeValueForKey:@"perceptrons"
                withSetMutation:NSKeyValueUnionSetMutation
                   usingObjects:s];
    [[self primitiveValueForKey:@"perceptrons"] removeObject:value];
    [self didChangeValueForKey:@"perceptrons"
               withSetMutation:NSKeyValueUnionSetMutation
                  usingObjects:s];
}

I put NSLogs in so I'm sure they are not getting called - nothing in the console when I add/remove perceptron objects.

What does the ArrayController do when it gets an add: remove: message? Is it sending addObject/removeObject messages directly to the set? Why in the textbook example does it send a message up to the parent object to remove a child? Why is that not happening here? Is there a way to debug this and find out?

thanks

Bill
  • 10,323
  • 10
  • 62
  • 85

1 Answers1

1

Bill,

You are overriding methods that are dynamically generated by Core Data. I suspect your static entries in the lookup table are just being over written. These methods are not the same as the @property methods, which expect to be overridden.

In a bigger sense, why do you want to insert your code here? There are better supported methods designed for your implementation when objects are instantiated. You may wish to examine -awakeFromFetch and -awakeFromInsert.

Andrew

adonoho
  • 4,339
  • 1
  • 18
  • 22
  • Thanks adonoho. I'll look into those other methods. I want to insert code because I have to create additional 'grandchild' objects at the same time as any new perceptron object is added. In the book example they are overriding the method because they want to check to see if an employee object that is about to be removed is the 'manager' of the department object before removing them. – Bill Dec 10 '12 at 15:15
  • Bill, While our friends at BNR are quite knowledgable about things, bear in mind that they view things through two prisms: pedagogy and history. Sometimes those are not the best guides going forward. I recommend that you create your own methods to do your checks and then invoke the Core Data methods as needed. Andrew – adonoho Dec 10 '12 at 16:39
  • OK so awakeFromInsert seems to do the job. I confirmed it's getting called everytime I add a new object. But I also need to intercept any removeObject requests because I need to remove other associated objects from core data when any perceptron object is removed from a layer. What's the equivalent to awakeFromInsert? Also, am I going to be able to maintain undo/redo capabilities if I am adding/removing other objects whenever these messages are called? – Bill Dec 11 '12 at 04:44
  • Bill, Core Data is just an object graph manager. It gives you many access points to that graph. These are extremely general purpose methods. In my apps, when a cascade of deletions is not good enough for graph management, I manage the relationships from outside the objects. `-prepareForDeletion` is the method you're looking for. Your undo/redo concern is independent of where you perform tree management, those are characteristics of the managed object context. Andrew P.S. If you agree, please don't forget to accept this answer. – adonoho Dec 11 '12 at 13:06