Static NSLocalizedString - objective-c

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;
}

Related

Auto generation of _instanceVariable from property name in Objective C

I'm new to Objective C, and am using the Stanford CS193P course for the basics. In the first lecture, according to what I understood from it, anytime I declare a property in the header file, Objective C auto-generates the setter and getter for the property, where the getter name is the same as the property name. The professor also mentioned about the #synthesize keyword, which is used to set something as the instance variable name, like so #synthesize card = _card.
So now, any changes can be made to the property by using _card directly as well.
However, he mentions many times that all this happens behind this scenes and none of this appears to us in the implementation file.
If that's the case, then in the code below:
//
// PlayingCard.h
// CardGame
//
// Created by Manish Giri on 9/19/15.
// Copyright (c) 2015 Manish Giri. All rights reserved.
//
#import "Card.h"
#interface PlayingCard : Card
#property (nonatomic,strong) NSString *suit; //one of club, heart, spade, diamond
#property (nonatomic) NSUInteger rank; //numbers from 0 through 13
#end
//
// PlayingCard.m
// CardGame
//
// Created by Manish Giri on 9/19/15.
// Copyright (c) 2015 Manish Giri. All rights reserved.
//
#import "PlayingCard.h"
#implementation PlayingCard
//#synthesize suit = _suit;
//override the getter method "contents" to return the description- rank&suit of the playing card
-(NSString *) contents {
//return [NSString stringWithFormat:#"%lu %#", (unsigned long)self.rank, self.suit];
//if rank is 0 or not set, return ?
NSArray *rankStrings = #[#"?", #"1", #"2", #"3", #"4", #"5", #"6", #"7", #"8", #"9", #"10", #"11", #"12", #"13"];
return [rankStrings[self.rank] stringByAppendingString:self.suit];
}
-(NSString *) suit {
//return ? if suit is nil or not set
return _suit?_suit:#"?";
}
-(void) setSuit:(NSString *)suit {
//check the suit to be set is valid
if([#[#"♥︎", #"♦︎", #"♠︎", #"♣︎"] containsObject:suit]) {
_suit = suit;
}
}
#end
Why do I get the error:
Use of undeclared identifier _suit. Did you mean suit?
After I got this error, I added the line #synthesize suit = _suit, and the error was fixed, but isn't this done automatically? If not, what's the difference?
The professor, most certainly, did not have the #synthesize line in his code (in the slide) while still using _suit.
You have defined your own getter/setter and so have turned off this automatic generation of the instance variable. You will need to add your own instance variable:
#implementation PlayingCard () {
NSString *_suit;
}
#end
#implementation PlayingCard
...
#end
I would also strongly suggest you use an enum for the suits as #"♥︎", #"♦︎", #"♠︎", #"♣︎" are presentation formats and are less useful to your code. For example:
// This should be in the header file
typedef enum {
SUIT_NONE,
SUIT_HEARTS,
SUIT_DIAMONDS,
SUIT_SPADES,
SUIT_CLUBS
} Suit;
#implementation PlayingCard () {
Suit _suit;
}
#end
It's now much easier and efficient to do:
if (_suit == SUIT_CLUBS) { ... }
than:
if ([_suit isEqualToString:#"♣︎"]) { ... }
Enums can also be used in switch statements and you will also find it easier for code using this class as well, for example:
if (cardsOnTable[i].suit == _cardsInHand[j].suit) {
points++;
}
It is done for you, unless you explicitly implement both the setter and getter methods yourself. I think you should also have seen a compile warning that this was happening on the property definition.
When you specify a property you're defining the thread and memory management, but if you then implement the accessor methods there is no guarantee you actually follow those rules. In this case you might actually be using some other memory all together so you need to tell the compiler what you want it to do.
All that magic is gone once you override a getter method. When you override it, you have to manually declare ivar backing the property or use #synthesis which essentially does the same. You can still define custom setter though and find that ivar is still there.

Is it ok to have overriden getters of an Objective-C class be static?

I have some existing code I'm modifying from another developer. They have a static NSString declared as follows...
static NSString *myStaticString;
This string should be initialized before use. What I'm looking to do is have a property method overriden which will ensure the variable is set. Here's what my suggested layout would look like...
static NSString *myStaticString;
#interface MyClass ()
#property (readonly) NSString *myProperty;
#end
#implementation MyClass
+(NSString *)myProperty
{
if (!myStaticString)
myStaticString = [#"My string value!" retain];
return myStaticString;
}
#end
The new thing for me here is I've never declared a getter as a static method and to be honest I don't know if that is a good idea or not.
In answer to the question (and I paraphrase) "is it ok to have getters return a pointer to a static?" the answer is yes, it is.
The issue here is, though, that getters are instance methods, and you've defined a class method. So you'll end up with a confusing combination of your explicitly defined class method that happens to bear the same name of an automatically synthesized getter instance method (and, worse, that synthesized getter instance method will just be returning a pointer to some automatically synthesized ivar, which is obviously not what you intended). Bottom line, you are not overriding the getter like you obviously thought you were.
As bbum pointed out, you can easily remedy this by defining this explicitly declared method as an instance method. By doing that, you will thereby be overriding the getter, accomplishing what you probably intended.
Personally, since there's nothing here that requires an instance method, I might be inclined to just retire the property altogether and have the class method return a pointer to the string referenced by your static variable. In that case, I'd suggest one of two approaches:
If the string is truly a constant, then I might do something like:
// MyClass.h
#interface MyClass : NSObject
+ (NSString *)someString;
#end
and
// MyClass.m
#import "MyClass.h"
static NSString * const kSomeInternalConstant = #"my string";
#implementation MyClass
+ (NSString *)someString
{
return kSomeInternalConstant;
}
#end
If the string is defined at runtime, but does not change while the app is running, then I'd replace the MyClass.m with:
// MyClass.m
#import "MyClass.h"
#implementation MyClass
+ (NSString *)someString
{
static NSString *someInternalString = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
someInternalString = ... // set it to be whatever you want
});
return someInternalString;
}
#end
Clearly, replace these variable names with something more logical, but hopefully this illustrates the idea.
If you're looking for the class-level equivalent of #property, then the answer is "there's no such thing". But remember, #property is only syntactic sugar, anyway; it just creates appropriately-named object methods.
You still can use class methods that access static variables which have only a slightly different syntax.
Here's thread safe example:
// Foo.h
#interface Foo {
}
+(NSDictionary*) dictionary;
// Foo.m
+(NSDictionary*) dictionary
{
static NSDictionary* fooDict = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
// create dict
});
return fooDict;
}
You need it to be an instance method:
-(NSString *)myProperty
{
if (!myStaticString)
myStaticString = [#"My string value!" retain];
return myStaticString;
}
And, yes, that is fine.
• The retain is odd; don't need it, doesn't hurt. Best turn on ARC and be done with it.
• I'd move the static into the method or, if it never changes, just return #"My string value!" directly.
• This is not an uncommon pattern; this class may return a default, static, value and subclasses might override to return a different value, as necessary.
• When initializing a static, use dispatch_once. In this case, it doesn't matter as it is an assignment of a static constant string. But, like the retain, best to follow convention (i.e. eliminate the retain, use dispatch_once or just return the value directly).

Avoid extra static variables for associated objects keys

When using associated objects, an Objective-C runtime feature available starting from iOS 4 and OSX 10.6, it's necessary to define a key for storing and retrieving the object at runtime.
The typical usage is defining the key like follows
static char const * const ObjectTagKey = "ObjectTag";
and then use is to store the object
objc_setAssociatedObject(self, ObjectTagKey, newObjectTag, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
and retrieve it
objc_getAssociatedObject(self, ObjectTagKey);
(example taken by http://oleb.net/blog/2011/05/faking-ivars-in-objc-categories-with-associative-references/)
Is there a cleaner way to define the associated object key, that doesn't involve the declaration of extra variables?
According to this blog entry by Erica Sadun (whose credits go to Gwynne Raskind), there is.
objc_getAssociatedObject and objc_getAssociatedObject require a key to store the object. Such key is required to be a constant void pointer. So in the end we just need a fixed address that stays constant over time.
It turns out that the #selector implementation provides just about what we need, since it uses fixed addresses.
We can therefore just get rid of the key declaration and simply use our property's selector address.
So if you are associating at runtime a property like
#property (nonatomic, retain) id anAssociatedObject;
we can provide dynamic implementations for its getter/setter that look like
- (void)setAnAssociatedObject:(id)newAssociatedObject {
objc_setAssociatedObject(self, #selector(anAssociatedObject), newAssociatedObject, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (id)anAssociatedObject {
return objc_getAssociatedObject(self, #selector(anAssociatedObject));
}
Very neat and definitely cleaner than defining an extra static variable key for every associated object.
Is this safe?
Since this is implementation-dependent, a legitimate question is: will it easily break?
Quoting the blog entry
Apple would probably have to implement a completely new ABI for that to happen
If we take those words to be true, it's then reasonably safe.
If you need access to the key from outside the scope of a single method, a nice pattern for this which leads to more readable code is to create a pointer which simply points to its own address in the stack. For example:
static void const *MyAssocKey = &MyAssocKey;
If you only need access from within the scope of a single method, you can actually just use _cmd, which is guaranteed to be unique. For example:
objc_setAssociatedObject(obj, _cmd, associatedObj, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
A slight variation on the idea #Gabriele Petronella discussed is to associate a dictionary to every object:
//NSObject+ADDLAssociatedDictionary.h
#import <Foundation/Foundation.h>
#interface NSObject (ADDLAssociatedDictionary)
- (void)addl_setAssociatedObject:(id)object forKey:(id<NSCopying>)key;
- (id)addl_associatedObjectForKey:(id<NSCopying>)key;
#end
//NSObject+ADDLAssociatedDictionary.m
#import <objc/runtime.h>
#interface NSObject (ADDLAssociatedDictionaryInternal)
- (NSMutableDictionary *)addl_associatedDictionary;
#end
#implementation NSObject (ADDLAssociatedDictionary)
- (void)addl_setAssociatedObject:(id)object forKey:(id<NSCopying>)key
{
if (object) {
self.addl_associatedDictionary[key] = object;
} else {
[self.addl_associatedDictionary removeObjectForKey:key];
}
}
- (id)addl_associatedObjectForKey:(id<NSCopying>)key
{
return self.addl_associatedDictionary[key];
}
#end
#implementation NSObject (ADDLAssociatedDictionaryInternal)
const char addl_associatedDictionaryAssociatedObjectKey;
- (NSMutableDictionary *)addl_associatedDictionaryPrimitive
{
return objc_getAssociatedObject(self, &addl_associatedDictionaryAssociatedObjectKey);
}
- (void)addl_setAssociatedDictionaryPrimitive:(NSMutableDictionary *)associatedDictionary
{
objc_setAssociatedObject(self, &addl_associatedDictionaryAssociatedObjectKey, associatedDictionary, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSMutableDictionary *)addl_generateAssociatedDictionary
{
NSMutableDictionary *associatedDictionary = [[NSMutableDictionary alloc] init];
[self addl_setAssociatedDictionaryPrimitive:associatedDictionary];
return associatedDictionary;
}
- (NSMutableDictionary *)addl_associatedDictionary
{
NSMutableDictionary *res = nil;
#synchronized(self) {
if (!(res = [self addl_associatedDictionaryPrimitive])) {
res = [self addl_generateAssociatedDictionary];
}
}
return res;
}
#end
Then in our category on some subclass Derived of NSObject
//Derived+Additions.h
#import "Derived.h"
#interface Derived (Additions)
#property (nonatomic) id anAssociatedObject;
#end
//Derived+Additions.m
#import "NSObject+ADDLAssociatedDictionary.h"
#implementation Derived (Additions)
- (void)setAnAssociatedObject:(id)anAssociatedObject
{
[self addl_setAssociatedObject:anAssociatedObject forKey:NSStringFromSelector(#selector(anAssociatedObject))];
}
- (id)anAssociatedObject
{
return [self addl_associatedObjectForKey:NSStringFromSelector(#selector(anAssociatedObject))];
}
#end
One benefit of the associated dictionary approach in general is the added flexibility that comes from being able to set objects for keys that are generated at runtime, not to mention the much nicer syntax.
A benefit particular to using
NSStringFromSelector(#selector(anAssociatedObject))
is that NSStringFromSelector is guaranteed to give an NSString representation of the selector which will always be an acceptable dictionary key. As a result, we don't have to worry at all (though I don't think it's a reasonable concern) about ABI changes.

How to declare constants

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.

Can I validate a #property value in Objective-C using #synthesized methods?

What it says on the tin: I'd like to use the #property/#synthesize syntax to define a property on my Objective-C 2.0 class, but I want to place restrictions on the range of values allowed in the property. For example:
#interface MyClass : NSObject {
int myValue;
}
#property (nonatomic) int myValue;
Implementation:
#implementation MyClass
#synthesize myValue(test='value >= 0');
Note that the syntax here is just an example. Is this, or something much like it possible? Alternately, what is the literal equivalent of a synthesized setter, so that I can ensure that I use the same object retention rules in my manual setters as is used in a synthesized one.
Assuming your properties are Key-Value compliant (as they would be if you are using #synthesize) you should also implement Key-Value compliant validators. Take a look at Apple's documentation on the matter: http://developer.apple.com/documentation/Cocoa/Conceptual/KeyValueCoding/Concepts/Validation.html
The important thing to note is that validation does not happen automatically except when using certain kinds of binding. You either call the validator directly or by calling validateValue:forKey:error:.
You could override the produced setter to call the validator before saving it but if you are using bindings this is probably not what you want to do as the validator will possibly be called more than once for a single modification.
Also note that the validator might change the value being validated.
So lets look at your example (untested, btw. I'm not near a Mac):
#implementation MyClass
#synthesize myValue;
-(BOOL)validateMyValue:(id *)ioValue error:(NSError **)outError
{
if (*ioValue == nil) {
// trap this in setNilValueForKey
// alternative might be to create new NSNumber with value 0 here
return YES;
}
if ( [*ioValue intValue] < 0 ) {
NSString *errorString = #"myValue must be greater than zero";
NSDictionary *userInfoDict = [NSDictionary dictionaryWithObject:errorString
forKey:NSLocalizedDescriptionKey];
NSError *error = [[[NSError alloc] initWithDomain:#"MyValueError"
code:0
userInfo:userInfoDict] autorelease];
*outError = error;
return NO;
} else {
return YES;
}
}
If you wanted to override the synthesised setter and make it do the validation (still untested):
- (void)setMyValue:(int)value {
id newValue = [NSNumber numberWithInt:value];
NSError *errorInfo = nil;
if ( [self validateMyValue:&newValue error:&errorInfo] ) {
myValue = [newValue intValue];
}
}
You can see we had to wrap the integer in an NSNumber instance to do this.
When you use the #synthesize the accessor methods are generated. You can implement your own which will overwrite the generated one.
You can put your own implementation inside the accessor methods, e.g. you can add value checking before assignment and so on.
You can ommit one or the other or both, the ones that you don't implement will be generated because of #synthesize, if you use #dynamic you are specifying that you will provide accessors either at compile or run time.
Accessors will have names derived from the property name myproperty and setMyproperty. The method signatures are standard so it is easy to implement your own. The actual implementation depends on property definition (copy, retain, assign) and if it is read-only or not (read-only doesn't get set accessor). For more details see objective-c reference.
Apple reference:
#synthesize You use the #synthesize
keyword to tell the compiler that it
should synthesize the setter and/or
getter methods for the property if you
do not supply them within the
#implementation block.
#interface MyClass : NSObject
{
NSString *value;
}
#property(copy, readwrite) NSString *value;
#end
#implementation MyClass
#synthesize value;
- (NSString *)value {
return value;
}
- (void)setValue:(NSString *)newValue {
if (newValue != value) {
value = [newValue copy];
}
}
#end