I'm using Mogenerator to build classes for my CoreData, and I love the attribute names that it generates based off CoreData attributes like this in the header file of _TAGUser
:
extern const struct TAGUserAttributes {
__unsafe_unretained NSString *displayName;
__unsafe_unretained NSString *email;
} TAGUserAttributes;
@interface _TAGUser : NSManagedObject
@property (nonatomic, strong) NSString* displayName;
@property (nonatomic, strong) NSString* email;
@end
And this in the implementation file:
const struct TAGUserAttributes TAGUserAttributes = {
.displayName = @"displayName",
.email = @"email",
};
@implementation _TAGUser
@end
Now in the subclass TAGUser
, I added this property to the header file:
@interface TAGUser : _TAGUser {}
@property (strong, nonatomic, readonly) NSString *firstLetterOfDisplayName;
@end
And this to the implementation file:
@implementation TAGUser
- (NSString *)firstLetterOfDisplayName {
return ((self.displayName != nil && self.displayName.length > 0) ?
[self.displayName substringToIndex:1].uppercaseString :
nil);
}
@end
Is there a way I can either extend or add to the struct TAGUserAttributes
so that anywhere else in my code I can call on TAGUserAttributes.firstLetterOfDisplayName
for KVO, section mapping in NSFetchedResultsController
, etc?
One does not simply extend a C struct. You have two possible approaches:
Use NSStringFromSelector(firstLetterOfDisplayName)
for KVO etc. This way you get some compiler safety. The compiler will complain if a selector with given name doesn't exist. However, the selector can exist anywhere in the visible scope, not only in your TagUser
class, to make compiler happy.
Another approach which I have seen here and there is to add another structure, containing a pointer to the original one. I can't figure out better naming now, but I hope it will be understandable:
in .h file:
extern const struct TAGUserAdditionalAttributes {
const struct TAGUserAttributes* base;
__unsafe_unretained NSString * firstLetterOfDisplayName;
} TAGUserAdditionalAttributes;
in .m file:
const struct TAGUserAdditionalAttributes TAGUserAdditionalAttributes = {
.base = &TAGUserAttributes,
.firstLetterOfDisplayName = @"firstLetterOfDisplayName"
};
//then you can use "base" attributes like this:
TAGUserAdditionalAttributes.base->displayName
Unfortunately the pointer syntax makes it quite ugly, but it still works.