Transformable Attributes in Core Data

The way I tend to use transformable attributes in Core Data is to just make use of the standard NSValueTransformer that gets used to encode/decode any object that conforms to the NSCoding Protocol, then in my NSManagedObject subclass, cast this to the type it’s expected to be (I use mogenerator to generate the subclasses by the way):

name it with suffix Object since it will have type id

name it with suffix Object since it will have type id

  @interface MyObject : _MyObject
  
  @property (nonatomic, strong) NSDictionary *metadata;
  
  @end

And then in the .m file, the accessors

  @implementation MyObject
  
  + (NSSet*)keyPathsForValuesAffectingMetadata
  {
      return [NSSet setWithObjects:@"metadataObject", nil];
  }
  
  - (void)setMetadata:(NSDictionary *)metadata
  {
      [self willChangeValueForKey:@"metadata"];
      self.metadataObject = metadata;
      [self didChangeValueForKey:@"metadata"];
  }
  
  - (NSDictionary*)metadata
  {
      [self willAccessValueForKey:@"metadata"];
      NSDictionary *metadata = (NSDictionary*)self.metadataObject;
      [self didAccessValueForKey:@"metadata"];
      return metadata;
  }
  
  // the rest of your implementation here...
  @end

Summary: Saving your custom object classes in CoreData is pretty straightforward when supporting the NSCoding protocol. It’s then easy to ensure typing by declaring properties that just wrap these Core Data attributes. This post is basically something of a recipe so I can remind myself later.

UPDATE:  See this post.  You can actually get mogenerator to set the data type for you and you don’t have to write these accessors at all.

Notes on NSNotificationCenter

This blog is sometimes about content from my head, but also a place to just keep interesting reference info.

I was debugging a crash that provided very little info about my app’s code, but threw an exception when calling

[UIViewController didPurgeMemoryForReason:]

In the end I suspect it was because someone was calling

[[NSNotificationCenter defaultCenter] removeObserver: self];

outside of a dealloc method, which ends up accidentally deregistering for the didReceiveMemoryWarning notification.

Anyway, looking at this post, in the comments, I learned something new about a block-based API for the notification center where you can provide the notification’s handler right as you add the observer. What’s more is how you remove the observer.

I quote shusta from the comments:

NSNotificationCenter provides -addObserverForName:object:queue:usingBlock: which, unlike the other addObserver methods, returns an actual observer. To stop observing, you call -removeObserver: with that returned object instead of self. This isn’t as weird as it might sound.

To set up the observer, you would call

id keyboardWillShowObserver = [[NSNotificationCenter defaultCenter] 
    addObserverForName:UIKeyboardWillShowNotification
                object:nil
                 queue:nil
            usingBlock:^(NSNotification *notification) {

// react to notification
}];

This tells the notification center to call the provided block upon UIKeyboardWillShowNotification, and returns to you keyboardWillShowObserver. (NSNotificationObserver retains keyboardWillShowObserver. You probably don’t need to.)

To stop observing UIKeyboardWillShowNotification, you would call

[[NSNotificationCenter defaultCenter] removeObserver:keyboardWillShowObserver];
keyboardWillShowObserver = nil;

So now you don’t have to worry about side effects such as superclass observers, since you’re not removing your entire object as an observer.

This isn’t all sparkly pixie dust, though. Block-based observers come with their own problems, which is that blocks probably retain self. So if you want to remove the observer in -dealloc, you’ll have a problem because -dealloc will not be called. (A retain cycle)

The way to solve this is to create a block variable (for primitives), or a weak pointer to self and use that instead.

__weak MyClass *weakself = self;
/***/ ^(NSNotification *notification) {
    [weakself->array removeAllObjects];
    [weakself showKeyboardLabel];
}];

The block won’t retain weakself, and you can -removeObserver: in -dealloc, no problem.

Of course, if you’re going to removing the observer sooner, it’s probably unnecessary. Regardless, the block based method avoids the pitfall described in this article by removing observers very precisely instead of indiscriminately.

Quick Reference – Load a UIView created in a NIB

I have a few situations where I would like to visually lay out some UIView and writing code just to move something over by a pixel, no back two, no actually the original was fine, etc. is just a pain. I like WYSIWYG. So from time to time I’d like to load a UIView from a NIB because sometimes you need more than one instance of that UIView in your view hierarchy.

