1

I want to construct a method which returns as a string the class prefix of the module it is operating in.

For example, if I have project with classes named XYZMessage, XYZBusiness, XYZTransaction... I want a function to return the string XYZ.

I have an implementation which uses the name of the appDelegate (The first capital letters except the last) to do this, but I would like a better way. I would hope that Xcode defines a macro with this value or there's a key in the plist or something more concrete. I don't want to #define CLASS_PREFIX @"XYZ" or anything hard-coded.

EDIT: The Why
The situation is I have a server who provides me the type (i.e. which class to construct) along with the information.

{
"type" : "merchant",
"data" : {
    "name" : "Super cool pizza",
    "location" : {
        "lat" : "123.000",
        "lon" : "23.0000"
    }
}

I have a class AXQMerchant which will take this (data) payload as it's initializer (unpack the keys/values, match the types to its properties, build sub-objects, etc.)

What I'm trying to avoid is this structure in my API handler:

NSString* objectType = ...; //server provided
NSString* classToConstruct; //our local type
if ([objectType isEqualToString:@"transaction"]) {
    classToConstruct = @"AXQTransaction";
} else if ([objectType isEqualToString:@"store"]) {
    classToConstruct = @"AXQStore";
    ... //a series of else-if blocks
} else if ([objectType isEqualToString:@"merchant"]) {
    classToConstruct = @"AXQMerchant";
}
id object = [[NSClassFromString(classToConstruct) alloc] initWithPayload:...];
//now do something with object

This section will easily grow unwieldy when my type list is >20 types. What I want to write is:

classToConstruct = [classPrefix() stringByAppendingString:[objectType capitalizedString]];
id object = [[NSClassFromString(classToConstruct) alloc] initWithPayload:...];

For those who are curious; my current implementation is...

str = NSStringFromClass([[UIApplication sharedApplication].delegate class]); //could be [self class], instead...
for (NSUInteger i = 0; i < str.length; i++) {
    unichar c = [str characterAtIndex:i];
    if (c < 'A' || c > 'Z') { //if c is not a capital we're at prefix end (+1 extra)
        return [str substringWithRange:NSMakeRange(0, i - 1)];
    }
}
return nil;

This is dispatch_once()'d so I only calculate it when the app is opened the first time.

Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880
Ryan Dignard
  • 639
  • 1
  • 5
  • 16
  • 1
    What kind of behavior are you looking for if you have multiple classes in the project that have a different prefix? (Like, XYZMessage, XYZBusiness, XYZTransaction, AAAPerson, AAAClass, AAAContact.) I don't think "class prefix" is a well enough defined concept. Class prefixes are totally arbitrary. What are you interested in using this information for? – Itai Ferber Aug 19 '14 at 20:30
  • `isKindOfClass:` is _usually_ sufficient. What exactly are you trying to do? – CrimsonChris Aug 19 '14 at 20:32
  • @CrimsonChris see the Edit section. Basically I want to remove the checks altogether (these types share a common protocol for building them) – Ryan Dignard Aug 19 '14 at 21:03
  • Interesting puzzle, but I vote for the preprocessor definition. Put it in the project settings. – jscs Aug 19 '14 at 21:03
  • @ItaiFerber when you create a new project in Xcode there's an option to put in a generic class prefix; _that's_ the value I'd like to get (other prefixes aren't important). – Ryan Dignard Aug 19 '14 at 22:10
  • I agree with Josh. I'm interested in what this is applicable _for_, though. To what end is this useful? I ask because I'm curious. :) – Itai Ferber Aug 20 '14 at 15:39

2 Answers2

1

The project's class prefix seems to be available to an Xcode template file via the replacement string ___VARIABLE_classPrefix:identifier___, so one possibilty would be to create either a custom .pch or header file template. The header can then expose the prefix as either a macro or an NSString.

Community
  • 1
  • 1
jscs
  • 63,694
  • 13
  • 151
  • 195
0

Use NSStringFromClass to get the class name and then return the first three characters of the string.

NSString *mystr = NSStringFromClass([instance class]);
return [mystr substringToIndex:3];
R3D3vil
  • 681
  • 1
  • 9
  • 22