How to declare constants - objective-c

I'm steadily getting the hang of Objective-C, but am still very much a beginner and have a beginner-level question hopefully someone could shed some light on:
If I have a very simple project and want to set a constant that I'll use throughout—say, a NSDictionary with keys being month names and values being days in that month—how is this done? (I.e., what command form and where to put it?)
NOTE: If this example is already possible using built-in functions, perhaps we could just pretend it isn't for the purposes of this question ;)

The answer depends on the type of your constant. If all you need is an int or a double, you can use preprocessor and the #define CONST 123 syntax. For Objective C classes, however, you need to do a lot more work.
Specifically, you would need to hide the constant behind a class method or a free-standing function. You will also need to add a prototype of that method or function in the header file, provide a function-scoped static variable to store the constant, and add code to initialize it.
Here is an example using a simple NSDictionary:
Header: MyConstants.h
#interface MyConstants
+(NSDictionary*)getConstDictionary;
#end
Implementation: MyConstants.m
+(NSDictionary*)getConstDictionary {
static NSDictionary *inst = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
inst = #{
#"key1": #"value1",
#"key2": #"value2",
#"key3": #"value3"
};
});
return inst;
}
Usage:
NSString *val = [[MyConstants getConstDictionary] objectForKey:#"key2"];

The accepted answer is correct, but if you prefer operate with variable (not trough method). I can suggest this pattern:
#implementation MyClass
static NSSet *mySetOfObjects;
+ (void)initialize {
mySetOfObjects = [[NSSet alloc] initWithObjects:#"one", #"two", #"three", nil];
}
// Example usage:
+ (BOOL)isRecognizedString:(NSString *)searchItem {
return [mySetOfObjects containsObject:searchItem];
}
#end
As for me - it looks better.
For more details the source is here.

Let's assume you want to declare an NSString constant in your class that holds a url. In your header .h file you will need the following:
#import
extern NSString * const BaseURL;
#interface ClassName : NSObject {
You will then need to set it's value in your main .m file as follows:
#import "ClassName.h"
NSString * const BaseURL = #"http://some.url.com/path/";
#implementation ClassName
You can now access this constant throughout your class or subclasses. Here's an example of usage:
NSString *urlString = [NSString stringWithFormat:#"%#%#", BaseURL, #"filename.html"];

If your constants are strings then you can use this form:
MyObject.h:
extern NSString *const kJanuary;
....
extern NSString *const kDecember;
#interface MyObject : NSObject
{
...
}
#end
MyObject.m:
NSString *const kJanuary = #"January";
....
NSString *const kDecember = #"December";
#implementation MyObject
....
#end
You can then use the constant kJanuary, for example, from anywhere when using your class.

Related

Static NSLocalizedString

After checking a number of topics, I still can't figure something out : what is the (best?) way to use static NSLocalizedString, i.e. to statically allocate a NSLocalizedString and access it easily.
Ideally, I would want to do something like that (which won't compile, with an Initializer element is not a compile-time constant error):
//Somewhere in my header
static NSString* mystring = NSLocalizedString(#"min", nil); //Error : "Initializer element is not a compile-time constant"
#implementation myClass
(NSString*)aMethod
{
return myString;
}
#end
I know NSLocalizedString is a macro defined by #define NSLocalizedString(key, comment) \
[[NSBundle mainBundle] localizedStringForKey:(key) value:#"" table:nil], but that is not helping much :S.
Why ?
Long story short, to prevent the multiple definition of the same string in multiple parts of a document (which would prevent a one-stroke edit in my whole app).
Consider the example, where the redundancy of the definition is quiet explicit :
//MyDelegate.h
#property IBoutlet NSTextField* myTextField;
//MyDelegate.m
#implementation MyDelegate.m
#synthetize myTextField;
-(void)setTextFieldToDefaultValue
{
[myTextField setStringValue:NSLocalizedString(#"Name",#"This field is used to write one's name");
}
-(BOOL)isTextFieldStringDefault:(NSString*)myString
{
return [[myTextField stringValue] isEqual:NSLocalizedString(#"Name",#"This field is used to write one's name")];
}
#end
Of course, it makes more sense in a project which is quiet dense and big, where the string would be used in difference methods, and in a context where you have use of a lot of similar localized strings.
Generally this should all be in your implementation file:
static NSString* myString = nil;
#implementation myClass
+ (void)initialize
{
myString = NSLocalizedString(#"min", nil);
}
- (NSString *)aMethod
{
return myString;
}
#end
Well one more way you can write the same without using initialize method above:-
static NSString* mystring=nil;
-(NSString*)aMethod
{
mystring = NSLocalizedString(#"min", nil);
return mystring;
}

How to store values in a C structure without losing them when calling structure

I have a C (Objective-C) structure defined:
struct ResultadoVentaPUP{
NSString *autenticadoPorPin1;
NSString *autenticadoPorPin2;
NSString *tipoPago;
NSString *importe;
};
Then I declare a variable of this type globally (at top of the file):
ResultadoVentaPUP resven;
In a function I set values for this structure, for example:
resven.importe=#"12.45";
but when I try to view the content of "importe" in another function from the same file), ir returns (null).
NSLog(#"Result: %#",resven.importe);
What am I doing wrong? should I define the struct with 'static'?
Thank you!
Storing Obj-C objects in a C structure is a rather bad idea nowadays anyway, with ARC (Automatic Reference Counting), it is not even allowed any longer (the compiler will complain if you do that). Why not using an object instead? If you don't want to use assessor methods because you fear the overhead, just use an object with public ivars. Public ivars are bad IMHO, yet a struct is pretty much the same as an object with public ivars.
#interface ResultadoVentaPUP : NSObject
{
#public
NSString * autenticadoPorPin1;
NSString * autenticadoPorPin2;
NSString * tipoPago;
NSString * importe;
}
#end
#implementation ResultadoVentaPUP
#end
ResultadoVentaPUP * resven;
void someFunction () {
resven = [[ResultadoVentaPUP alloc] init];
resven->importe = #"12.45";
}
void someOtherFunction () {
NSLog(#"Result: %#",resven->importe);
}
This code will also work nicely if you use ARC and sooner or later every project should migrate to ARC in the near future (as soon as it can drop support for OSX/iOS versions without ARC support).
Maybe your declaration should be struct ResultadoVentaPUP resven;. This works for me:
#import <Foundation/Foundation.h>
struct ResultadoVentaPUP{
NSString *autenticadoPorPin1;
NSString *autenticadoPorPin2;
NSString *tipoPago;
NSString *importe;
};
struct ResultadoVentaPUP resven;
void func1() {
resven.importe = #"12.45";
}
void func2() {
NSLog(#"Result: %#", resven.importe);
}
int main(int argc, char *argv[]) {
NSAutoreleasePool *p = [[NSAutoreleasePool alloc] init];
func1();
func2();
[p release];
}
And I would be remiss if I didn't include the caveat that any time you are using global variables you should seriously be reconsidering your design.

Settings-like array of NSString objects

I'm only starting with Objective-C and it's still hard for me to do some pretty basic things. Here's what I want to achieve - I need to create a class that would hold all static data of my application which I guess could be represented with a number of NSString ** arrays, such as this one:
NSString *animalNames[NUM_ANIMALS] = {#"fox", #"wolf", #"elephant", #"giraffe"};
I want to be able to access these arrays in a static way from anywhere in my application. Something like this:
StaticData.animalNames[1]
How would I accomplish this in terms of #property, #interface, #synthesize and all this stuff?
I need to create a class that would hold all static data of my application
Here's an example of what you are talking about. It's a basic singleton class with a static array of your animals.
#import <Foundation/Foundation.h>
#interface Foo:NSObject
+ (id)sharedFoo;
- (NSArray *)animals;
#end
#implementation Foo
static NSArray *animals;
+ (void)initialize {
animals = [NSArray arrayWithObjects:#"fox",#"wolf",#"giraffe",#"liger",nil];
}
+ (id)sharedFoo {
static dispatch_once_t pred;
static Foo *cSharedInstance = nil;
dispatch_once(&pred, ^{ cSharedInstance = [[Foo alloc] init]; });
return cSharedInstance;
}
- (NSArray *)animals {
return animals;
}
#end
int main(int argc, char *argv[]) {
NSLog(#"Animals = %#",[[Foo sharedFoo] animals]);
}
This application logs the following to the console:
2012-10-08 10:01:46.814 Untitled[77085:707] Animals = (
fox,
wolf,
giraffe,
liger )
EDIT:
If you favor the dot syntax/property notation, you could just implement the following in the class interface:
#property (readonly) NSArray *animals;
which would let you write:
[Foo sharedFoo].animals
etc.

What is an import statement where filename contains "+"?

I have seen in some source code (by other developers) something like this:
#import "SomeClass+SomeOtherClass.h"
What is the + for? What does this mean?
Let's say you want to add functionality to an existing class (exp: NSString). You can do that by creating a subclass or you can use a category. And it is common to name the file where the category is defined using the pattern : MyClass+MyCategory.h.
For example, we can add a method reverseString to the class NSString in a category:
// File NSString+reversable.h
- (NSString *)reverseString;
// File NSString+reversable.m
- (NSString *)reverseString
{
// Implementation
}
Have a look at this documentation for more information about categories.
Then you can use that category in another class:
#import "NSString+reversable.h"
// ...
NSString *aString = #"Hello!";
NSString *reversedString = [aString reverseString];
The "+" in header/source filenames is - by convention - used to describe Category implementations.
Example :
Let's say you want to add some functionality to an existing class (e.g.the NSString class). (NSString+Utilities.h)
// NSString+Utilities.h
#interface NSString (Utilities)
-(NSString *) doSthWithThisString;
#end
// NSString+Utilities.m
#implementation NSString (Utilities)
-(NSString *) doSthWithThisString
{
NSMutableString *transformedStr = [self copy];
// Do sth
return transformedStr;
}
#end
Using it :
// in another file
#import "NSString+Utilities.h"
- (void)awakeFromNib
{
NSString* myString = #"This is a string";
// you may use our new NSString method as much as any already-existing one
NSString* newString = [myString doSthWithThisString];
}
Reference :
Mac OS Developer Library - Categories & Extensions
Objective-C Categories - Wiki

How do I publicly declare the keys to an NSDictionary?

I have defined a dictionary that I would like to pass around to various other objects. When they receive this dictionary, they need to know how it is defined so they can unpack it to get its values. I've been using #define's in my public header to define the keys. That way, I get edit-time compiler checking to ensure I don't use a bum key. But is there some other, more standard way to declare the interface to a defined dictionary so that other objects will get compile errors if they try to use undefined keys?
Better than #define is to use constant NSStrings. In your header:
extern NSString * const MyDictionaryFribbleKey;
(That's a constant pointer to an NSString.) And in your implementation:
NSString * const MyDictonaryFribbleKey = #"theFribble";
This is how the frameworks export constant strings. This won't stop the use of invalid keys, nothing will really do that (it's C, you can bypass anything), but it raises the bar higher.
Instead of using a dictionary why not use an object?
The example below shows that there really isn't much extra work involved. Plus you gain the advantages of actually using objects.
Object Set up
#interface MyClass : NSObject
#property (nonatomic, strong) NSString *myString;
#property (nonatomic, assign) CGFloat myFloat;
#end
#implementation MyClass
#synthesize myString = _myString;
#synthesize myFloat = _myFloat;
#end
Object use
MyClass *myClass = [[MyClass alloc] init];
// Set
myClass.myString = #"aa";
myClass.myFloat = 12.0f;
// Get
NSString *myString = myClass.myString
CGFloat myFloat = myClass.myFloat;
NSDictionary Set up
.h
extern NSString * const MYClassKeyMyString;
extern NSString * const MYClassKeyMyFloat;
.m
NSString * const MYClassKeyMyString = #"MYClassKeyMyString";
NSString * const MYClassKeyMyFloat = #"MYClassKeyMyFloat";
NSDictionary use
NSDictionary *myDict = [[NSMutableDictionary alloc] init];
// Set
[myDict setObject:#"aa" forKey:MYClassKeyMyString];
[myDict setObject:[NSNumber numberWithFloat:12.0f] forKey:MYClassKeyMyFloat];
// Get
NSString *myString = [myDict objectForKey:MYClassKeyMyString];
CGFloat myFloat = [[myDict objectForKey:MYClassKeyMyFloat] floatValue];
That's a pretty standard way. You can also enumerate the keys of a dictionary using the -enumerateKeys method.