It’s dead easy. For a subclass of UIView called MyCustomView, you just need to do the following in Interface Builder:

* Create a NIB file for your view, and lay it all out. Create Outlets as necessary.
* Set the File’s owner in IB to your UIView subclass’ name
* Set the class type of your NIB’s view (much like a view controller’s view property) to your subclass name.
* Any outlets should be relative to the view, NOT the file’s owner

Then in code:

– Implement a method something like:

- (id)initWithNib
{
    // where MyCustomView is the name of your nib
    UINib *nib = [UINib nibWithNibName:@"MyCustomView" bundle:[NSBundle mainBundle]];
    self = [[nib instantiateWithOwner:self options:nil] objectAtIndex:0];
    return self;
}
- (id)initWithCoder:(NSCoder*)aDecoder
{
    self = [super initWithCoder: aDecoder];
    if(self){
        // do your initialization tasks here
    }
    return self;
}
- (void)awakeFromNib
{
   // then do any other initialization tasks here. Possibly interesting to you https://horseshoe7.wordpress.com/2013/02/07/xcode-using-ib-to-configure-custom-classes/
}

Bam! It’s that easy.

Cocoa Bindings – The Easy way for an NSView subclass to update itself

So, say you have a NSView subclass in your Interface that is purely data-driven (i.e. it’s not an interactive component, it merely provides a graphical representation of an underlying data model).  It would be nice to keep this view updated to the current state of your data model automatically without writing too much glue code.  Here comes Cocoa Bindings!

Now, as Cocoa Bindings and Core Data are both powerful technologies, it’s hard to write a tutorial that doesn’t start from the beginning.  So, this is not a tutorial (per se), nor am I starting from the beginning.  Here is the start situation:

