I'm having issues with dictionary, i want a dictionary create only once to save data to plist file. So how to create singleton dictionary ? Thank in advance
You can create one instance of NSDictionary in AppDelegate, make this dictionary as a public property of class.
#property (nonatomic, strong) NSMutableDictionary *myDict;
Initialize this in - (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions method.
Now access it through out the app -
((AppDelegate *) [UIApplication sharedApplication].delegate).myDict
Only one instance will be created for your use.
As you responded in comments, you need a global variable. Bellow is the receipt.
Here is what you can do:
Add variable extern definition at the top of your AppDelegate.h file:
extern NSMutableDictionary *MyGlobalDictionary;
Add variable definition at the top of your AppDelegate.m file:
NSMutableDictionary *MyGlobalDictionary;
Now you need to initialize the dictionary, can be done in initialize method of you AppDelegate. In AppDelegate.m add this somewhere in #implemetaion of AppDelegate:
+ (void)initialize {
MyGlobalDictionary = [[NSMutableDictionary alloc] init];
}
How to use:
Whenever you need it, just #import your AppDelegate.h file. Bellow is an example how to use:
NSLog(#"%#", [MyGlobalDictionary objectForKey:#"someKey"]);
Important:
While creating singleton is extremely easy it is considered to be a bad practice. Think about passing your dictionary to objects that can be interested in it. Or may be define some global class singleton if it is unavoidable.
Related
I have viewController with a global property 'notesArray", and I want to get it from AppDelegate through singleton.
Here is my appViewController.h
#import <UIKit/UIKit.h>
#interface AppViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
{
NSMutableArray *notesArray;
}
#property (nonatomic, strong) NSMutableArray *notesArray;
+ (AppViewController*)sharedManager;
#end
Here is my AppViewController.m
#implementation AppViewController
#synthesize notesArray;
+ (AppViewController*)sharedManager {
static AppViewController *sharedManager;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedManager = [[self alloc] init];
});
return sharedManager;
}
...
#end
My app works fine, but I need to save it's state in NSUserDefaults, so in AppDelegate/applicationDidEnterBackground: I make
- (void)applicationDidEnterBackground:(UIApplication *)application {
[[NSUserDefaults standardUserDefaults] setObject:[AppViewController sharedManager].notesArray forKey:#"savedNotes"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
But the problem is that [AppViewController sharedManager].notesArray = nil.
I tried to set breakpoint to applicationDidEnterBackground: and all data from [AppViewController sharedManager] = nil.
Few observations:
notesArray is not a global property. It is a property on instances of AppViewController. Now in #2 we see that you intend it to be a singleton, but since ObjC doesn't really have a good way to prevent someone else from creating a second object of this type, are you sure you're not creating a second copy e.g. by creating an object of that type in a XIB? This is probably not your problem (see #3), but I just wanted to cover all the bases.
Your sharedManager method implies that you're seeing AppViewController as a singleton. That's an unusual thing to do with a view controller. Usually you would have several view controllers, and the singleton would be part of the model they share. Even better, you'd just give each view controller a pointer to the model object that has this array, and if you ever need a second list, everything will just work. Also, why is it called "manager"? It's a view controller.
Have you stepped through your code in the debugger to see what is going on? What value does notesArray have while you're trying to use it in applicationDidEnterBackground:? I do not see anywhere in your code that you initialize notesArray. So you just have an empty pointer to an object (i.e. notesArray is likely nil). You probably meant to add an init method to your singleton's class that creates an NSMutableArray instance and remembers its address in notesArray?
I'm very new to Objective C so please bear with me. I have been searching through a lot threads but still couldn't find suitable answer for my case yet I believe this question has been asked over and over. I found a lot of tutorials how to use AppDelegate for sharing string but I can't figure out how to use it to share NSMUtableDictionary.
I want to share one NSMutableDictionary between two classes where I add data to the NSMutableDictionary in one class and read it it another. I'm using AppDelegate class to store the data.
AppDelegate.h
#import <UIKit/UIKit.h>
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (nonatomic,retain) NSMutableDictionary *myArray;
#end
AppDelegate.m
#import "TestResults.h"
#synthesize myArray;
TestResults.h
#interface TestResults : UIViewController {
singletonObj * sobj;
}
TestResults.m
- (void)viewDidLoad
{
[super viewDidLoad];
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSMutableDictionary *myArrayFromAppDelegate = appDelegate.myArray;
[myArrayFromAppDelegate setValue:#"aaa" forKey:#"bbb"];
NSLog(#"%#", myArrayFromAppDelegate);
}
When i do NSLog it return an empty array. Where did I go wrong?
I think you forget to alloc and init in AppDelegate.
In
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
myArray = [[NSMutableDictionary alloc]init];
.
.
[self.window makeKeyAndVisible];
return YES;
}
And you can give your Dictionary name : myDict it is benificial for you.
And by calling this myArray from other ViewController gives you empty NSMutableDictionary.
Oh lordy. This is indeed a VERY common beginner question.
The real answer to the question "How do I share objects in the app delegate" is "dont". It clutters up your app delegate, and makes it do work it was not intended to do. It's like storing your food from your house in your car. It works, but it weighs down the car so it doesn't work as well at it's primary job.
You should design your apps with as little global state as possible.
If you do need to share global state data, don't put it int the app delegate. Instead, create a data container singleton and use that.
You should be able to do a search on [ios] singleton and find lots of examples of creating singletons. A data container singleton is just a singleton that has properties that are used to hold and share data.
Second point:
You have an NSMutableDictionary called myArray. That is a recipe for confusion. Don't use the name of another type (the wrong type) in naming your dictionary. DO NOT DO THS! EVER! If it's not an array, don't call it an array.
Third point:
As others have pointed out, you never alloc/init your dictionary. The alloc/init should take place in the object that owns the dictionary (in your case, AppDelegate, but move it to your data container singleton.) You can ether create it in the owning class's init method, or write a custom getter that "lazy loads" the dictionary:
- (NSDictionary *)myDict;
{
if (!_myDict)
{
myDict = [NSMutableDictionary new];
}
return myDict;
}
Here you may alloc this dict.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.myArray = [NSMutableDictionary dictionary];
.....
}
Otherwise you can do in TestResults.m
NSMutableDictionary *myArrayFromAppDelegate = appDelegate.myArray;
if (!myArrayFromAppDelegate)
appDelegate.myArray = [NSMutableDictionary dictionary];
You can also do this work.
- (void)viewDidLoad
{
[super viewDidLoad];
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
appDelegate.myDictionary=[[NSMutableDictionary alloc]init];////This could be another way
NSMutableDictionary *myDictionaryFromAppDelegate = appDelegate.myDictionary;///Don't name an dictionary by array!!!!!!!
[myDictionaryFromAppDelegate setValue:#"aaa" forKey:#"bbb"];
NSLog(#"%#", myDictionaryFromAppDelegate);
}
Thanks
I have implemented Opencv in one of my project. In an opencv .mm file, I need to access the appdelegate object for global access of an array but it is giving Linker Error all the time (When I am trying to import the AppDelegate Class). So I have created an NSObject Class, still I can not access the Global Array which is created as the #property of the NSObject (I have imported the NSObject class in the .mm file). Array is giving the NULL value.
So where do I create the Array by which I can access the array in my whole project?
I can not use the NSUSerDefaults and DocumentDirectory. Because I want to save a lots of images and video links in that array, So I can not use NSUserDefaults and I don't want to use again the phone memory for the temp file as because I am picking the images from the Photolibrary, so DocumentDirectory is discarded, So Is there any way by which I can create the global array and access them from the openCV files i.e objective CPP files?
you can make class as UserdataSingleton which overrides NSObject. which you can use all over your application to share data globally (for your case array). this code template may help you:
#import <Foundation/Foundation.h>
#interface UserDataSingleton : NSObject
{
#private
NSArray *globalArray;
}
+(UserDataSingleton *) getInstance;
-(void)saveInUserDatasingletonWithArray:(NSArray *)array;
-(NSDictionary *)getGlobalArray;
#end
and implementation file will be some thing like:
#import "UserDataSingleton.h"
#implementation UserDataSingleton
static UserDataSingleton *userDataSingletonInstance;
+(UserDataSingleton *) getInstance
{
if (userDataSingletonInstance == nil) {
userDataSingletonInstance = [[UserDataSingleton alloc] init];
}
return userDataSingletonInstance;
}
-(void)saveInUserDatasingletonWithArray:(NSArray *)array
{
globalArray = array;
}
-(NSDictionary *)getGlobalDictionary
{
return globalArray;
}
#end
================== usage:
#import "UserDataSingleton.h"
#define USERDATASINGLETON (UserDataSingleton *)[UserDataSingleton getInstance]
......................your code...
NSArray *this_IS_Array_Populated_here_For_Global_Access = [NSArray alloc] initWith....];
[USERDATASINGLETON saveInUserDatasingletonWithArray:this_IS_Array_Populated_here_For_Global_Access];//you put your array for global access.
later some where in any other view or view controller you can get that global array for example lets say you have YourViewController class:
NSMutableArray *yourArrayFromWebResponse = [USERDATASINGLETON getGlobalArray];
thanks
Note that Objective C is a superset of C. Thus, you can have regular C variables in your program. My favorite is to make a global variable for my appDelegate. Put this in your app delegate's .h file:
MyAppDelegateClass * appDelegate;
(change "MyAppDelegateClass" to your appDelegate's class name) and put this in application: didFinishLaunchingWithOption: method in your app delegate's .m file:
appDelegate = self; // set universal global variable
Now just #import your app delegate's .h file and have access to your appDelegate from anywhere.
You may try to create a singleton objet like and access it from everywhere
you could define a macro in your delegate like so:
#define sharedAppDelegate ((AppDelegate *)[UIApplication sharedApplication].delegate)
and then in the class which you want to access your array import your AppDelegate class, boiler plate would be:
#import AppDelegate.h
and then just use:
NSArray *arrayYouWanted = [AppDelegate sharedAppDelegate].yourPropertyArrayName;
You can also store it in NSUserDefaults if you want to persist it.
A "token" will be given upon authentication in a form of xml file with some other elements.
I managed to extract the token, and display it in the calling class, let's say parser.m.
However, I need to make the content of that variable available globally, so that I can reuse the same token. How do I do that?
Please note that a different token will be given upon the next authentication.
.h:
#interface Parser : NSObject <NSXMLParserDelegate>{
NSXMLParser *parser;
NSMutableString *element;
NSMutableString *token;}
#property (nonatomic, retain) NSMutableString *token;
#end
.m:
#import "Parser.h"
NSLog(#"tOKEn called from main: %#", parser->token);
It is not able to access the "token" that was declared under parser.m
How do I go around this?
Update 1:
I found out that using #public serves the purpose too. Not sure whether its a good move or not since I will be needing the token in all my API calls.
create a singleton class for global variable in objective c
in .h file
#import <Foundation/Foundation.h>
#interface Singleton : NSObject
{
///......
}
+ (Singleton *)sharedSingleton;
in .m file
#import "Singleton.h"
#implementation Singleton
static Singleton *singletonObj = NULL;
+ (Singleton *)sharedSingleton
{
#synchronized(self)
{
if (singletonObj == NULL)
singletonObj = [[self alloc] init];
}
return(singletonObj);
}
and use this in another file
#import "Singleton.h"
//.....
Singleton *sinObj = [Singleton sharedSingleton];
and create variables inside that and also write setter and getter method for that variable in singleton class. Access this method and variable using sinObj object of singleton class
IMO singletons are a overused curse.
Your (every) application should have a layers structure, and this token variable shouldn't leave communication layer. If it does this means that something is wrong with your application design. Note that token is needed only to do posts and every other part of code doesn't need it.
For temporary variables, consider using a singleton instance, such as the MySingleton class illustrated in this answer. How to create a singleton: What should my Objective-C singleton look like?.
You can access the variable like this: [MySingleton sharedSingleton].variable; Singleton is a good choice if you have a lot of global variables, but if only one better to use NSUserDefaults.
NSUserDefaults are for things that require persistance, i.e. you are planning on storing them between app starts. Good starter: http://mobile.tutsplus.com/tutorials/iphone/nsuserdefaults_iphone-sdk/
Also please read: Are global variables bad?
Try this:
[[NSUserDefaults standardUserDefaults]setObject:_YourObject_ forKey:#"token"];
NSString *str = [[NSUserDefaults standardUserDefaults] stringForKey:#"token"];
Or You can use singleton.
Try to Declare that varible into Appdelegate as a property and syntesize it in .m .
Or aceess that varible in any class using this.
AppDelegate * appdelegate=(AppDelegate *)[[UIApplication sharedApplication]delegate];
AppDelegate.yourvarible;
or either you used NSUserDefault.
[[NSUserDefaults standardUserDefaults]setObject:token forKey:#"tokan"];
You can create a property in ur appdelegate and set the property when u get the token.
//getter
NSString *token=[(MyAppDelegate *)[[UIApplication sharedApplication] delegate].recievedToken;
//setter
[(MyAppDelegate *)[[UIApplication sharedApplication] delegate].recievedToken=token;
I used to declare variale in appdelegate and make it as sharable in all the classes (If the variable is global ) .
appDelegate = (StoryAppDelegate*)[[UIApplication sharedApplication]delegate];
this was the code am using normally to access appdelegate variable. Now am trying a story board application and its not working for me . while declaring appdelegate it shows an error "Unknown type name StoryAppDelegate".
StoryAppDelegate*ss;
this is the code am using .
Any help appreciated .
Just don't use the app delegate. That isn't what it's for.
Instead, create a specific class to own the responsibility + knowledge, make it a singleton and have all classes that require it get it via it's 'sharedController' (or whatever you call it) class method.
Or use a 'constants' file with a static variable or something (just not the app delegate).
Storyboard is used only for design, not changes to the code.
For that, you'd use:
AppDelegate *app;
in the header file of the view's controller.
And in the implementation file,
app=(AppDelegate *)[[UIApplication sharedApplication]delegate];
Then you can just use app.yourVariable
I would recommend using a singleton instance of your global variable as they have bailed me out of your exact situation multiple times. Here is an example I'm currently using to implement a singleton. This methodology is also ARC-safe as well
mySingleton.h
#import <Foundation/Foundation.h>
#interface mySingleton : NSObject {
}
+ (NSMutableDictionary *) myMutableDict;
#end
mySingleton.m
#import "mySingleton.h"
#implementation mySingleton
+ (NSMutableDictionary *)myMutableDict
{
static NSMutableDictionary *singletonInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
singletonInstance = [[NSMutableDictionary alloc]init];
});
return singletonInstance;
}
#end
As long as you include mySingleton.h in all of your view controllers you can access the data via [mySingleton myMutableDict]. For example: [[mySingleton myMutableDict] setObject:myObject forKey:myKey]; This will of course work with any object type.
It seems the case of circular dependency.
use #class StoryAppDelegate;
instead of
#import "StoryAppDelegate.h"
in your header file.