I want store a number as a global variable. What syntax do I use, and how can other parts of my application access that variable?
For a standard global variable (not persistent when the app is terminated and restarted) add this to a header file (*.h) of your choice:
extern NSInteger MYGlobalVariable;
Then put this in the implementation file; (*.m, *.c, *.cpp):
MYGlobalVariable = 0; // Or any other default value.
That is how you do a bread and butter global variable.
You probably want to use NSUserDefaults for this :
From anywhere in your code, you can set a value for a key :
int userAge = 21; // Just an example
NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];
if (standardUserDefaults) {
[standardUserDefaults setObject:[NSNumber numberWithInt:userAge] forKey:#"age"];
[standardUserDefaults synchronize];
}
And get it back from any other place :
NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];
NSNumber *age = nil;
if (standardUserDefaults)
age = [standardUserDefaults objectForKey:#"age"];
userAge = [age intValue]
You can also set an initial value :
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSDictionary *appDefaults = [NSDictionary
dictionaryWithObject:[NSNumber numberWithInt:13] forKey:#"age"];
[defaults registerDefaults:appDefaults];
Also, if you have complex data, you may want to create a wrapper class with setters and getters.
Define the variable in AppDelegate.h file. Create a property in .h file
#property (retain, nonatomic) NSString *str;
Then synthesize in AppDelegate.m file;
#synthesize str;
Later define a variable in you project prefix.pch file
#define DELEGATE ((AppDelegate*)[[UIApplication sharedApplication]delegate])
Use the value anywhere in your project
AppDelegate *a = DELEGATE;
a.str = #"value";
NSLog(#"value of variable str : %#",a.str);
To make a Variables that can be seen by the whole files in Objective c
for example you want to set your base url one time and in each class you append on it some extra strings,
go to main.m file, because this is the place the whole app will see it.
then outside main function, put your base url
NSString *baseurl = #"staging.nabdanet.com";
int main(int argc, char * argv[])
{
#autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
and when you want to access these class, all what you will do is this,
SomeClass.m
extern NSString *baseurl;
with the same name in both ;)
For persistent vars, use NSUserDefaults. This gets written on a file in the app sandbox.
For session vars (non-persistent), I use a singleton class with an NSMutableDictionary property to store variables.
To declare a global variable in either objective-C or Swift, you simply declare it outside the scope of any class/interface.
Objective-C:
#import "headerFile1.h"
#import "headerFile2.h"
BOOL isTrue = true;
int x = 1;
#interface exampleInterface (){
...
}
#end
#implementation exampleClass
...
isTrue= false; // can be used in the same way anyplace in your code
x=3; // anyplace means anyplace, even from other controllers
#end
Swift:
import UIKit
var x=45;
class SomeClass {
...
x=0; // This is also available from anyplace in your project
...
}
Related
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'm trying to get the name of an instance variable from an Objective-C class. Say I have a class that looks like this:
#interface MyClass : NSObject
#property (nonatomic, copy) NSSNumber *myVar;
#end
Given myVar, I want to get "myVar". Then I could use it in a log like this:
MyClass *myObject = [[myClass alloc] init];
NSLog(#"The variable is named: %#", getVarName([myObject myVar]));
Then the log would say: The variable is named myVar. Thank you for your help!
PS The reason I want to do this is to create a method for encoding variables for archiving. So when I write my encodeWithCoder method I can just do something like this:
- (void)encodeWithCoder:(NSCoder *)aCoder
{
NSArray *varsForEncoding = [[NSArray alloc] initWithObjects:var1, var2, var3, nil];
for (NSObject *var in varsForEncoding)
{
[aCoder encodeObject:var forKey:getVarName(var)];
}
}
Then do the reverse in initWithCoder. That would prevent typos screwing this up, e.g. using key #"myVar" when encoding but typing #"mVar" in the initializer.
You can try with this method:
//returns nil if property is not found
-(NSString *)propertyName:(id)property {
unsigned int numIvars = 0;
NSString *key=nil;
Ivar * ivars = class_copyIvarList([self class], &numIvars);
for(int i = 0; i < numIvars; i++) {
Ivar thisIvar = ivars[i];
if ((object_getIvar(self, thisIvar) == property)) {
key = [NSString stringWithUTF8String:ivar_getName(thisIvar)];
break;
}
}
free(ivars);
return key;
}
(source)
Just use a single line of code as this.
#define NSLogVariable(x) NSLog( #"Variable : %s = %#",#x,x)
define it along with the headers as a macro and use it anywhere.
eg:
NSString *myObj=#"abcd";
NSLogVariable(myObj);
it will display
Variable : myObj = "abcd"
Hope it help some one.
I have the following class in my iOS application (it is like an abstract class from the Java world).
#implementation WSObject
static NSDictionary* _dictionary = nil;
+(NSDictionary*) dictionary {
if (_dictionary == nil) {
_dictionary = [NSKeyedUnarchiver unarchiveObjectWithFile:[self localStorePath]];
}
return _dictionary;
}
...
#end
I then have multiple classes which implement this above WSObject with the class method dictionary. The problem is, that each of these classes should have their own _dictionary, but they are all sharing the same object from the super class. I could, of course, copy to all the subclasses, but that would break the reusability. Besides this getter, there are other class methods in WSObject which mutate the dictionary. Because of this, there would be a several class methods which should be in every subclass.
How can I solve this in a smart way? Please tell me if my description is insufficient.
Associative references seem like they'll do the trick. You can essentially tack some storage on to the class object itself. (I'm using NSStrings here, in place of the dictionaries you want to use, just for demonstration.)
Superclass:
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#interface Stuper : NSObject
// Accessor method for the "class variable"
+ (NSString *) str;
// Analog to your +localStorePath
+ (NSString *) quote;
#end
#import "Stuper.h"
// The doc suggests simply using the address of a static variable as the key.
// This works fine, even though every class is (as in your problem) using
// the same key, because we are associating to a different class each time.
static char key;
#implementation Stuper
+ (NSString *) str {
NSString * s = objc_getAssociatedObject(self, &key);
if( !s ){
s = [self quote];
// You'll probably want to use OBJC_ASSOCIATION_RETAIN for your dictionary.
// self inside a class method is the class object; use that as
// the associator. The string is now tied to the associator, i.e.,
// has the same lifetime.
objc_setAssociatedObject(self, &key, s, OBJC_ASSOCIATION_COPY);
}
return s;
}
+ (NSString *) quote {
return #"It was the best of times, it was the worst of times.";
}
#end
Subclass:
#import "Stuper.h"
#interface Stub : Stuper #end
#import "Stub.h"
#implementation Stub
+ (NSString *) quote {
return #"Call me Ishmael.";
}
#end
Trying this out:
#import <Foundation/Foundation.h>
#import "Stuper.h"
#import "Stub.h"
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSLog(#"%#", [Stuper str]);
NSLog(#"%#", [Stub str]);
[pool drain];
return 0;
}
Each class object now has its own string, associated with it.
2011-12-05 23:11:09.031 SubClassVariables[36254:903] It was the best of times, it was the worst of times.
2011-12-05 23:11:09.034 SubClassVariables[36254:903] Call me Ishmael.
The only downside here is that you'll have to call the accessor method every time you want the object; you don't have a pointer you can use directly. You can call objc_getAssociatedObject in the superclass as an accessor, too, of course, since it has access to key.
In order to give each subclass its own dictionary, store a second dictionary object in your primary dictionary using the class name as the key. For example:
static NSMutableDictionary *_dictionary = nil;
+ (NSDictionary*)dictionary
{
if (_dictionary == nil)
_dictionary = [[NSKeyedUnarchiver unarchiveObjectWithFile:[self localStorePath]] mutableCopy];
NSString *key = NSStringFromClass( [self class] );
if ( [_dictionary objectForKey:key] == nil )
[_dictionary setObject:[NSMutableDictionary dictionary] forKey:key];
return [_dictionary objectForKey:key];
}
Perhaps you can return a copy of the dictionary
#implementation WSObject
static NSDictionary* _dictionary = nil;
+(NSDictionary*) dictionary {
if (_dictionary == nil) {
_dictionary = [NSKeyedUnarchiver unarchiveObjectWithFile:[self localStorePath]];
}
return [_dictionary copy];
}
...
#end
Keep in mind that if you modify _dictionary you will get a copy of that modified dictionary which may differ from what is on disk.
How often is this being called? is it really necessary to cache the file contents in this static _dictionary object?
Why not just fetch it every time form disk, assuming it isn't too often that performance comes into question.
#implementation WSObject
+(NSDictionary*) dictionary {
return [NSKeyedUnarchiver unarchiveObjectWithFile:[self localStorePath]];
}
...
#end
I'm pretty new to cocoa and Xcode, I've done some basic C coding, but I pretty much suck at objective-c and cocoa, so please excuse me for any stupid mistakes I make. My problem is with these global variables I'm using.
I have a global NSString variable declared in the header file, and it's used in the main file like so:
//AppController.h
-(IBAction)button1:(id)sender;
-(IBAction)button2:(id)sender;
extern NSString *hi
//AppController.m
-(IBAction)button1:(id)sender
{
NSString *const hi = #"Hello";
}
-(IBAction)button2:(id)sender;
{
NSLog (#"%#", hi);
}
However when I click run the build fails and I get the error message:
"_hi", referenced from:
Some extra info:
Undefined symbols for architecture x86_64: "_hi", referenced from: -[AppController gallery:] in AppController.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
If you know what this means and/or how to fix it please help me. Thanks
You need to provide a global definition for hi. Move your declaration:
NSString *const hi = #"Hello";
to someplace outside of any method. I'm not really sure what you want button1: to do, but it doesn't seem necessary at all for your implementation.
I assume Luke likes to:
Set the string to a specific value after button one is clicked,
and retrieve it again after button two is clicked.
AppController.h
#import <Cocoa/Cocoa.h>
#interface AppController : NSObject{
NSString * string;
}
-(IBAction)button1:(id)sender;
-(IBAction)button2:(id)sender;
#end
AppController.m
#import "AppController.h"
#implementation AppController
-(IBAction)button1:(id)sender
{
string = #"Hello";
}
-(IBAction)button2:(id)sender;
{
NSLog (#"%#", string);
}
#end
When defining global variables and constant strings, etc., this is usually how I do it:
MDAppController.h:
#import <Cocoa/Cocoa.h>
extern NSString * const MDShouldShowInspectorKey;
extern NSString * const MDShouldShowViewOptionsKey;
extern BOOL MDShouldShowInspector;
extern BOOL MDShouldShowViewOptions;
#interface MDAppController : NSObject <NSApplicationDelegate> {
IBOutlet NSWindow *window;
}
- (IBAction)hideInspector:(id)sender;
#end
MDAppController.m:
#import "MDAppController.h"
NSString * const MDShouldShowInspectorKey = #"MDShouldShowInspector";
NSString * const MDShouldShowViewOptionsKey = #"MDShouldShowViewOptions";
BOOL MDShouldShowInspector = NO; // default value
BOOL MDShouldShowViewOptions = YES; // default value
#implementation MDAppController
+ (void)initialize {
NSMutableDictionary *defaultValues = [NSMutableDictionary dictionary];
[defaultValues setObject:
[NSNumber numberWithBool:MDShouldShowInspector]
forKey:MDShouldShowInspectorKey];
[defaultValues setObject:
[NSNumber numberWithBool:MDShouldShowViewOptions]
forKey:MDShouldShowViewOptionsKey];
[[NSUserDefaults standardUserDefaults] registerDefaults:defaultValues];
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
NSUserDefaults *uD = [NSUserDefaults standardUserDefaults];
MDShouldShowInspector = [[uD objectForKey:MDShouldShowInspectorKey] boolValue];
MDShouldShowViewOptions = [[uD objectForKey:MDShouldShowViewOptionsKey] boolValue];
}
- (IBAction)hideInspector:(id)sender {
NSLog(#"MDShouldShowViewOptionsKey == %#", MDShouldShowViewOptionsKey);
MDShouldShowInspector = NO;
[[NSUserDefaults standardUserDefaults]
setObject:[NSNumber numberWithBool:MDShouldShowInspector]
forKey:MDShouldShowInspectorKey];
}
#end
My question is why do you want to be extern? The best way here is to create a singleton, you should have all members as part of a class and avoid any global.
Hope this helps