– You are using Core Data in your app, and don’t have any issues like I have described in blog posts preceding these (i.e. pretty much every attribute is immutable (i.e. you use myAttribute = newAttribute to register any kind of change on my attribute),

– You are familiar with NSArrayControllers and know a bit about basic Cocoa Bindings.

So?  How to get things working?  The trick is to make use of the CoreData framework’s automatically generated NSNotifications, namely this one:

NSManagedObjectContextObjectsDidChangeNotification, which you can use to determine if any of these objects are of any interest to your NSView subclass, and if yes, tell your class to redraw itself.

How does this all begin?  It begins with the bindings.   In an app I’m working on, I have sort of objects that have a specific duration, and this duration is derived from the duration of child objects.  Imagine the parent object as a day, and the child objects as tasks, and those children have children of subtasks, who have a duration.  Get it ?  A sort of pseudo equation for the entire duration would be:

totalDuration = [day valueForKeyPath: @"tasks.@sum.subtasks.@sum.duration"];

(although in Cocoa this isn’t allowed, but perhaps you get the shorthand.  It sums all durations in the sub elements)

Or said another way, a Day has many Task object who each have many Subtask objects, and a subtask has a duration property that you are editing elsewhere in your GUI.

So, how do we get this working? Here would be a portion of your NSView subclass’ .m file. The .h is a subclass of NSView and has:

@property (nonatomic, strong) Day *day;

static int DayObservingContext; // see here for an explanation of KVO contexts http://stackoverflow.com/a/11917449/421797

+ (void)initialize
{
    [self exposeBinding:@"day"];
}

- (void)bind:(NSString *)binding toObject:(id)observable withKeyPath:(NSString *)keyPath options:(NSDictionary *)options
{
    if ([binding isEqualToString:@"day"]) {
        [observable addObserver:self forKeyPath:@"selection" options:0 context:&DayObservingContext];
        _arrayController = (NSArrayController*)observable;
    }
    else{
        [super bind:binding toObject:observable withKeyPath:keyPath options:options];
    }
}

- (void)unbind:(NSString *)binding
{
    if ([binding isEqualToString:@"day"]) {

        [_arrayController removeObserver:self forKeyPath:@"selection"];
        _arrayController = nil;
        self.day = nil;
    }
    else{
        [super unbind: binding];
    }
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if (context == &DayObservingContext) {

        id selection = _arrayController.arrangedObjects[_arrayController.selectionIndex];

        if (!selection && [selection isKindOfClass:[Day class]] == NO) {
            [NSException raise:NSInternalInconsistencyException format:@"This object should be bound to Day Objects!"];
        }

        self.day = (Day*)selection;

        [self setNeedsDisplayInRect:[self visibleRect]];
    }
    else
    {
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }
}

- (Day*)day { return _day;}
- (void)setDay:(Day *)day
{
    if (day == _day) {
        return;
    }

    if (_day) {
        [[NSNotificationCenter defaultCenter] removeObserver: self
                                                        name: NSManagedObjectContextObjectsDidChangeNotification
                                                      object: _day.managedObjectContext];
    }

    _day = day;

    if (_day) {
        [[NSNotificationCenter defaultCenter] addObserver: self
                                                 selector: @selector(contextChanged:)
                                                     name: NSManagedObjectContextObjectsDidChangeNotification
                                                   object: _day.managedObjectContext];
    }

    [self setNeedsDisplayInRect:[self visibleRect]];
}

- (void)contextChanged:(NSNotification*)notification
{
    // Get a set containing ALL objects which have been changed
    NSSet* insertedObjects = (NSSet*)[[notification userInfo] objectForKey:NSInsertedObjectsKey];
    NSSet* updatedObjects = (NSSet*)[[notification userInfo] objectForKey:NSUpdatedObjectsKey];
    NSSet* deletedObjects = (NSSet*)[[notification userInfo] objectForKey:NSDeletedObjectsKey];

    NSSet *changedObjects = [NSSet set];

    if (insertedObjects) changedObjects = [changedObjects setByAddingObjectsFromSet:insertedObjects];
    if (updatedObjects) changedObjects = [changedObjects setByAddingObjectsFromSet:updatedObjects];
    if (deletedObjects) changedObjects = [changedObjects setByAddingObjectsFromSet: deletedObjects];

    // go through all objects, find type, and see if they have a relationship that is a part of this Day
    BOOL shouldRefresh = NO;

    for (NSManagedObject *object in changedObjects) {

        if ([object isKindOfClass:[Day class]]) {
            if (object == _day) {
                shouldRefresh = YES;
                break;
            }
        }
        if ([object isKindOfClass:[Task class]]) {
            if ([(SCRecipeStep*)object day] == _day) {
                shouldRefresh = YES;
                break;
            }
        }
        if ([object isKindOfClass:[Subtask class]]) {  // it is a subtask that has the .duration property which is edited elsewhere in your GUI
            if ([[(Subtask*)object task] day] == _day) {
                shouldRefresh = YES;
                break;
            }
        }
    }

    if (shouldRefresh) {
        [self setNeedsDisplayInRect:[self visibleRect]];
    }

}

- (void)drawRect:(NSRect)dirtyRect
{
   // your custom code here that knows how to draw a Day object
}

Now, all you have to do in Interface Builder is create an outlet to the NSArrayController that is managing your Day objects (i.e. _arrayController.arrangedObjects will be a collection of Day objects), and of course an outlet to your “DayView” subclass.

then, you just add the binding in your loadView method:

- (void)loadView
{
    [super loadView];

    [self.dayView bind: @"day"
              toObject: self.daysArrayController
           withKeyPath: @"selection" /* due to the way we overrode bind: we could specify nil here */
               options: nil];
}

And so any time your currently selected day changes, it will know how to change the currently drawn day, and because we are using NSNotificationCenter to be informed of any changes to the managedObjectContext, and have code that checks if any of these changes are relevant to our view, the DayView will update itself accordingly.

I spent ages trying to get the Day object’s children to notify the parent if any of its properties change (explained in the KVO documentation, “Registering Dependent Keys, to-many relationships), but found it to be an insane amount of code required and thought “there must be an easier way than this”, I read that one sentence in this section of the documentation that states:

“2. If you’re using Core Data, you can register the parent with the application’s notification center as an observer of its managed object context. The parentshould respond to relevant change notifications posted by the children in a manner similar to that for key-value observing.”

This is what this post attempts to clarify. I hope it helps. I can’t believe how much time I’ve spent trying to get something that’s meant to be simple, working.

PS – THIS POST was very helpful for getting the right approach

Core Data, KVO, Bindings… Tips and Tricks for the Layman

So, as my blog has indicated, I have been trying to tackle many advanced technologies all at once, and I’m sure I will look back on this blog one day and shake my head at the silliness of the issues I’m having currently, but well, you can’t make an omelette without breaking some eggs.

I really wish I had a mentor, some guru, someone where I could just ask “am I on the right track?  Is this the right approach?”  I don’t need much supervision or direction, but just a point in the right direction would be IMMENSELY helpful.   So, without that, taking the brute force approach, I thought I’d post a few things that you, as the beginner may want to keep in mind until you are more advanced yourself.

This list will be periodically updated.

* KVO and Bindings are deep and powerful technologies (as is Core Data).  Apple has tried to hide a lot of this from you so you can get up and running quickly.  That said, it’s still a steep learning curve and it’s difficult to just ‘jump into’ KVO, Bindings, and Core Data all at once.

* Errors and exceptions relating to KVO, CoreData, and Bindings are difficult to debug as the console output of such errors is seldom descriptive enough so to help you track down the problem.

* Core Data entities should have properties that are ‘one thing’, and not a compound property.  (else you have to write a bunch of custom code)  i.e., if you for example use a Value Transformer to restore a custom object, changes to those objects’ properties will not mark the Core Data entity as dirty, and thus any changes you make to that will not get saved.  (unless you are setting these properties after just having added that object to the array, because by definition that object will be dirty.)  In slightly more programmer speak, your custom properties (transformable attributes) should be IMMUTABLE, meaning, only changes are registered if you make a call that’s something like

myEntity.myCustomProperty = someValue

NOT,

myEntity.myCustomProperty.maxValue = someMaxValue

* All the tutorials and intros to Cocoa Bindings tout it as this magic thing that will result in you never having to write glue code again!  Wrong.  F•cking wrong wrong wrong.  (At least until you get your head around it!!)  I’m actually quite surprised at how terrible some of Apple’s documentation can be on the topic of KVO, Core Data, and Bindings.  iOS Developers (which I am, 2 weeks into Cocoa…) won’t have to worry as most of this stuff doesn’t work on iOS.  For example, the easiest way to make a NSView subclass that is backed by a Core Data model.  I spent AGES trying to figure this out the KVO way, whereas the solution’s approach was briefly mentioned in ONE sentence in a KVO programmer’s guide.   (will write a post about this soon)

False Assumptions I have made along the way and what WASN’T true:

– changes to an object in a to-many relationship will notify its parent.  (i.e. I change an Employee’s name, the Department will not receive a KVO notification about this.  Only if you add/remove employees, will the Department receive an update about this.  This isn’t such an issue, but what if your object was a TimeLine with many TimeSteps, who each have a duration property?  The Timeline won’t update.  Yes yes, this is all in the KVO Documentation, and implementing such updates are non-trivial)

KVO – Observing any change in Object state

I have a situation where it would be really handy to bind an entire object (and its encapsulated states) to a view.  As this view displays itself depending on the all the different values of its member variables, it could be very tedious to set all this up, property by property, when all a view object really needs to know is when its underlying data model has changed and it should therefore redraw itself.

So, I thought I would post my solution to the problem.  Basically the approach is to create a property that you can observe (call it observableSelf), and will send change notifications any time any other property of that object changes.  Other than the fact that you have to observe some extra property, I find the solution kind of elegant.

meh.  Here’s the code.  It speaks for itself.

//
//  KVOUpdatingObject.h
//
//  Created by Stephen O'Connor on 1/28/13.
//  Copyright (c) 2013 Stephen O'Connor. All rights reserved.

#import <Foundation/Foundation.h>

typedef NSUInteger ChangeMonitor;  // I put this here because it seemed better to
                                   //define an appropriate type than int, although it doesn't really matter.

@interface KVObservableObject : NSObject

@property (nonatomic, assign) ChangeMonitor observableSelf; // basically you observe this

@end

and now the .m

//  KVOUpdatingObject.m
//  CocoaBindingsTesting
//
//  Created by Stephen O'Connor on 1/28/13.
//  Copyright (c) 2013 Stephen O'Connor. All rights reserved.
//

#import "KVOUpdatingObject.h"
#import <objc/runtime.h> // very important to import this!

@implementation KVOUpdatingObject

+(NSSet*)keyPathsForValuesAffectingValueForKey:(NSString*)key {

    NSSet *keyPaths = [super keyPathsForValuesAffectingValueForKey:key];

    if ([key isEqualToString:@"observableSelf"]) {
        NSMutableArray *keys = [NSMutableArray array];
        unsigned int count;
        objc_property_t *properties = class_copyPropertyList([self class], &count);  // see imports above!
        for (size_t i = 0; i < count; ++i) {
            NSString *property = [NSString stringWithCString:property_getName(properties[i])
                                                    encoding:NSASCIIStringEncoding];

            if ([property isEqualToString: @"observableSelf"] == NO) {
                [keys addObject: property];
            }
        }
        free(properties);

        keyPaths = [keyPaths setByAddingObjectsFromArray: keys];
    }

    return keyPaths;
}

@end

KVC is easy to understand. KVO starts to get a little more complicated, and Cocoa Bindings is the next step up. I’ve been having trouble with Bindings and CoreData only because I haven’t had very much time with it. It’s amazing what Apple hides from the Developer and yet still enables the Developer to do wonderful things. But slowly the Developer needs to know more and more and go deeper. I’m still on my way down that road.

This is easily tested to give you some safe feeling. I created a subclass of the above, gave it a NSNumber property and an NSArray property (someNumber, and someObjects respectively). Here’s the test case:

@implementation CocoaBindingsTestingTests

- (void)setUp
{
    [super setUp];

    // Set-up code here.
    _testObject = [KVOTesting new];   // the subclass of KVObservableObject

    _observationCount = 0;  // some instance variable on this test case

    [_testObject addObserver:self forKeyPath:@"observableSelf"
                     options:NSKeyValueObservingOptionNew
                     context:nil];
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if ([keyPath isEqualToString:@"observableSelf"]) {

        NSLog(@"Object Changed!");
        _observationCount++;
    }
    else
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}

- (void)tearDown
{
    // Tear-down code here.
    [super tearDown];
}

- (void)testExample
{
    [_testObject setValue:@4 forKey:@"someNumber"];  
    _testObject.someNumber = @4; 
    _testObject.someObjects = @[@2, @3, @4]; 
    [_testObject setSomeNumber: @5];

    STAssertTrue(_observationCount == 4, @"Should have reported 4 changes");
}

@end

Now, the only remaining issue for such a use case is what if this object is a member of another object, and this object's properties change, but not the object itself.  How would that 'parent' know?

Cocoa Bindings Tips – Array Controllers

Working with Array Controllers I’ve learned a few things that I’d like to write down.

1)  You can subclass and override an NSArrayController’s awakeFromNib file to set your own sortDescriptors.  When you do this, you can around the issue of a NSTableView not being sorted until you click on a column header.

