Creating object named after the value of an NSString - is it possible? - objective-c

Is it possible to create an object named after an NSString's value? If so, how?

Try this:
Class theClass = NSClassFromString(someString);
id object = [[theClass alloc] init];

If you mean that the string specifies the class name, then yes it's easy to do this using the NSClassFromString function to lookup the appropriate class "factory" object:
NSString* myClassName = #"NSNumber";
id myNewObject = [[NSClassFromString(myClassName) alloc] init];
// myNewObject is an NSNumber...
The example is contrived, but you get the idea.

Yes:
//In your header
extern NSString *FrobnitzerCalibrationHigh;
extern NSString *FrobnitzerCalibrationMedium;
extern NSString *FrobnitzerCalibrationLow;
//In your implementation
NSString *FrobnitzerCalibrationHigh = #"FrobnitzerCalibrationHigh";
NSString *FrobnitzerCalibrationMedium = #"FrobnitzerCalibrationMedium";
NSString *FrobnitzerCalibrationLow = #"FrobnitzerCalibrationLow";
You can make a couple of macros and put them in your prefix header:
//Semicolons intentionally omitted (see below)
#define DECLARE_STRING_CONSTANT(name) extern NSString *name
#define DEFINE_STRING_CONSTANT(name) NSString *name = ##name
Then use them in your class headers and implementations:
//In your header
DECLARE_STRING_CONSTANT(FrobnitzerCalibrationHigh);
DECLARE_STRING_CONSTANT(FrobnitzerCalibrationMedium);
DECLARE_STRING_CONSTANT(FrobnitzerCalibrationLow);
//In your implementation
DEFINE_STRING_CONSTANT(FrobnitzerCalibrationHigh);
DEFINE_STRING_CONSTANT(FrobnitzerCalibrationMedium);
DEFINE_STRING_CONSTANT(FrobnitzerCalibrationLow);
(The macros omit the semicolons because their usages will supply them. If the macros had semicolons as well, the expansion would be extern NSString *FrobnitzerCalibrationHigh;;—harmless in this case, but it would bug me if I did this, largely because it's not harmless in some other cases.)

Related

Is it a variable or an object? Im very confused

#import <Foundation/Foundation.h>
int main (int argc, char * argv[])
{
#autoreleasepool {
NSString *str = #"Programming is fun";
NSLog (#"%#", str);
}
return 0;
}
In the line
NSString *str = #"Programming is fun";
the constant string object Programming is fun is assigned to the NSString variable str. Its value is then displayed using NSLog .
The NSLog format characters %# can be used to display not just NSString objects, but other objects as well.
/*****/
The previous paragraph was from a book I read, what is really confusing to me is why is he keep using the words variable and objects interchangeably? are objects and varaibles the same thing? so far this is the only confusing part about obj-c to me.
please explain, thank you
An object is an instance of a class. Something that is allocated in memory.
A variable is a name which you use to access something like an object (NSString for example) or a primitive (int for example).
In your case so your object is an instance of NSString, that contains #"Programming is fun":
NSString *str = #"Programming is fun";
The variable to access that object is str.

How to access constant string in runtime using a string which holding its name?

I have some constant strings defined in my #implementation file like:
static NSString * const contentDisplayDateKeyPath = #"content.display_date";
static NSString * const contentIDKeyPath = #"content.id";
Could I get the content of contentDisplayDateKeyPath use a string which holding the variable's name in runtime?
ex:
NSString *constantName = #"contentDisplayDateKeyPath"
[self valueForKey:constantName]
then I'll get content.display_date
Can this be achieved?
I am trying to achieve this by using CFBundleGetDataPointer
CFBundleRef mainBundle = CFBundleGetBundleWithIdentifier(CFBridgingRetain([[NSBundle mainBundle] bundleIdentifier]));
void *stringPointer = CFBundleGetDataPointerForName(mainBundle, CFBridgingRetain(obj));
NSString *string = (__bridge NSString *)stringPointer;
But the stringPointer is always null.
Thanks for help
This should do it for you.
NSString *__autoreleasing *string = (NSString*__autoreleasing*)dlsym(RTLD_DEFAULT, "<name of constant like PKPaymentNetworkVisa>");
NSLog(#"%#", *string);
Use a map with the key as the constant name and the value as the constant value:
static NSDictionary *_constants = #{
#"contentDisplayDateKeyPath" : #"content.display_date",
#"contentIDKeyPath" : #"content.id",
// etc.
};
...
NSString *constantName = #"contentDisplayDateKeyPath";
NSString *constantValue = _constants[constantName];
Another option is to encapsulate this into a singleton object and access your constants through read only properties. Check out What should my Objective-C singleton look like? to see the singleton design pattern.
This question was answered here:
How do I lookup a string constant at runtime in Objective-C?
The solution worked perfectly for me.
You can use CFBundleGetDataPointerForName to lookup a constant's value at runtime
-(NSString *)lookupStringConstant:(NSString *)constantName
{
void ** dataPtr = CFBundleGetDataPointerForName(CFBundleGetMainBundle(), (__bridge CFStringRef)constantName);
return (__bridge NSString *)(dataPtr ? *dataPtr : nil);
}

Are strings defined as constants not NSStrings?

I have a constant defined as:
#define BEGIN_IMPORT_STRING #"Importing Hands!";
But I get an error when I try to concat with:
NSString *updateStr = [NSString stringWithFormat:#"%#%#", BEGIN_IMPORT_STRING, #" - Reading "];
This doesn't happen if I replace it with a string literal
NSString *updateStr = [NSString stringWithFormat:#"%#%#", #"foo", #" - Reading "];
Or a local string
NSString *temp = #"foo";
NSString *updateStr = [NSString stringWithFormat:#"%#%#", temp, #" - Reading "];
You need to remove the semicolon from your #define:
#define BEGIN_IMPORT_STRING #"Importing Hands!"
To the compiler, the resulting line looks like this:
NSString *updateStr = [NSString stringWithFormat:#"Importing Hands!";, #" - Reading "];
Replace
#define BEGIN_IMPORT_STRING #"Importing Hands!";
with
#define BEGIN_IMPORT_STRING #"Importing Hands!"
This is because compiler in your case replaces all occurrences of BEGIN_IMPORT_STRING with #"Importing Hands!";
Aside from the accepted answer (remove semicolon), note that:
#"Foo" is an NSString. You can even send it a message.
#define FOO #"Foo" is a preprocessor macro, not a constant. It's a typing shortcut.
Though macros aren't an uncommon way to avoid retyping the same string, they're an unfortunate holdover. Essentially, they're playing games that aren't necessary anymore.
For repeated strings, I prefer:
static NSString *const Foo = #"Foo;
The const portion of this definition ensures that the pointer is locked down, so that Foo can't be made to point to a different object.
The static portion restricts the scope to the file. If you want to access it from other files, remove the static and add the following declaration to your header file:
extern NSString *const Foo;
Should you be using
NSLocalizedString(#"Importing Hands!", #"Message shown when importing of hands starts");
?
I put it as an answer because this looks like something you would not want to have to go and redo through all your code.

how to do string enums and such in objective c

I have filenames and such that are NSStrings. I have to keep typing them in and I may mistype and cause an error. How does the experienced objective C programmer handle this so they only type it in once?
In the header:
extern NSString * const kMyFile;
in the implementation file
NSString * const kMyFile = #"FileName.txt";
You get code completion on it this way.
Or, if it is only being used in one class and doesn't need to be exposed in the header you could just do
static NSString * const kMyFile = #"FileName.txt";
- (void)viewDidLoad {
//assign names here
//create variable names in the header--> NSArray *filename;
filename = [[NSArray alloc] initWithObjects: #"File1", #"File2", nil];
//[filename objectAtIndex: i] --> NSString
}

incorrect variable value outside main()

i have this code
#import <Foundation/Foundation.h>
int testint;
NSString *teststring;
int Test()
{
NSLog(#"%d",testint);
NSLog(#"%#",teststring);
}
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
testint = 5;
NSString *teststring = [[NSString alloc] initWithString:#"test string"];
Test();
[pool drain];
return 0;
}
in output i have:
5
(null)
why Test function doesn't see correct teststring value? What should I do, to have correct "test string" in output?
You're shadowing a global variable with a local one. If the intent is to use the global testString, you shouldn't re-declare it with "NSString*".
in output i have:
5 (null)
why Test function doesn't see correct teststring value?
Because you never assigned anything there. In main, you declared a local variable with the same name, and initialized that variable with the pointer to the NSString object you created.
how should i declare global objects with "alloc init"?
You don't.
Declarations create variables (or sometimes types). The NSString *teststring lines (both of them) are declarations: One of a global variable, the other of a local variable.
alloc messages (and most other messages to classes) create objects.
Thus, this line:
NSString *teststring = [[NSString alloc] initWithString:#"test string"];
declared a local variable (teststring) and created a string object, and initialized the variable to hold the pointer to the string object.
(Note that “initWithString:” initializes the object, not the variable. The part from the = until the semicolon is the initializer for the variable.)
You meant to assign to the global variable, not declare a local variable. So, do that: Leave out the type specifier to turn the declaration into an assignment statement:
teststring = [[NSString alloc] initWithString:#"test string"];
By the way, you don't need to use alloc and initWithString: here. #"test string" is already an NSString object. And when you do alloc something, don't forget to release it (assuming you didn't turn on the GC).
You have two different variables named testint. The one in main() is shadowing the global one.
how should i declare global objects with "alloc init"?
Strings are a special case. You can do this:
NSString* foo = #"bar";