Initialise Singelton once in class? [duplicate] - iphone

This question already has answers here:
What should my Objective-C singleton look like? [closed]
(26 answers)
Closed 8 years ago.
I am doing the following in order to initialise my singelton:
ChatDataController *box = [ChatDataController sharedInstance];
The problem is that i use *box in different places, for example in these methods:
- (void) viewDidAppear:(BOOL)animated
- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
Is there a way to only have to initialise once? so that *box can be used in any method within a given class?

Put this code in your ChatDataController
+ (ChatDataController *)sharedInstance
{
static ChatDataController *object = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
object = [[ChatDataController alloc] init];
});
return object;
}

Is there a way to only have to initialise once?
If ChatDataController is a singleton it can only be initialised once.
[ChatDataController sharedInstance] should always return the same instance and only alloc] init] the first time it is called.
If, as you mentioned in one of the comments, you already have your singleton, then simply call [ChatDataController sharedInstance] whenever you need the shared instance. There is no need to store the pointer to the object in a property.

https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CocoaFundamentals/CocoaObjects/CocoaObjects.html
In "Creating a Singleton Instance"
static MyGizmoClass *sharedGizmoManager = nil;
+ (MyGizmoClass*)sharedManager
{
if (sharedGizmoManager == nil) {
sharedGizmoManager = [[super allocWithZone:NULL] init];
}
return sharedGizmoManager;
}

try this one:- create macro in .pch file
first import class
#import"ChatDataController.h"
then create macro
(sharedInstance must be class method)
#define box ([ChatDataController sharedInstance])
after that u you can use this object in all classes

Related

Overriding alloc init for singleton class [duplicate]

