What is best way to share class instance (create and share singleton)? - iphone

I know 2 ways. What is better? And anything better than 2 ways?
+ (MyClass *)shared {
/*
static MyClass *sharedInstance = nil;
#synchronized(self) {
if (sharedInstance == nil) {
sharedInstance = [[self alloc] init];
}
}
return sharedInstance;
*/
/*
static dispatch_once_t pred;
static MyClass *sharedInstance = nil;
dispatch_once(&pred, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
*/
}

Can also create a your class instance in AppDelegate and use it anywhere in your project.
appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
appappDelegate.<yourClassInstance>

Here is another way to setup you shared instance. Thread safety is handled by the runtime and the code is very straight forward. This is usually how I setup my singletons. If the singleton object uses lots of resources but may not used then the dispatch_once approach works well.
static MyClass *sharedInstance = nil;
+ (void) initialize
{
sharedInstance = [[MyClass alloc] init];
}
+ (MyClass*)sharedInstance
{
return sharedInstance;
}

Just use the dispatch_once version - it's reliable and clean. Besides, it will work also with ARC - unlike the approach suggested above.

Here's some Details
+ (YourClass *)sharedInstance
{
// structure used to test whether the block has completed or not
static dispatch_once_t p = 0;
// initialize sharedObject as nil (first call only)
__strong static id _sharedObject = nil;
// executes a block object once and only once for the lifetime of an application
dispatch_once(&p, ^{
_sharedObject = [[self alloc] init];
});
// returns the same object each time
return _sharedObject;
}

The second one looks better, but this is still not perfect. Check Apple's recommendation:
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CocoaFundamentals/CocoaObjects/CocoaObjects.html#//apple_ref/doc/uid/TP40002974-CH4-97333-CJBDDIBI

Related

How to declare constant values in nsarray in ios

I had declared constant NSArray like the below way.
static NSArray* const myArray = [NSArray arrayWithObjects:#"obj1",#"obj2",#"ibj3",#"obj4",#"obj5",nil];
But it shows an error "Initiliser elements are Not Compile time constants".
So I declared like this.But I got the error.
Please help This Case.
Thanks.
Since NSArrays are heap-allocated objects, you cannot create them in a static context. You can declare the variables, and then initialize them in a method.
So, you can do this way :-
static NSArray *myStaticArray = nil;
- (void) someMethod
{
if (myStaticArray == nil)
{
myStaticArray = [[NSArray alloc] init...];
}
}
Hope it helps you..
I don't see why you cannot use this to solve your problem. it is 100% constant, because the NSArray is immutable, and it is also 100% static.
GlobalConstant.h file:
#import <Foundation/Foundation.h>
// EDITED : __unused static NSArray *_myGlobalArray;
#interface GlobalConstant : NSObject
+ (NSArray *)myGlobalArray;
#end
GlobalConstant.m file:
#import "GlobalConstant.h"
#implementation GlobalConstant
+ (NSArray *)myGlobalArray {
static NSArray *_myGlobalArray = nil; // EDITED
#synchronized (_myGlobalArray) {
if (_myGlobalArray == nil) {
_myGlobalArray = [NSArray arrayWithObjects:#"1", #"2", nil]; // here is your array...
}
return _myGlobalArray;
}
}
#end
...and your array will be available in every class which includes the GlobalConstant.h file, you can reach the array like
NSArray *_globalArray = [GlobalConstant myGlobalArray];
To create the static array you can make use of the initialize method. This is a special class method that every class has. It is called the first time a class is referenced in any way and before any other code in the class is executed.
static NSArray* myArray = nil;
#implementation SomeClass
+ (void)initialize {
if (self == [SomeClass class]) {
myArray = #[ #"obj1", #"obj2", #"obj3", #"obj4", #"obj5" ];
}
}
// rest of methods
#end
and, to save typing, you can use NSArray* myArray = #[ #"obj1", #"obj2", #"ibj3", #"obj4", #"obj5" ];

IOS Memory leak in class method

In your opinion if I have a singleton subclass of NSObject being initialised with parameters like this:
- (MyObject *) initWithSomeParam:(NSString *)param{
self = [super init];
if (SharedInstance == nil){
SharedInstance = [super init];
SharedInstance.someProperty = param;
}
return self;
}
+ (MyObject *) objectWithSomeParam:(NSString *)param{
return [[self alloc] initWithSomeParam:param];
// Will the alloc cause a leak?
}
The user doesn't have access to the instance method, just the class. Thanks.
That's not the normal way of implementing a singleton and you are breaking the convention of init. Better would be to create a sharedInstance class method and leave the initWithParam method to be more conventional:
static MyObject *_sharedInstance = nil;
+ (MyObject *)sharedInstance:(NSString *)param
{
if (_sharedInstance == nil)
{
_sharedInstance = [MyObject alloc] initWithParam:param];
}
return _sharedInstance;
}
// This must be called during app termination to avoid memory leak
+ (void)cleanup
{
[_sharedInstance release];
_sharedInstance = nil;
}
- (id)initWithParam:(NSString *)param
{
self = [super init];
if (self != nil)
{
self.someProperty = param;
}
return self;
}
However, even that doesn't seem very comfortable; i.e. what happens if the user calls sharedInstance with a different parameter? Perhaps you want to keep a NSMutableDictionary of the initialized objects and create/return them depending on the parameter?
If so, you would do:
static NSMutableDictionary _sharedInstances = [[NSMutableDictionary alloc] init];
+ (MyObject *)sharedInstance:(NSString *)param
{
MyObject *obj = [_sharedInstances objectForKey:param];
if (obj == nil)
{
obj = [[MyObject alloc] initWithParam:param];
[_sharedInstances setObject:obj forKey:param];
}
return obj;
}
// This must be called during app termination to avoid memory leak
+ (void)cleanup
{
[_sharedInstances release];
_sharedInstances = nil;
}

