Thanks to Martin R who pointed me in the right direction I've found the problem in my code.
What I didn't know was the fact that Core Data automatically generates additional primitive properties for you:
For example, given an entity with an attribute firstName, Core Data automatically generates firstName, setFirstName:, primitiveFirstName, and setPrimitiveFirstName:. Core Data does this even for entities represented by NSManagedObject. To suppress compiler warnings when you invoke these methods, you should use the Objective-C 2.0 declared properties feature, as described in “Declaration.”
(Source)
The fact that I wasn't aware of this leaded me to adopt the example code in a wrong way. The way it works for me is now:
@class Location;
@interface Appointment : NSManagedObject
@property (nonatomic, retain) NSDate * primitiveBegin;
@property (nonatomic, retain) NSDate * begin;
@property (nonatomic, retain) NSDate * end;
@property (nonatomic, retain) Location * location;
@property (nonatomic, retain) NSString *sectionIdentifier;
@property (nonatomic, retain) NSString *primitiveSectionIdentifier;
@end
@implementation Appointment
@dynamic primitiveBegin;
@dynamic begin;
@dynamic end;
@dynamic location;
@dynamic primitiveSectionIdentifier;
@dynamic sectionIdentifier;
#pragma mark -
#pragma mark Transient properties
- (NSString *)sectionIdentifier {
// Create and cache the section identifier on demand.
[self willAccessValueForKey:@"sectionIdentifier"];
NSString *tmp = [self primitiveSectionIdentifier];
[self didAccessValueForKey:@"sectionIdentifier"];
if (!tmp) {
/*
Sections are organized by month and year. Create the section identifier as a string representing the number (year * 1000) + month; this way they will be correctly ordered chronologically regardless of the actual name of the month.
*/
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *components = [calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit)
fromDate:[self begin]];
tmp = [NSString stringWithFormat:@"%d", ([components year] * 10000) + [components month] * 100 + [components day]];
[self setPrimitiveSectionIdentifier:tmp];
}
return tmp;
}
#pragma mark -
#pragma mark Begin setter
- (void)setBegin:(NSDate *)begin
{
// If the time stamp changes, the section identifier become invalid.
[self willChangeValueForKey:@"begin"];
[self setPrimitiveBegin:begin];
[self didChangeValueForKey:@"begin"];
[self setPrimitiveSectionIdentifier:nil];
}
#pragma mark -
#pragma mark Key path dependencies
+ (NSSet *)keyPathsForValuesAffectingSectionIdentifier
{
// If the value of timeStamp changes, the section identifier may change as well.
return [NSSet setWithObject:@"begin"];
}
@end