This question already has answers here:
How to properly implement ARC compatible and `alloc init` safe Singleton class? [duplicate]
(3 answers)
Closed 8 years ago.
I am writing some singleton class in my framework and I do not want other developer to call init and alloc on those singleton classes so I have override those methods but since I am using ARC, so my code for singleton class is:
+(MFSingletonClass*) sharedInstance
{
static dispatch_once_t pred = 0;
dispatch_once(&pred, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
and following are alloc and init methods:
+ (id)alloc {
static dispatch_once_t pred = 0;
dispatch_once(&pred, ^{
sharedInstance = [super alloc];
});
return sharedInstance;
}
- (id)init {
__weak typeof(self) weakSelf = self;
static dispatch_once_t pred = 0;
dispatch_once(&pred, ^{
static BOOL init = NO;
if (!init) {
init = YES;
typeof(self) strongSelf = weakSelf;
strongSelf = [super init];
}
});
return weakSelf;
}
I wanted to know whether my implementation of alloc and init method is proper or not?
Thanks in advance!
You ask whether your "implementation of alloc and init method is proper or not?"
Depends on how you define "proper"...
Your code is not incorrect as far as it goes, in that it usually does work, but the init is, let's say, over-cautious and a little incorrect, and there is a trick or two you missed.
Looking at the init you double up checking whether the initialisation has been run:
dispatch_once; and
a BOOL flag init.
The block passed to dispatch_once will be executed at most once, and at that time init will be NO. Overkill. Removing that you get:
- (id)init
{
__weak typeof(self) weakSelf = self;
static dispatch_once_t pred = 0;
dispatch_once(&pred,
^{
typeof(self) strongSelf = weakSelf;
strongSelf = [super init];
});
return weakSelf;
}
Now consider [super init], this is a method call on the current instance, that is though it is not explicit this expression references self. Given that your efforts to avoid a retain cycle are wasted. Furthermore in those efforts you assigned the result of [super init] to a block-local variable strongSelf while init returns weakSelf - this is the reason for the "usually does work" remark above, most calls to [super init] do actually return the same object, but the need not. If we remove the use of weak references we solve both these issues at once:
- (id)init
{
static dispatch_once_t pred = 0;
dispatch_once(&pred,
^{
self = [super init];
});
return self;
}
Bot doesn't this leave us with a retain cycle? No, the object referenced by self does not keep a reference to the block, so the block having a reference back to the object doesn't matter.
The "as far as it goes" remark above
The default alloc method just calls allocWithZone:, the latter takes a memory zone - something which is no longer used but exists for historical reasons. Therefore you should really implement allocWithZone: rather than alloc to catch all allocations - the code would follow the same algorithm as your alloc.
Then there is the copy and copyWithZone: pair. If you want a singleton you don't copies of it, so you should implement copyWithZone: (which copy just calls as will alloc/allocWithZone:) and return self:
- (id) copyWithZone:(NSZone *)zone
{
return self;
}
The missed trick
So your code works as far as it goes, apart from the case where [super init] returns a different object, but was overcomplicated; clean up init to address that.
However if you dig up Apple's now deprecated Cocoa Objects documentation you'll find Apple's old recommendation for producing a true singleton. Under ARC you can ignore the MRC overrides, and you can add the use of GCD as you have done to ensure concurrent correctness, and that will leave you with one trick: Apple implement allocWithZone: by calling sharedManager (your sharedInstance) and having that in turn call allocWithZone on super. With your code that would be:
+ (MFSingletonClass*) sharedInstance
{
static MFSingletonClass *sharedInstance = nil;
static dispatch_once_t pred = 0;
dispatch_once(&pred,
^{
sharedInstance = [[super allocWithZone:NULL] init];
});
return sharedInstance;
}
+ (id)allocWithZone:(NSZone *)ignore
{
return [self sharedInstance];
}
Which is a little cleaner, but your approach works fine as well.
And kudos for knowing the difference between a true singleton and just a shared instance!
HTH
With singletons, you have two choices: Write the very simple sharedInstance method and be done with it, or try to do all kinds of ingenious tricks to keep people from instantiating more objects. Trying to instantiate the singleton through any call other than sharedInstance is a programming error. You don't write complicated code to prevent programming errors. And you'll never get it right anyway :-)

Objective C Singleton Class [duplicate]

This question already has answers here:
Using a singleton to create an array accessible by multiple views
(2 answers)
Closed 9 years ago.
I have created a singleton class in Objective C. Like the one below:
#interface SingletonClass : NSObject{
NSMutableArray *instanceArray;
}
#property(nonatomic,retain)NSMutableArray *instanceArray;
+(SingletonClass*)sharedInstance;
#end
#implementation SingletonClass
#synthesize instanceArray;
static SingletonClass *sharedInstance =nil;
+(SingletonClass*)sharedInstance
{
if(sharedInstance==nil){
sharedInstance=[[super allocWithZone:NULL]init];
}
return sharedInstance;
}
-(id)init{
self=[super init];
if(self){
instanceArray=[[NSMutableArray alloc]init];
[instanceArray addObject:#"One"];
[instanceArray addObject:#"Two"];
}
return self;
}
+(id)allocWithZone:(NSZone *)zone{
return [self sharedInstance];
}
#end
I know it can be accessed from anywhere with the following piece of code:
SingletonClass *singletonObject=[SingletonClass sharedInstance];
And the instanceArray can be accessed anywhere by singletonObject.instanceArray.
Now my question is, is is possible to modify the array by adding new objects to it ? Will that be persisted ? Because i tried to add an object from one class
[singletonObject.instanceArray addObject:#"Three"];
When i checked the array contents from another class, the array consisted of only two values which are initialized by default. The value which i added from another class didnt show up.
What could be the problem ? Am I missing something here ? Please help.
Drop the allocWithZone: implementation entirely. It is prone to error and a distinctly odd thing to do. The reality is that if you have code that is using your singleton class and not going through sharedInstance then that code is broken. Attempting to hide that brokenness is just going to cause pain later.
Just do this one:
+(instancetype)sharedInstance
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[SingletonClass alloc] init];
});
return sharedInstance;
}
If you aren't seeing updates to the array in your other class, then there is some other bug.
Your implementation of allocWithZone: is never called because you are calling the [super allocWithZone:], also i don't think you need this method.
i would change your class method with this:
+(instancetype)sharedInstance
{
if(sharedInstance==nil){
sharedInstance = [[SingletonClass alloc]init];
}
return sharedInstance;
}
and if you want to be more secure that you are not going to create another instance of your object use dispatch_once:
+(instancetype)sharedInstance
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[SingletonClass alloc] init];
}
return sharedInstance;
}
I think that you forgot the ! before self in init method :
-(id)init {
self = [super init];
if(!self) {
instanceArray=[[NSMutableArray alloc]init];
[instanceArray addObject:#"One"];
[instanceArray addObject:#"Two"];
}
return self;
}
That's why each time you get a new instance of your singleton

Using Webview within Class Method

Basically I have a class method which I am calling to call a web-service call as in dispatch mechanism, and when I get the response, I send the response in NSDictionary in sync mode.
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^{
NSDictionary *_pD= [HttpRequest Details:#"Type" :#"guest" :[Description valueForKey:#"number"]];
dispatch_sync(dispatch_get_main_queue(), ^{
DLog(#"%#",[_D description]);
[self mapObjects:_D];
});
});
However, in this call I need to also invoke WebView, and wait for a javascript to get invoked from webview, hence I am just curious if that is possible to do also in Class method? Since in class method, anytime I assigned a delegate, it generates an error that I cant assign it to self.
Thanks.
You can have a static instance of your class being the delegate, and handle the entire thing from there.
Also remember to set the UIWebViewDelegate protocol in your .h
+ (YourClass *)getInstance {
static YourClass *instance = nil;
if (!instance) {
instance = [YourClass new];
}
return instance;
}
- (void)callWebService {
... do your thing
}
and call like this:
[[YourClass getInstance] callWebService];
If you want to get picky on the getInstance method, the proper way to do it is this (I didn't want to confuse you with weird code):
+ (YourClass *)getInstance {
static dispatch_once_t pred;
static YourClass *instance = nil;
dispatch_once(&pred, ^{
instance = [[[self class] alloc] init];
});
return instance;
}
Since in class method, anytime I assigned a delegate, it generates an
error that I cant assign it to self.
Just a quick thought. Why don't you write a new class and assign its object as the delegate instead of self?

how to make static variable initialized

I want to save the "dataFilePath" as a static variable so that it can be initialized when first time use "Constants" and no need to instantiate the Class , for example [Constants SDataFilePath]. But the trues is that the init method is not called. How can I do to meet my request? (In Java the construct method will be called the fist time to access the Class).
#implementation Constants
static NSString *dataFilePath;
-(id)init
{
NSLog(#"init!");
if(self = [super init]) {
dataFilePath = [self getDataFilePathWithArg:dbfile];
}
return self;
}
+(NSString *)SDataFilePath {
return dataFilePath;
}
....
#end
Well you could make Constants a singleton. Leave your code how it is and add this method to the .m:
+ (Constants *)sharedConstants
{
static Constants *_sharedConstants = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
_sharedConstants = [[self alloc] init];
});
return _sharedConstants;
}
And the method declaration to the .h:
+ (Constants *)sharedConstants;
Then access your variable like this:
[[Constants sharedConstants] SDataFilePath]
That will force an init the first time you access [Constants sharedConstants] (and only the first time). Also, you'll need to change +(NSString *)SDataFilePath to an instance method, not class method:
-(NSString *)SDataFilePath
This cannot be done this way. Any reason why you want this path to be static? You might want to look into setting dataFilePath with a getter, but no setter and instantiating the class as a singleton. That way you can set the path by some internal method and share the instance as a singleton. See here

How to set a NSString in a class from a uitextfield from a viewcontroller

I am tying to set NSString *receiveCodeText; thats in an object with a uitextfiled value thats in my viewcontroller from my viewcontroller inside tableView:didSelectRowAtIndexPath: however I am getting an error
/Users/imac/Documents/Iphone
applications/tables/Classes/RootViewController.m:198:0 /Users/imac/Documents/Iphone
applications/tables/Classes/RootViewController.m:198:
error: accessing unknown
'setReceiveCodeText:' class method
/Users/imac/Documents/Iphone
applications/tables/Classes/RootViewController.m:198:0 /Users/imac/Documents/Iphone
applications/tables/Classes/RootViewController.m:198:
error: object cannot be set - either
readonly property or no setter found
here is my code and how I am trying to pass the text.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
searchTableViewController *searchTable = [[searchTableViewController alloc] initWithNibName:#"searchTableViewController" bundle:nil];
switch (indexPath.row) {
case 1: {
searchTable.editedFieldName = #"Make";
//Pass code number over to DBAccess class
DBAccess.receiveCodeText = self.codeText.text;
} break;
case 2: {
searchTable.editedFieldName = #"Model";
} break;
case 3: {
searchTable.editedFieldName = #"Year";
} break;
}
[self.navigationController pushViewController:searchTable animated:YES];
[searchTable release];
}
DBAccess is a class. Unless setRecieveCodeText: is a class method, you can't use it directly. Properties belong to the instance rather than the class so you will have to declare class methods and use a static variable to handle this. However it makes sense to instantiate and then use that object or even using a singleton if you want to avoid multiple instances of the same class. A singleton should be available for use across classes.
I've included code related to the class method approach.
#interface DBAccess: NSObject {
}
+ (NSString *)receiveCodeText;
+ (void)setReceiveCodeText:(NSString *)code;
[..]
#end
In the .m file,
static NSString * receiveCodeText;
#implementation DBAccess
[..]
+ (NSString *)receiveCodeText {
return receiveCodeText;
}
+ (void)setReceiveCodeText:(NSString *)code {
[receiveCodeText autorelease];
receiveCodeText = [code copy];
}
[..]
#end