Initialize properties in Singletons in objective-c

So I'm kind of unsure about something. What I want is one class to know about the data through all my different view controllers. This one class should have an array of my objects so that if I have a detailViewController, I would just be looking at one instance in my array that the DataManager would hold. I thought that this DataManager would be a singleton. I followed Apple's documentation on creating a singleton, but now I'm a bit confused on the properties.
static DataManager *sharedDmgr = nil;
+ (id)sharedInstance {
if (sharedDmgr == nil) {
sharedDmgr = [[super allocWithZone:NULL] init];
}
return sharedDmgr;
}
If I want an NSMutableArray property, what is the proper way to initialize it? Do I do something like
+ (id)sharedInstance {
if (sharedDmgr == nil) {
sharedDmgr = [[super allocWithZone:NULL] init];
[self sharedInit];
}
return sharedDmgr;
}
- (void)sharedInit {
// initialize all my properties for the singleton here?
}
Thanks!
Let's say a DataManager object has a NSMutableArray attribute named "array", then your objective is to be able to do [DataManager sharedDataManager].array in all your code.
The way to do it would be to:
Declare the NSMutableArray *array as an attribute on the DataManager.h #interface block.
Declare a #property for that attribute.
On the - [DataManager init] method initialize the mutable array. Something like self.array = [NSMutableArray array];
Then your sharedInstance method would be:
static DataManager *sharedDmgr = nil;
+ (id)sharedInstance {
if (sharedDmgr == nil) {
sharedDmgr = [[DataManager alloc] init];
}
return sharedDmgr;
}
All done. Let me know if you need some example code.
You can use the same lazy initialization pattern for your property getters. So for a mutable array...
#interface DataManager ()
#property (strong, nonatomic) NSMutableArray *array;
#end
#implementation DataManager
#synthesize array=_array;
// shared instance method like #fbernardo's suggestion
- (NSMutableArray *)array {
if (!_array) {
_array = [[NSMutableArray alloc] init];
}
return _array;
}

NSMutableArray within singleton class always returns count 0 / never retains its objects

My simplified singleton looks like this:
#interface MyClass : NSObject {
NSMutableArray * myArray;
}
+ (MyClass*) instance;
#property(nonatomic,retain)NSMutableArray *myArray;
Then in the implementation
static MyClass * myinstance;
#synthesize myArray;
+ (MyClass*) instance {
if(myinstance == nil)
myinstance = [[MyClass alloc] init];
return myinstance;
}
- (id) init {
if(self = [super init]) {
myArray = [[NSMutableArray alloc] initWithCapacity:2];
[myArray addObject:#"Trauma"];
}
return self;
}
However when I try to access it for a tableview this always returns 0:
[[[MyClass instance] myArray] count];
Little unsure about what I'm doing wrong
The method that returns the instance of your singleton is named +instance, but when attempting to access your singleton, you are using +myinstance. Your instance of MyClass is most likely nil.

class variables in objective-c and memory management

#implementation ProductController
NSString *areaName = nil;
+ (void)setAreaName:(NSString *)areaName_ {
areaName = areaName_;
}
#end
and
#implementation ProductController
NSString *areaName = nil;
+ (void)setAreaName:(NSString *)areaName_ {
if(areaName_ != areaName) {
[areaName release];
areaName = [areaName_ copy];
}
}
- (void)dealloc {
[areaName release];
}
#end
Now which one is correct?and why?
As you seem to understand, there are no "class variables" in Obj-C. The workaround is just a C-style (global, or file-scoped) variable that you set up similarly to how you've shown above. First off, you should use file scope for these variables by marking them with the static keyword:
static NSString *areaName = nil;
You might also consider using a convention like FirstLetterUppercase to indicate the scope difference.
As for memory management, you can treat it exactly like an instance variable, but one that never goes away forever:
static NSString *AreaName = nil;
+ (void)setAreaName:(NSString *)name {
if (![name isEqualToString:AreaName]) {
[AreaName release];
AreaName = [name copy];
}
}
Note that in your second example, you should NOT release the "class" variable from an instance's -dealloc method. If you have more than one instance of the object, this leaves a bad dangling pointer, and defeats the purpose of the "class" variable anyways. Generally, when you use this pattern, you'll "leak" (for some definition of leak) the class variable value, and that's OK.
class variables are generally bad style.
nevertheless, an alternative to other answers would be to create a static dictionary for your lib/app's class variables. a very primitive implementation would take this form:
// MONLibraryClassVariable.h
extern id MONLibraryClassVariableGetObjectForKey(NSString * key);
extern void MONLibraryClassVariableSetObjectForKey(id<NSObject> object, NSString * key);
// MONLibraryClassVariable.m
/* #todo make all this thread safe */
static NSMutableDictionary * MONLibraryClassVariables_ = nil;
id MONLibraryClassVariableGetObjectForKey(NSString * key) {
return [MONLibraryClassVariables_ objectForKey:key];
}
void MONLibraryClassVariableSetObjectForKey(id<NSObject> object, NSString * key) {
if (nil == MONLibraryClassVariables_) {
MONLibraryClassVariables_ = [NSMutableDictionary new];
}
[MONLibraryClassVariables_ setObject:object forKey:key];
}
// ProductController.m
static NSString * const ProductController_KEY_areaName = #"ProductController.areaName";
#implementation ProductController
+ (void)setAreaName:(NSString *)inAreaName {
MONLibraryClassVariableSetObjectForKey([[inAreaName copy] autorelease], ProductController_KEY_areaName);
}
- (void)dealloc {
// nope [areaName release];
[super dealloc];
}
#end