1

I am implementing this SO post Custom Core Data SectionNameKeyPath : in particular, Martin R's first suggestion of adding a category method to feed my sectionNameKeyPath.

There, they have one persistent attribute called acctPeriod to be used for the sort descriptor, and one category method called periodYear which works on acctPeriod (to be precise, extracts its first 4 characters). However, I have many persistent attributes like acctPeriod, any of which could be chosen by the user for the sort descriptor, and I want to implement the same method on them to feed as sectionNameKeyPath. In other words, I want to pass acctPeriod as an argument to the category method, like periodYear:(NSString*) acctPeriod

Is this possible? How would the code for such a category method and FRC (sectionNameKeyPath) look?

Thanks!

Community
  • 1
  • 1
J Sreedhar
  • 52
  • 8

2 Answers2

3

The "section name key path" is a key path that is applied to each managed object and returns the section name, i.e. the fetched results controller calls [object valueForKeyPath:<sectionNameKeyPath>] for each object when dividing the table into sections.

If the key path is implemented as a (category) method, it has to be a method without arguments, using only the implicit argument self. Therefore I do not see how an additional parameter can be used in that method (unless you work with some global variables).

But if the method to create the section name is exactly identical for all possible attributes (like taking the first four characters of a string in the linked example), you can implement that method as a category on NSString:

@interface NSString (MyAdditions)
- (NSString *)firstFourCharacters;
@end

@implementation NSString (MyAdditions)
- (NSString *) firstFourCharacters {
    if ([self length] <= 4)
        return self;
    return [self substringToIndex:4];
}
@end

Then you dynamically create a section name key path of the form <yourAttribute>.firstFourCharacters with

sectionNameKeyPath:[NSString stringWithFormat:@"%@.firstFourCharacters", yourAttribute]

in the fetched results controller, where yourAttribute is the persistent attribute that is currently used for sorting the table view.

The Key-Value Coding machinery will (for each managed object) first apply <yourAttribute> to the object, and then apply firstFourCharacters to the result.

Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • Thanks, I shall try it. Also, I did not know that dot syntax works for methods too (and not just for properties). – J Sreedhar Jan 07 '14 at 10:06
  • I am a bit confused on another point. In the linked example (where I don't have sufficient rep to comment), is it not necessary to sandwich the line where the persistent attribute is accessed, between, say, willAccessValueForKey:@"acctPeriod" and didAccessValueForKey:@"acctPeriod"? Or is that needed only when we write custom getter/setter for modeled properties? – J Sreedhar Jan 07 '14 at 10:41
  • @JSreedhar: In the linked example `sectionNameKeyPath` is just a method that accesses `self.acctPeriod`. - If you implement the section name key path as a *transient attribute* (as suggested at the end of the answer), you would need will/didAccessValueForKey and the primitive accessor to avoid infinite recursion. See http://stackoverflow.com/a/20249349/1187415 for an example. The transient property has the advantage that the section name is cached for each object instead of being recalculated frequently. – Martin R Jan 07 '14 at 10:56
  • thanks. Another thing, do you agree with Dan Shelly's recommendation against using a transient property as the sectionNameKeyPath - he says it will result in fault-firing. However, if Apple's example code uses it, I guess it is ok. – J Sreedhar Jan 07 '14 at 11:48
  • @JSreedhar: I did not investigate that, so I cannot comment on it. – Martin R Jan 07 '14 at 12:00
  • while studying the example at stackoverflow.com/a/20249349/1187415 you suggested, I have another doubt. Should we sandwich this line [self setPrimitiveValue:tmp forKey:@"sectionIdentifier"]; between willChangeValueForKey and didChangeValueForKey KVC methods? – J Sreedhar Feb 21 '14 at 11:35
  • @JSreedhar: I do not think so. That is the *getter* method for the "sectionIdentier" property, so posting change notifications looks wrong to me. There are also code examples in the Core Data Programming Guide that are similar to this one. – Martin R Feb 21 '14 at 12:01
  • Thanks, so the sandwiching is for avoiding infinite recursion (in the getter or setter) as you wrote earlier. One more doubt: suppose I implement the section name key path as a transient attribute called lastNameInitial, say. In my custom getter for lastNameInitial, I understand I must sandwich the primitive accessor to lastNameInitial, as you do in your example. Now suppose in this same custom getter that lastNameInitial, if nil, is calculated from another attribute called lastName. Then there is no need to sandwich the call to lastName, right? I can just invoke [self lastName]... – J Sreedhar Feb 21 '14 at 21:13
0

As was pointed out, this should be trivial:

@interface Transaction (AdditionalMethods)
-(NSString*)sectionStringForPeriod:(NSNumber*)acctPeriod;
@end
Mundi
  • 79,884
  • 17
  • 117
  • 140
  • I am invoking this method to specify the sectionNameKeyPath: in NSFetchedResultsController, and I would like its argument to be the persistent attribute that is currently used for sorting the table view. @MartinR says it cannot be done, unfortunately. – J Sreedhar Jan 07 '14 at 10:25