2)  Content, Content Objects, Content Values explained:

Binding a NSPopUpCell to a collection of objects can be tricky.  I had the case where I have enumerated values, so ultimately we are talking about setting a numeric value for a property in the data model, but want to display user friendly text.  One would think “bind the number then use a one-way value transformer to convert those enums to strings.”  Somehow this didn’t work like I’d hoped.  In the end I used an array of NSDictionary objects and did the bindings as follows:

Content binds an array controller’s arranged objects.  But each of these will be an NSDictionary.  (Don’t forget in the NSArrayController’s inspector in Interface Builder, so specify that objects for that controller are of type NSDictionary, and specify the keys you use in those dictionaries in that same pane)

Content Objects – this is like saying, from the Content, is there a specific property that you are trying to bind to your data model?  What you set here is the object that will be selected.

Content Values – what would you like to display?

Selected Object – what are you binding the selected object to?

So, in this case I bound content to an array of NSDictionaries, the Content Object was that dictionary with key “numberRepresentation”, and the contentValue was “textRepresentation”, so that I would be displaying text, but assigning a NSNumber – the selected contentObject – to the parameter on the bound data model (as specified by the selected Object binding).

This seems pretty trivial, but was very helpful getting my head around Core Bindings.  It’s a powerful technology, but it’s unforgiving as it isn’t easy to debug, and it doesn’t provide much in terms of debug info / what went wrong.  The error messages are often not that helpful.