hi i am new to ios dev ,I am trying to set a value for nsstring from delegate class and access from other class ,the value i get is null.i dont know what mistake i am doing?
//token class header file
#interface TokenClass : NSObject
{
NSString *tokenValue;
}
#property (nonatomic,strong) NSString *tokenValue;
//token class main file
#implementation TokenClass
#synthesize tokenValue;
#end
//App Delegate
TokenClass *token = [[TokenClass alloc]init];
[token setTokenValue:#"as"];
when i access tokenvalue in some other classs i get null value.
can any one point me what mistake i am doing?Am i using # property correctly?
There are a lot of ways to achieve what you want:
1. Usually I am using NSUserDefaults to save small amount of data which I will need even the user closed the app. There are a lot of information how to use it. See my answer here.
2. In your UIViewController class (e.x. your rootViewController) create #property which will hold your TokenClass. Then you will get tokenValue by self.tokenClass.tokenValue
3. The other way is create a singleton class which will be available during the whole run loop of your application. A Singleton candidate must satisfy three requirements:
controls concurrent access to a shared resource.
access to the resource will be requested from multiple, disparate
parts of the system.
there can be only one object.
+(TokenClass*) sharedTokenClass {
static dispatch_once_t pred;
static TokenClass *_sharedTokenClass = nil;
dispatch_once(&pred, ^{
_sharedTokenClass = [[TokenClass alloc] init];
});
return _sharedTokenClass;
}
You will use it it from any place you want by
[TokenClass sharedTokenClass]tokenValue];
If I were you, I would use the first variant.
PS. I strongly recommend you to read some memory management articles to get the point of object's lifecycle.
You need to use Singleton class to expose variables or objects to the entire project or create global variables. Create sharedInstance of TokenClass class and create property which can be accessed anywhere
in your .h file
//token class header file
#interface TokenClass : NSObject
#property (nonatomic,strong) NSString *tokenValue;
//create static method
+ (id)sharedInstance;
in .m file
#import "TokenClass.h"
#implementation TokenClass
#pragma mark Singleton Methods
+ (id)sharedInstance {
static TokenClass *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
- (id)init {
if (self = [super init]) {
tokenValue = [[NSString alloc] init];
}
return self;
}
#end
now in your appDelegate
#import TokenClass.h
#implementation AppDelegate
in `didFinishLaunchingWithOptions:`
[TokenClass sharedInstance] setTokenValue:#"as"];
in any class you can get value using
NSLog(#"tokenValue = %#", [[SingletonClass sharedInstance] tokenValue]);
Related
This question already has an answer here:
What is the use of Singleton class in objective-c? [duplicate]
(1 answer)
Closed 7 years ago.
I am new to iOS development and I have gone through singleton class. I understood the concept, but having doubts in implementing the singleton class. Can anyone please share source code of the real time example using singleton class.
This is how a GCD for singleton class looks like.
Suppose there is a class that you made, MySingleTonClass which is a subclass of NSObject
MySingleTonClass.h
+(instanceType)sharedManager;
#property (nonatomic, strong) NSString *userName;
MySingleTonClass.m
+(instanceType)sharedManager{
static MySingleTonClass *manager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
manager = [[MySingleTonClass alloc]init];
});
return manager;
}
Now you call this singleTon Class in some other class suppose in ViewController.m. First Import the Class
#import MySingleTonClass.h
-(void)viewDidLoad{
MySingleTonClass *manager = [MySingleTonClass sharedManager];
manager.userName = #"ABCDE";
//manager is the singleton Object
}
Edit
Now suppose you want to access this same value. then suppose in some other ViewController, after ViewController
Suppose in SecondViewController.m
#import "MySingleTonClass.h"
-(void)viewDidLoad{
MySingleTonClass *manager = [MySingleTonClass sharedManager];
NSLog (#"%#",manager.userName);
// This would still log ABCDE, coz you assigned it the class before, So even if you create a new object called manager here, it will return the same Manager you created before.
manager.userName = #"Myname"; //Now the value changed to MyName untill you change it again, in the lifetime of this application.
}
I hope i could make you understand the concept of it.
As you know, dispatch_once_t is a GCD snippet that makes the code inside of it invoke only ONCE per application run. Any code you write inside it will be run, or rather invoked only once in the lifetime of the application being active.
Check out this link for the original source - http://getsetgames.com/2009/08/30/the-objective-c-singleton/
#implementation MySingleton
static MySingleton* _sharedMySingleton = nil;
+(MySingleton*)sharedMySingleton
{
#synchronized([MySingleton class])
{
if (!_sharedMySingleton)
[[self alloc] init];
return _sharedMySingleton;
}
return nil;
}
static User *defaultUser;
+ (User *)defaultUser
{
if (!defaultUser)
{
defaultUser = [self new];
// do something...
}
return defaultUser;
}
There are two ways:-
1) We can create singleton class using **GCD** dispatch_once
in this only one object will create if existing object is there then it will refer to them.
+(id)sharedManager
{
static MyManager *sharedMyManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedMyManager = [[self alloc] init];
});
return sharedMyManager;
}
2) Second way is follows:-
+ (id)sharedManager {
static MyManager *sharedMyManager = nil;
#synchronized(self) {
if (sharedMyManager == nil)
sharedMyManager = [[self alloc] init];
}
return sharedMyManager;
}
suppose this above method is written in class **MyManager** then u can use that as follow
MyManager *sharedManager = [MyManager sharedManager];
hope this will help u.
In my app, when the user launched the app, I create an instance of a class in my AppDelegate and call a method in the class which compares all of the user's iOS contacts to find which ones are using my app, and puts those contacts into an NSMutableArray
AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
...
GetContactClass *contact = [[GetContactClass alloc] init];
[contact getAllContacts];
...
}
GetContactClass.h
#property (retain, nonatomic) NSMutableArray *appContacts;
At the end of the getAllContacts method, I NSLog out appContacts and it works fine.
However, later in the app I try to set an NSMutableArray in a ViewController to equal appContacts, but I get a (null) array.
ViewController.m
self.searchableContacts = [[NSMutableArray alloc] init];
GetContactClass *contact = [[GetContactClass alloc] init];
self.searchableContacts = contact.appContacts;
What am I doing wrong here?
You're creating an entirely new instance which hasn't been asked to collect all contacts, so it hasn't stored them. By the look of the code the instance which has stored them has been destroyed. As you're running this on the main thread you might as well just ask the new instance to get contacts and delete the code for the old one. It's better however to run the contacts collection on a background thread and keep the result till you need it, in a retained instance variable.
If you want use this data in all app you must use a Pattern Design Singleton:
In objective-c:
#implementation Settings
+ (id)sharedInstance {
static Settings *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
Other way is change retain to strong but this is a bad idea and put this property in appDelegate and call all times APPDelegate get property.
Ok, strange thing occurred and I guess answer is quite simple, but I fail to figure out what's going on.
Situation is next:
I have an NSObject class called Constants.
Constants.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <GooglePlus/GooglePlus.h>
#interface Constants : NSObject
+(Constants*)shared;
#property GTLPlusPerson* googlePlusUser;
#property int profileType;
#property NSString *userName, *userLastName, *userEmail, *userGoogleId,*userProfilePicture;
#end
Constants.m
#import "Constants.h"
#implementation Constants
#synthesize profileType, userProfilePicture, userLastName,userName,userGoogleId,userEmail;
static Constants *constants = nil;
+ (Constants*)shared {
if (nil == constants) {
constants = [[Constants alloc] init];
}
return constants;
}
I use this class in order to save some static variables that I will use throughout the app.
Now, If I try and declare one of the variables like
[Constants shared].userName = #"name";
from an NSObject class method (Which I call from a ViewController), I fail to do so.
But If I declare Constant variables directly from ViewController (after viewDidLoad for example) everything works fine.
Here is the Class I try to declare variables from, but I fail (It also has singleton in it, that might be the source of the problem, but im not sure why would it)
#implementation GoogleLogin
static GoogleLogin* gLogin = nil;
+(GoogleLogin*)shared
{
if (nil == gLogin){
gLogin = [[[self class]alloc]init];
}
return gLogin;
}
-(void)getProfile
{
GTLServicePlus* plusService = [[GTLServicePlus alloc] init];
plusService.retryEnabled = YES;
[plusService setAuthorizer:[GPPSignIn sharedInstance].authentication];
GTLQueryPlus *query = [GTLQueryPlus queryForPeopleGetWithUserId:#"me"];
plusService.apiVersion=#"v1";
[plusService executeQuery:query
completionHandler:^(GTLServiceTicket *ticket,
GTLPlusPerson *person,
NSError *error) {
if (error){
NSLog(#"Error while fetching user profile: %#", error);
}else{
NSLog(#"User profile information fetched OK");
[Constants shared].googlePlusUser = person;
[Constants shared].profileType = 1;
[Constants shared].userName = person.name.givenName;
[Constants shared].userLastName = person.name.familyName;
[Constants shared].userEmail = [GPPSignIn sharedInstance].authentication.userEmail;
[Constants shared].userGoogleId = person.identifier;
[Constants shared].userProfilePicture = person.image.url;
NSLog(#"%# %# %# %# %# ",person.name.givenName,person.name.familyName,[GPPSignIn sharedInstance].authentication.userEmail,person.identifier,person.image.url);
}
}];
}
and this is how I call those methods, from my ViewController:
- (IBAction)signupWithGoogle:(UIButton *)sender {
//if i call this method here, on button click, it will finish all the steps needed, except setting constant variables
[[GoogleLogin shared] googleLoginFromViewController:self];
//if I uncomment next line, username will be declared and I will be able to access it later
//[Constants shared].userName = #"Petar";
}
Can anybody figure out why is this happening and what should I do to change that?
When you define a property is strongly suggested to declare the attributes to use with it. I guess the compiler should complain about this with a message like
No 'assign', 'retain', or 'copy' attribute is specified - 'assign' is
assumed
So, use the following instead (copy semantics is fine for mutable classes).
#property (nonatomic, copy) NSString *myString;
You should also specify if the property should be accessed in a atomic or nonatomic way. If you don't specify it, the former will be applied.
Then, you are using a singleton pattern. The suggested way is to use GCD like so.
+ (ConstantsManager*)sharedManager {
static ConstantsManager *sharedManager;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedManager = [[[self class] alloc] init];
});
return sharedManager;
}
Well you did not set your property attributes on the singleton class.
For example,
#property (nonatomic, strong, readonly) ...
Have you tried moving the property assignments out of the completionHandler? It may be that your properties are being assigned on a background thread and your view controller is not catching the assignment. An easy way to check is to override the setters and getters and put breakpoints in them to see what order they are being accessed.
1) Remove the #synthesize because it's not needed (properties will be synthesized as _property automatically)
2) Override setter & getter
-(void)setProfileType:(NSInteger)profileType {
_profileType = profileType;
}
-(NSInteger)profileType {
return _profileType;
}
3) Place breakpoints within these methods and see if the getter is being called before the setter. Alternatively, if simply moving the assignments out of the completionHandler fixes it you know you have some concurrency issues.
I suggest reading up on atomic/nonatomic properties, #synthesize and Objective-C concurrency.
I'm looking for a good way to let each developer have a different config (e.g. server URLs, config flags) that works well with Objective-C and git and supports a default config. One idea is to have two plist files: one checked into git with all the defaults and one that is not checked in and contains custom overrides.
It'd be nice to have more flexibility than a static plist so I started thinking about conditionally loaded classes. Like:
+ (NSDictionary *)config
{
NSMutableDictionary *defaults = ...;
# if DeveloperConfig.h+m exist
// DeveloperConfig can run arbitrary code to override fields
[defaults addEntriesFromDictionary: [DeveloperConfig config]];
# endif
return defaults;
}
Is there a recommended solution for this kind of per-dev configuration?
I will do this way that MyConfigManager does not depends on anything. +[load] is used to register configs which will be called by runtime on startup.
#implementation MyConfigManager
static NSMutableDictionary *defaults;
+ (NSMutableDictionary *)mutableDefaults
{
static dispatch_once_t pred;
dispatch_once(&pred, ^{
defaults = [[NSMutableDictionary alloc] init];
});
return defaults;
}
+ (void)addDefaults:(NSDictionary *)dict
{
[[self mutableDefautls] addEntriesFromDictionary:dict];
}
+ (NSDictionary *)config
{
return [self mutableDefaults];
}
#end
#implementation DeveloperConfig
+ (void)load
{
[MyConfigManager addDefaults:#{#"key":#"value"}];
}
#end
you don't even need a new class because load is called for every categories
#interface MyConfigManager (DeveloperConfig)
#end
#implementation MyConfigManager (DeveloperConfig)
+ (void)load
{
[self addDefaults:#{#"key":#"value"}];
}
#end
I have a problem with an singleton pattern.
I have read the following tutorials about singleton classes and have created my own.
http://www.galloway.me.uk/utorials/singleton-classes/
http://www.johnwordsworth.com/2010/04/iphone-code-snippet-the-singleton-pattern/
The first time i build & run the app it works like it should. No problems at all!
But when i rebuild the app the singleton class does not work properly anymore. The first init works like it should but when i call it again after a button click it crashes my app.
My singleton class:
BPManager.h
#interface BPManager : NSObject {
NSString *dbPath;
}
#property (nonatomic, retain) NSString *dbPath;
+ (id)bpManager;
- (void)initDatabase:(NSString *)dbName;
- (int)getQuestions;
#end
BPManager.m
static BPManager *sharedMyManager = nil;
#implementation BPManager
#synthesize dbPath;
- (void)initDatabase:(NSString *)dbName
{
dbPath = dbName;
}
-(int)getQuestions
{
NSLog(#"getQuestions");
}
- (id)init {
if ((self = [super init])) {
}
return self;
}
+ (BPManager *) bpManager {
#synchronized(self) {
if(sharedMyManager != nil) return sharedMyManager;
static dispatch_once_t pred; // Lock
dispatch_once(&pred, ^{ // This code is called at most once per app
sharedMyManager = [[BPManager alloc] init];
});
}
return sharedMyManager;
}
- (void)dealloc {
[dbPath release];
[super dealloc];
}
When i call the following code when building my interface, the app creates the singleton:
BPManager *manager = [BPManager bpManager];
[manager initDatabase:#"database.db"];
Note: At this point i can create references to the class from other files as well. But when i click on a button it seems to loose his references.
But when a button is clicked, the following code is ecexuted:
BPManager *manager = [BPManager bpManager];
int count = [manager getQuestions];
The app should get the sharedInstance. That works, only the parameters (like dbPath) are not accessible. Why is that?
Edit:
after some research, i have changed the method to:
+ (BPManager *) bpManager {
#synchronized(self) {
if(sharedMyManager != nil) return sharedMyManager;
static dispatch_once_t pred; // Lock
dispatch_once(&pred, ^{ // This code is called at most once per app
sharedMyManager = [[BPManager alloc] init];
});
}
return sharedMyManager;
}
But the problem is not solved
How about
#interface BPManager : NSObject
#property (nonatomic, copy) NSString *dbName;
#property (nonatomic, assign) int questions;
-(id) initWithDBName:(NSString*) dbName {
#end
#import "BPManager.h"
#implementation BPManager
#synthesize dbName=_dbName, questions;
+(BPManager *)singleton {
static dispatch_once_t pred;
static BPManager *shared = nil;
dispatch_once(&pred, ^{
shared = [[BPManager alloc] initWithDBName:#"database.db"];
});
return shared;
}
-(id) initWithDBName:(NSString*) dbName {
self = [super init]
if (self) self.dbName = dbName;
return self;
}
-(void)dealloc {
[_dbName release];
[super dealloc];
}
#end
BPManager *manager = [BPManager singleton];
int count = [manager questions];
The static is private to the implementation file but no reason it should be even accessible outside the singleton method. The init overrides the default implementation with the default implementation so it's useless. In Objective-C you name the getter with the var name (count), not getCount. Initializing a class twice causes an undefined behaviour. No need to synchronize or check for if==nil when you are already using dispatch_once, see Care and Feeding of Singletons. NSString should always use copy instead retain in #property. You don't need the dealloc because this is going to be active forever while your app is running, but it's just there in case you want to use this class as a non singleton . And you probably are as good with this class being an ivar in your delegate instead a singleton, but you can have it both ways.
I'm not sure whether it's the (complete) answer, but one major flaw is that you're using instance variables (self, super) in a class method, +(id)bpManager; I'm actually surprised it let you compile that at all. Change the #synchronized(self) to #synchronized(sharedMyManager), and the [[super alloc...] init] to [[BPManager alloc...] init]. And, writing that just made me realize that the problem looks like accessing a subclassed method on an object instantiated as the superclass, but that should have been overwritten in the dispatch. Shouldn't you really only need one of those anyway, why double-init like that? (And while we're there, that's a memory leak - init'd in the if() and then overwritten in the closure without releasing it.)
The solution of Jano must work well. I use this way too to create singleton object. And I don't have any problem.
For your code, I think that if you use #synchronized (it's not necessary cause your have dispatch_once_t as Jano said), you should not call return in #synchronized.
+ (BPManager *) bpManager {
#synchronized(self) {
if(sharedMyManager == nil) {
static dispatch_once_t pred; // Lock
dispatch_once(&pred, ^{ // This code is called at most once per app
sharedMyManager = [[BPManager alloc] init];
});
}
}
return sharedMyManager;
}