In class A I have this:
static NSString * const kMyConstant = #"my constant string";
How can I reference this from class B?
You should extern your string in the header, and then define the string in the implementation.
//ClassA.h
extern NSString * const kMyConstant;
//ClassA.m
NSString * const kMyConstant = #"my constant string";
//ClassB.h/m
#import "ClassA.h"
...
NSLog(#"String Constant: %#", kMyConstant);
You need to remove the static -- that specifies that kMyConstant is only visible in files linked with this one.
Then, declare (as opposed to defining) the string in Class A's header:
extern NSString * const kMyConstant;
and import that header wherever you want to use this string. The extern declaration says that there exists an NSString * const by the name kMyConstant whose storage is created in some other place.
If the static definition is already in the header, you need to move it elsewhere (usually the implementation file). Things can only be defined once, and if you try to import a file which defines a variable, you'll get a linker error.
If it's static, you can't (that's what the static keyword is for).
If you simply declare it as a global variable, however, you can do something like this:
// ClassA.m
NSString *const str = #"Foo";
// ClassB.m
extern NSString *const str;
NSLog(#"str is: %#", str);
Related
I'm working on an ios application that has a mix of swift and obj-c code. One of my obj-c model classes defines a struct containing strings to assist in converting to a dictionary and back. I have the bridging header setup and I can access methods defined in my objective-c class in a swift class. What I can't figure out is how to access the static stuct to get at my property strings. Here is a snippet of my .h and .m files:
OrderItem.h
extern const struct OrderItemAttributes {
__unsafe_unretained NSString *created;
__unsafe_unretained NSString *created_by_id;
__unsafe_unretained NSString *device_deleted;
} OrderItemAttributes;
#interface OrderItem : NSManagedObject {}
#property (nonatomic, strong) NSDate* created;
#end
OrderItem.m
const struct OrderItemAttributes OrderItemAttributes = {
.created = #"created",
.created_by_id = #"created_by_id",
.device_deleted = #"device_deleted",
};
#implementation OrderItem
#dynamic created;
#end
I thought I would simply be able to use
OrderItem.OrderItemAttributes.created
to access the attribute strings but swift doesn't accept that syntax. Is there any way to do what I want without major changes to my objective-c code?
The variable OrderItemAttributes isn't part of the OrderItem namespace. It would be accessed directly as:
var foo: NSString = OrderItemAttributes.created.takeUnretainedValue()
The problem you're seeing with autocomplete occurs because OrderItemAttributes is ambiguous; it's both a type name and a variable name. Use different names for the struct type name and the global variable to avoid the ambiguity. E.g., add 'Struct' to the end of the type name:
extern const struct OrderItemAttributesStruct {
__unsafe_unretained NSString *created;
__unsafe_unretained NSString *created_by_id;
__unsafe_unretained NSString *device_deleted;
} OrderItemAttributes;
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.
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.
I've seen 2 ways of creating global variables, what's the difference, and when do you use each?
//.h
extern NSString * const MyConstant;
//.m
NSString * const MyConstant = #"MyConstant";
and
//.h
extern NSString *MyConstant;
//.m
NSString *MyConstant = #"MyConstant";
the former is ideal for constants because the string it points to cannot be changed:
//.h
extern NSString * const MyConstant;
//.m
NSString * const MyConstant = #"MyConstant";
...
MyConstant = #"Bad Stuff"; // << YAY! compiler error
and
//.h
extern NSString *MyConstant;
//.m
NSString *MyConstant = #"MyConstant";
...
MyConstant = #"Bad Stuff"; // << NO compiler error =\
in short, use const (the former) by default. the compiler will let you know if you try to change it down the road - then you can decide if it was a mistake on your behalf, or if the object it points to may change. it's a nice safeguard which saves a lot of bugs/headscratching.
the other variation is for a value:
extern int MyInteger; // << value may be changed anytime
extern const int MyInteger; // << a proper constant
I have Constants NSString, that I want to call like:
[newString isEqualToString:CONSTANT_STRING];
Any wrong code here?
I got this warning:
sending 'const NSString *' to parameter of type 'NSString *' discards qualifiers
How should these be declared?
You should declare your constant string as follows:
NSString * const kSomeConstantString = #""; // constant pointer
instead of:
const NSString * kSomeConstantString = #""; // pointer to constant
// equivalent to
NSString const * kSomeConstantString = #"";
The former is a constant pointer to an NSString object, while the latter is a pointer to a constant NSString object.
Using a NSString * const prevents you from reassigning kSomeConstantString to point to a different NSString object.
The method isEqualToString: expects an argument of type NSString *. If you pass a pointer to a constant string (const NSString *), you are passing something different than it expects.
Besides, NSString objects are already immutable, so making them const NSString is meaningless.
just to put all on one place which found on various post on stackoverflow and works for me , #define is bad because you cannot benefit from variable types, basically the compiler replaces all occurrence when compiles (import Constants.h whenever you need) :
// Constants.h
#import <Foundation/Foundation.h>
#interface Constants : NSObject
extern NSString *APP_STATE_LOGGED_IN;
extern NSString *APP_STATE_LOGGED_OUT;
#end
// Constants.m
#import <Foundation/Foundation.h>
#import "Constants.h"
#implementation Constants
NSString *APP_STATE_LOGGED_IN = #"APP_STATE_LOGGED_IN";
NSString *APP_STATE_LOGGED_OUT = #"APP_STATE_LOGGED_OUT";
#end
spare few minutes to read this. A goodread on pointers hell on constants and vice-versa.
http://c-faq.com/decl/spiral.anderson.html