Until now if I needed access to a global variable across my app i just added
#define PATH [NSString stringWithFormat:#"www.url.com"]
To my Constants.h file.
I need to fetch the PATH value from my server.
How can i assign the value I'm getting from a server to a macro \string like the above and still be able to use just the variable PATH anywhere in my app? (Without naming the class like a property use such as class.PATH
This works:
#import <Foundation/Foundation.h>
NSString* PATH;
#interface Constants : NSObject
+(void)getPathFromServer;
#end
And PATH is accessible from anywhere in my app but I'm not sure if that should be the way to go.
As I understand so far, you need to define a macro which dynamic change it's url content.
If I'm right , you may need a Vararg Macros which takes a variable.
#define PATH(...) [NSString stringWithFormat:#"%#",__VA_ARGS__]
You can use extern keyword
Example :
//Header file
extern NSString * const path;
// .m file under implementation
NSString * const Ppath = [NSString stringWithFormat:#"www.url.com"];
Have a look at these
Constants in Objective C
#define vs const in Objective-C
Related
I want to define a global preprocessor directive in my app. For example:
In MyProgram.h, I define:
#define USE_LOCALHOST
I import this file from beginning in appDelegate.m.
For the later use, in another file, I refer to this global preprocessor directive.
In MyWebService.h, I define:
#ifdef USE_LOCALHOST
static NSString *MY_SERVER = #"http://192.168.1.130:8888";
#else
static NSString *MY_SERVER = #"http://myserver.com";
#endif
However, the value of MY_SERVER is always #"http://myserver.com". How to make it work properly? Thanks.
Define it in .pch. And you will never forget to include .h-file where you have defined USE_LOCALHOST.
Or you can define it in build settings in Preprocessor Macros.
For example only for Debug.
#define works only in the file where it's defined in. But you can #import "MyProgram.h" in MyWebService.h and problem solved. Every time you need to access USE_LOCALHOST, just import the header file.
I created Objective C Header file. and added some properties in it.
i declared
static NSString* const kColor005C98 = #"005C98"; in Constants.h file
I defined this file in Bridging-Header file as #import "Constants.h"
Now when i want to use this property kColor005C98 in some swift file it failed the build and i am getting
Undefined symbols for architecture armv7: "_kColor005C98", referenced from:
i don't know what else i need to do so i don't get this error? (i have used this property in other objective C file successfully and no issue in that case)
Update:
As of Swift 2/Xcode 7 and later, a static constant definition like
static NSString* const kColor005C98 = #"005C98"; // in Constants.h file
is imported to Swift and can be used without problems.
(Old answer for Swift 1.x) When the code
static NSString* const kColor005C98 = #"005C98"; // in Constants.h file
is processed by an Objective-C compiler, it is treated as two things
combined into one statement:
A variable declaration which introduces an identifier and describes its type, and
a variable definition which actually instantiates/implements this identifier.
See for example
What is the difference between a definition and a declaration?
for a good explanation of the difference between declaration and
definition.
The Swift compiler treats the statement only as a declaration.
Therefore the variable is not defined anywhere, causing the linker error.
To solve the problem, you have to move the definition to an Objective-C
file:
// Constants.m:
#import "Constants.h"
NSString * const kColor005C98 = #"005C98";
and change the declaration to an extern declaration:
// Constants.h:
extern NSString * const kColor005C98;
Alternatively, you can just remove the static modifier:
NSString * const kColor005C98 = #"005C98";
to make it work with Swift. The disadvantage is that when
this line is included by multiple Objective-C files, all of them
will define a globally visible symbol kColor005C98, causing
"duplicate symbol" linker errors.
Another alternative is to use a macro definition instead:
#define kColor005C98 #"005C98"
In my iOS/Objective C projects, I often have a constants.h file with my API keys and such. Until today, I've been declaring my constants as static const like so:
static NSString * const kAPIKey = #"wembvkejrvb43789gvbiu2bvfake";
This works fine, but with the unfortunate downside that I can only create constants for primitives and NSString literals, essentially. Other objects, such as UIColor objects, cannot be stored in this constant as they cannot be initialized with a static literal syntax (my understanding, citation required).
After reading some C++ docs, I understand a few things:
The static is unnecessary, as const are implicitly static.
Calling NSString * const x is actually declaring a constant and immutable value in x. I cannot change the value, but may be able to change what x points to.
This const has internal linkage, meaning the the value is defined right away (presumable at compile time).
Are these conclusions correct?
How does an extern const differ? I assume they are externally linked (thus the extern keyword). Are they defined at run time? Can I create some sort of dynamic extern const that can be set with a value returned by a class method?
For example, I would like to create a globally-scoped constant that contains a UIColor value. I would like to construct this color value using the [UIColor colorWithRed:green:blue:alpha:] class method. This clearly doesn't work with the internally linked constants I've been using (I'm assuming because it happens at compile-time) - but is it possible using an external constant, possibly set up in the +initialize method?
Any elaboration on the details of this behavior would be immensely helpful.
The static is unnecessary, as const are implicitly static.
No, that's not true.
static when used at file scope (i.e. outside any method or function) means that the variable is visible only within that file.
extern means that the variable is defined in some other file.
const means that the variable cannot be modified.
Consider strings. Often, you'll have an implementation file (name ends in .m) that defines some constant string pointer:
NSString *const SomeString = #"some string";
You might want to use that same constant from other files. If so, you could add a declaration to the header (name ends in .h) file that explains to the compiler that the variable is defined elsewhere:
extern NSString *const SomeString;
and that would let you use SomeString in any file that imports the header file. On the other hand, you might decide that you definitely do not want the constant used outside the implementation file. In that case, you could declare it static (in the implementation file again):
static NSString *const SomeString = #"some string";
and that would prevent its use from outside the file.
Calling NSString * const x is actually declaring a constant and immutable value in x. I cannot change the value, but may be able to change what x points to.
Right, it declares the pointer x to be constant -- you can't change it. You also can't change the value that it points to if it's actually a NSString because an instance NSString isn't mutable.
This const has internal linkage, meaning the the value is defined right away (presumable at compile time).
I'll take the 5th on that -- I'm not sure exactly how the compiler deals with constant strings. I think it's safe to use that as a mental model, though; the string will in any case be defined before your code ever gets to use it.
On your specific programming question, how to create a compile-time defined color object: you can't, because, apart from the handful for which the language supplies literal syntax, objects are created at runtime.
But you can still do it elegantly at runtime, without any addition to global scope, the same way the sdk does...
#interface UIColor (RainbowAddition)
+ (UIColor *)chartruseColor;
#end
#implementation UIColor (RainbowAddition)
+ (UIColor *)chartruseColor {
// bonus: this is really chartruse... according to the internet
return [self colorWithRed:0.5 green:1.0 blue:0.0 alpha:1.0];
}
#end
http://cloford.com/resources/colours/500col.htm
Objective-C is a pure extension of C, C++ is not.
At global scope:
in C (and Objective-C) writing const is equivalent to extern const (external linkage);
in C++ writing const is equivalent to static const (internal linkage).
Both in C (and Objective-C) and C++, to create a global-scoped const you can define it, just one time, in one source file like extern const TYPE identifier = VALUE; and declare it (typically in an header file) like: extern const TYPE identifier; (read it: I defined this const elsewhere at global linkage level).
We started with #defines pointing our app to dev, qa and live API servers. Well, that's rather lazy, not to mention painful to manage.
I'm thinking of storing default URL/connection settings in a .plist and creating dev|stage|live build configurations that will use the corresponding .plist for connections.
Is there a cleaner way to do this?
How secure is a .plist?
Here's how I handle it.
I have a single file where i store information like this. Lets call this file Configuration{h,m}
Within my .h (header) file, i declare the constants like this:
#pragma mark - API
extern NSString * const kAPIHost;
extern NSString * const kAPIVersion;
Within my .m (implementation) file, I finish it off with this
#pragma mark - API
#if TARGET_IPHONE_SIMULATOR
NSString * const kAPIHost = #"http://localhost/";
#else
NSString * const kAPIHost = #"http://liveserver.com";
#endif
NSString * const kAPIVersion = #"v2/";
What happens here is, it checks to see if i'm running on the sim, if i am, then it uses localhost, if it's running on device, it uses the live server.
Finally, I import Configuration.h in my precompiled header (PCH) file.
#import Configuration.h
Now, this file is available throughout your application without needing to import it in every single file. I use it like this.
NSURL * url = [NSURL URLWithString:[kAPIHost stringByAppendingString:[kAPIVersion stringByAppendingString:#"apiEndPoint/"]]];
The comment that troop231 posted sounds very interesting though. Maybe something I can implement at some time in the future. Always looking for more secure ways to do things :)
You could store this in keychain - it's secure - but I don't know why You would want to do that.
You could use extern constants instead of defines:
extern NSString *const in a class.
You can use preprocessor directives to help You manage the addresses:
http://www.techotopia.com/index.php/Using_Objective-C_Preprocessor_Directives
You could create a singleton class that would for example read these urls from .plist at start and then hand it over to any class that is interested.
About security:
using singleton with .plist and shipping app would not reveal Your test / dev addresses.
using #define, externs and preprocessor directives i.e. #ifdef DEBUG would also not reveal Your dev / test addresses in production code.
I've find it frustrating to define constants in the .h as externals and then assign the constants in the .m file. Seems so redundant. Is there any reason not to just define the constants in the header file?
Typical implementation would be:
// Constants.h
#interface Constants : NSObject
extern NSString *const kPCFavorites;
#end
The implementation would then be:
// Constants.m
#implementation Constants
NSString *const kPCFavorites = #"PCFavorites";
#end
However, I can just do this:
// Constants.h
static NSString *const kPCFavorites = #"PCFavorites";
#interface Constants : NSObject
#end
Obviously, this last definition doesn't even need an interface or implementation so both could be left out and become:
// Constants.h
static NSString *const kPCFavorites = #"PCFavorites";
with no .m file at all.
This seems much cleaner to me. Why wouldn't we implement constants this way? I've defined them both ways and I get no compile or runtime errors in XCode 5.
Because
static NSString * const kPCFavorites = #"PCFavorites";
declares a variable, not a constant. C doesn’t actually have a way to declare a symbolic constant (besides enum, which only works for integers).
As a result, if you use this method, every file that #includes your header will have its own variable called kPCFavorites. Historically, that would have meant that your program would increase in size because of all of the copies of kPCFavourites and the string #"PCFavourites", although more modern linkers may manage to get rid of some or all of the duplication (certainly I’d expect the linker to leave you with only one copy of the string itself; whether or not it can currently get rid of the extra pointer variables I’m not sure — but it’s easy to test).
static variables have file scope. If you compile a file which includes a header file with a static variable, that variable will exist in the compiled file. If you compile another file with the same header file, you have a second static variable and so on. If you include the header from 1000 source files, you get 1000 static variables, all with the same name.