After updating Xcode to version 5.1, I had a warning that told me I had defined a constant that I wasn't using. Its definition looked like this:
static NSInteger const ABCMyInteger = 3;
I was happy to see that it got marked, because I thought this meant that the compiler was now able to check for unused constants in addition local to variables.
I refactored some more, making three NSString constants obsolete. All three were defined very similarly to the NSInteger from above:
static NSString *const ABCMyString = #"ABCMyString";
To my surprise, however, these do not get marked as "unused", though I know for sure that they aren't used anymore.
Can someone explain why an NSInteger does get noticed by the compiler as unused, but an NSString does not?
A primitive variable is just a memory block allocated in a static memory part and initialized by the compiler. The string object, however, is a variable initialized at runtime (in startup, probably), so the compiler adds an implicit call to the constructor and uses the variable as a parameter for that call. So the variable is being used.
The _unused item of the structure is IMHO not a directive, but just a member variable, probably it is added for better alignment (fills the object size to a round size).
The definition of an NSString literal at compile time rely on the use of the NSSimpleCString meta class.
This class looks something like this:
#interface NSSimpleCString : NSString {
#package
char *bytes;
int numBytes;
#if __LP64__
int _unused;
#endif
}
#end
#interface NSConstantString : NSSimpleCString
#end
The addition of the _unused flag make me believe that further down the implementation of NSSimpleCString the code will instruct the compiler to silence those warnings with __unused.
You can try yourself by prepending your integer or float constant with __unused like:
__unused static const NSInteger ABCMyInteger = 3;
For a more in depth explanation read the article on literals by Mike Ash
Related
When reading the headers of Foundation I found this:
- (__strong const char *)UTF8String NS_RETURNS_INNER_POINTER;
// Convenience to return null-terminated UTF8 representation
This is from NSString.h in the iOS 7.1 SDK, what does __strong const char * mean here?
I'm most confused about the "__strong" here.
Foundation is shared between iOS and Mac OS. On Mac OS, for a while there existed a garbage collection memory management system. It's now deprecated and not longer supported on Mac OS. It was never used on iOS.
GC used __strong as a modifier on plain pointer type declarations to make the pointed to memory collectible. This usage of __strong has no meaning in ARC or manual retain/release code. The fact that there's no warning for the declaration is probably only because clang issues no warnings in system headers.
NS_RETURNS_INNER_POINTER is a Clang annotation that indicates the method returns a pointer to one of its inner data structures (i.e., an instance variable), and that inner variable is not reference-counted, so whenever that method is called, ARC should increment the retain count for the receiver (because that object should not be released as long as the pointer to its inner data structures is in use).
In this case, __strong essentially acts in conjunction with NS_RETURNS_INNER_POINTER to indicate the lifetime of an object that returned a pointer to its inner data structures.
__strong means that the object (of class NSString in this case), that holds the pointer, retains its ownership till the end of the life of the object and the pointed memory will be garbage-collected. Hence INNER.
const char * means that the char array this pointer points to is constant, i.e. cannot be changed for example by changing some characters in it (you will get a compiler error).
If you try to compile this:
#import <Foundation/Foundation.h>
int main(int argc, char **argv)
{
NSString *s = #"string";
const char *str = [s UTF8String];
printf("%s\n", str);
str[0] = 'S';
printf("%s\n", str);
return 0;
}
you'll get read-only variable is not assignable error.
I'm trying to determine if there is an elegant solution to this issue.
Say I have a global defined in some header:
Constants.h:
extern NSString *someGlobal;
And then I wish to use this global in some other class:
Foo.m
NSString *localVariable = someGlobal;
This all works just fine if I initialize the global like this:
Constants.m:
NSString *someGlobal = #"Some String Literal";
But lets say I need to initialize the global to something that isn't a compile-time constant. In such cases I typically do this:
Constants.m:
#implementation Constants
+ (void)initialize {
someGlobal = ... // some non-trivial initialization
}
#end
Now I have a potential problem in Foo.m. If no reference has been made to the Constants class when I try to use someGlobal, the result is nil. A workaround is to do:
Foo.m (or in some app startup code):
[Constants class];
That will trigger the initialize method of the Constants class and someGlobal will be properly initialized. As long as this is done before any runtime use of someGlobal, things work fine.
Is there a better way to initialize extern globals with non-compile time constants without the need to call code such as [Constants class] at app startup?
A more idiomatic way in Objective-C is using a singleton instead of multiple globals. Here is how:
#interface Globals
#property (readwrite,nonatomic) NSString *myString;
#property (readwrite,nonatomic) int myInt;
+(Globals*) instance;
#end
+(Globals*) instance {
static dispatch_once_t once;
static Globals *inst;
dispatch_once(&once, ^{
inst = [[Globals alloc] init];
inst.myString = #"Some String Literal";
inst.myInt = 42;
});
return inst;
}
Now you can use your globals like this:
NSLog(#"Global string: %#", [Globals instance].myString);
NSLog(#"Global string: %d", [Globals instance].myInt);
No, there is no better way. Logically, if some piece of code must execute before a variable is intialized, you have to take steps to make sure that happens.
You could arrange the flow of your program's code so as to guarantee that the Constants class get initialized before any other piece of code executes which needs it. For example, by tweaking the order in which things are initialized in your program and following the order of code execution from main() on down to prove to yourself that it works. But short of that (and the safest thing in any case), you would use your technique to force it to be made valid right before you use it.
Like dasblinkenlight's answer, this may not be exactly what you are looking for but it's another approach.
I would make class methods that returns the value you are looking for like this:
+(NSString *)someConstant {
static NSString *constant;
if(constant == nil)
constant = //your initialization here;
return constant;
}
Then where you need to use it just call [Constants someConstant];
Other random thoughts:
A constant that isn't some compile time value isn't really what extern variables are for and this method insures that the variable is initialized every time you use it. The class using the constant has to know about your class anyway or it wouldn't have imported its header file
if you don't take #define into account, there are two notorious ways for declaring constants in objective-c project:
// Util.h
extern NSString * const MyConstant;
// Util.m
NSString * const MyConstant = #"value";
or the other directly in header file
// Util.h
static NSString *const MyConstant = #"value";
Now, there comes two questions:
1)
Both works, the second method is quite convenient, as I have only one place for editing values.
However as I saw from Apple .h files, the first method is always preferred, and I wonder if there are any downside, with the static method.
2) Looking at Apple docs, we often encounter very long constant name like: NSTextInputContextKeyboardSelectionDidChangeNotification. In the case you used a long constant name like that, what convention would you generally use to assign a value. If I want to use something descriptive I could use #"nsTextInputContextKeyboardSelectionDidChangeNotification", but sounds little odd.
I won't explain you all the specifics of the two types of constant declaration - in short:
The first one separates constant declaration from constant definition. Only declaration is included by header files. It also conveniently hides the actual value of the constant.
The second one is more problematic - the header file contains both declaration and definition of the constant. That means that whenewer you include the header, the constant is created again. I don't think this will work correctly when included from multiple files.
The second question - no problem with long constant names. Your example is a bit extreme but there is nothing wrong with it.
EDIT: Adding more information about the static NSString* const in header.
Let's have a header A.h:
//A.h
static NSString *const MyConstant = #"value";
and file including it A.m
//A.m
#import "A.h"
printA() {
NSLog(#"A.h Constant: %#", MyConstant);
}
First note that headers are removed by the preprocessor before compilation. That means that before compilation there won't be any A.h file and A.m will look like this:
//A.m
static NSString *const MyConstant = #"value";
printA() {
NSLog(#"A.h Constant: %#", MyConstant);
}
Let's create another constant header B.h and implementation file B.m with exactly the same contents:
//B.h
static NSString *const MyConstant = #"value2";
//B.m
#import "B.h"
printB() {
NSLog(#"B.h Constant: %#", MyConstant);
}
Note that the constant is declared twice, with the same name and different values. This is possible because static makes the constant private for the file that includes it. If you remove the static, you'll get a compilation error because the compiler will find two public global constants with the same name.
In theory it is possible to use static NSString* const in header files and everything will work correctly but as you can see, it doesn't do exactly what you want and can be a source of difficult-to-find bugs. That's why you should use static only from implementation files.
Just to add - the second way that you have shown doesn't make much sense.
If you are going to declare and define a constant in one place such as this, it's usually done in the .m file and not the .h file.
You do it this way for constants that are only going to be used in the class itself and not exposed.
I want to make some NSNumber constants via the same style used for NSStrings in this topic. That is, I'm creating separate constants.h/.m files and importing them into classes that need to access them.
The trouble with doing this is that there isn't such a thing as a compile-time constant NSNumber. Only NSString gets that distinction. NSNumbers are always created dynamically. You can fake it by using a function that runs at your program's startup to initialize the variables. Your options:
Create a class with a +load method that performs the initialization.
In the file with the constants, include a function with __attribute__((constructor)). So, for example:
// Constants.m
NSNumber *someGlobalNumber;
__attribute__((constructor))
static void InitGlobalNumber() {
someGlobalNumber = [[NSNumber numberWithInteger:1] retain];
}
But of course then you can't reliably use these numbers in any other functions which are run that early in the startup process. This usually isn't a problem, but is worth keeping in mind.
The other option, which I've seen crop up a few times, is to have a class with accessors for the numbers instead of giving raw access to the variables. It's a bit of a heavier design, but it also feels less voodooish, which has its charms.
Unfortunately you cannot currently generate NSNumber constants in the same way you can generate NSString constants. When you try to do you will get a compiler error
NSNumber * const kNumberConstant = #2; // This doesn't work.
However, you can use primitives instead.
NSInteger const kSomeIntValue = 10;
You can basically achieve close to what you want in three parts:
.h file:
extern NSNumber *MyFirstConstant;
.m file
NSNumber *MyFirstConstant;
AppDelegate.m
+(void)initialize
{
MyFirstConstant = #5;
...
}
AppDelegate is guaranteed to run before any of your other code, and the initialize is the first method that would be called on AppDelegate, so you can essentially insure all your constants are setup for you before your app runs.
update:
Years later, I just realized it is possible to create a NSNumber constant for integers... but it's a hack:
#define CONST_INT_NSNUMBER( x ) ((__bridge NSNumber * const)(void * const)(( x << 8 ) | 0x27))
NSNumber * const number = CONST_INT_NSNUMBER(123) ;
This works because certain integer NSNumbers are stored as tagged pointers.
original answer:
You can't do it.
NSNumber * const mynumber = #5.5;
gives:
Initializer element is not a compile-time constant
Implying the compiler has a special feature specifically for creating compile-time constant NSString objects, but not any other type of object.
You could do this, however:
.h:
extern NSNumber * kConstantNumber ;
.m:
NSNumber * kConstantNumber ;
#implementation NSNumber (InitializeConstants)
+(void)load
{
kConstantNumber = #42;
// ... and the rest ...
}
#end
I have tried many times to understand the const keyword, but it just doesn't work out for me.
I want to declare an object that cannot be changed, which is to say, a constant object. For example, in the .h file:
extern MyClass *use_this_object;
and in the .m file:
MyClass *use_this_object;
+ (void) Initialize {
use_this_object = [MyClass new];
}
Now, where can I put a const so that other classes can access use_this_object but not modify it (assuming MyClass is immutable), while the MyClass class can initialize the variable?
Is this even possible? Or should I be using a static method to retrive the constant and not declare it extern at all?
There is no such thing as a "const object" in Objective-C. There are const pointers and there are immutable objects. A const pointer to an immutable object is what you're talking about, but you can't allocate those at run time.
For objects that can be allocated at compile time (and I only know of one, NSString), you can do this:
NSString * const kMyString = #"string";
This is a constant pointer to an (immutable) NSString. You read these things right-to-left.
To create what you want, you need a function or method with an internal static like this:
+ (Something *)something {
static Something *something = nil;
if (! something) {
something = [Something new];
}
return something;
}
This is preferable to using globals anyway for things other than true constants (like strings and integers).
It is up to you to make sure that Something is immutable.
EDIT Just a note about the above code. This is just an example of how to create a static object at runtime. There are many ways to do it with various trade-offs including using +initialize with a file static (which is currently my preferred way to create a singleton). Don't take the above code as the one-and-only-way. It's just the way that is closest to const because no other part of the program can get directly to the pointer.
I’d use the static method, seems much simpler.