Confusion regarding how to use a NSMutableArray and Singleton - objective-c

I am experimenting using a singleton for the first time. I would like to have an array that is global to all my view controllers with some special methods to add and remove items (this is for a shopping cart kind of thing).
My singleton class is called Cart.
This is Cart.h:
#interface Cart : NSObject
#property NSMutableArray *cartArray;
+ (Cart *)sharedManager; // Class method to return the singleton object
- (void)addItemToCart:(id)object;
- (void)removeItemFromCart:(id)object;
- (void)emptyAllItemsFromCart:(id)object;
- (NSMutableArray *)returnArray;
#end
This is Cart.m:
#implementation Cart
// #property NSMutableArray *cartArray;
NSMutableArray *cartArray;
+ (Cart *)sharedManager
{
Cart *cartObject = [[Cart alloc]init];
// self.cartArray = [NSMutableArray new];
return cartObject;
}
- (void)addItemToCart:(id)object
{
if(!cartArray){
cartArray = [NSMutableArray new];
}
[cartArray addObject:object];
}
- (void)removeItemFromCart:(id)object
{
[cartArray removeObject:object];
}
- (void)emptyAllItemsFromCart:(id)object
{
[cartArray removeAllObjects];
}
Then in one of my view controllers, I am trying to pass a custom object (that contains strings and NSNumbers) to my global array.
// Cart *singleton = [Cart sharedManager];
// [singleton addItemToCart:self.localChosenAccessory];
Or maybe something like:
Cart *mySingleton = [Cart sharedManager];
mySingleton.cartArray = self.addToCartArray;
Both above singleton objects come out to nil.
I'm new to singletons and Objective C in general. I would appreciate any advice. I have read through a lot of similar Stack Overflow links but don't quite get it in my situation.

In your [Cart sharedManager] method you are creating a new instance every time no matter what. That's not a singleton! You want something like this:
static Cart *managerInstance;
+ (Cart *)sharedManager
{
if(!managerInstance) {
managerInstance = [[Cart alloc] init];
// put code in instance init if you need to initialize array
}
return managerInstance;
}
Then you can call sharedManager as many times as you want and always get to the same singleton instance.

Don't forget to save the created object:
#implementation Cart
static Cart *sharedInstance = nil;
+ (Cart *)sharedInstance {
static dispatch_once_t pred; // Lock
dispatch_once(&pred, ^{ // This code is called at most once per app
sharedInstance = [[Cart alloc] init];
});
return sharedInstance;
}
...
and then you can call it like this:
Cart *mySingleton = [Cart sharedInstance];
[mySingleton addItemToCart:someObject];

You are initializing your object every time you ask shared manager to get you the instance of singleton class.
Replace this with your shared manager and then try it out:
static Cart *cartObject = nil;
+ (id)sharedManager {
if (cartObject == nil)
cartObject = [[self alloc] init];
return cartObject;
}

Related

Better way than write dozens of empty getters?

I use lazy instantiation on my properties, to have my class created and used as fast as possible. To achieve this, I write lots of 'empty' getters like this:
- (VMPlacesListFilter *)currentFilter
{
if (!_currentFilter) {
_currentFilter = [[VMPlacesListFilter alloc] init];
}
return _currentFilter;
}
They are all the same: if the instance variable is nil, call the -alloc and -init on the class of the property, then return the instance variable. Very common and straightforward.
If I don't create this getter by myself, Objective-C's automatic synthesization creates a getter for me, which does only the returning part (does not init the object if the instance variable is nil).
Is there any way to avoid writing this boilerplate code?
Nope, I'm afraid there's no good way around it, if you really want to have lazy initialization. Personally, I usually save lazy initialization for stuff that could really be time consuming or memory intensive (say, loading images or view controllers), and initialize cheap stuff (like simple data structures or model objects) in init.
- (instancetype) init {
self = [super init];
if( self ) {
_cheapThing1 = [NSMutableArray array];
_cheapThing2 = [[MyModelObject alloc] init];
}
return self;
}
- (ExpensiveThing*) expensiveThing
{
if( _expensiveThing == nil ) {
_expensiveThing = [[ExpensiveThing alloc] init];
}
return _expensiveThing;
}
Unless you're loading something from disk or the network, I wouldn't worry too much about initialization time. Of course, profile it.
I know this is an Objective-C question, but it's worth noting that Swift has lazy initialization built-in.
lazy var currentFilter = VMPlacesListFilter()
First off, I totally agree with #zpasternack that "lazy load" should not be misused. However, automatically generating setters and getters is completely doable with the power of Objective-C runtime. In fact, CoreData is doing this.
Anyway, I have come up with some stupid code implementing a class called LazyClass, in which you can declare dynamic properties like lazyArray (see below). Using dynamic method resolution, when the property is accessed for the first time, a getter that calls the corresponding class's default +alloc and -init method will be automatically added to the class. All underlying instance variables are stored in an NSMutableDictionary called myVars. Of course you can manipulate ivars through the runtime API as well, but using a dictionary should save some work.
Please note that this implementation just shows the basic idea of how it works. It lacks error checking and is not supposed to be shipped.
LazyClass.h
#interface LazyClass : NSObject
#property NSMutableDictionary *myVars;
// lazily initialized property
#property NSArray *lazyArray;
#end
LazyClass.m
#import "LazyClass.h"
#import <objc/objc-runtime.h>
#implementation LazyClass
#dynamic lazyArray;
- (instancetype)init {
self = [super init];
self.myVars = [NSMutableDictionary dictionary];
return self;
}
- (NSMutableDictionary *)getMyVars {
return self.myVars;
}
// the generated getter method
id dynamicGetterMethodIMP(id self, SEL _cmd) {
// selector name, which is also the property name
const char *selName = sel_getName(_cmd);
NSString *selNSName = [NSString stringWithCString:selName encoding:NSUTF8StringEncoding];
NSString *keyPath = [NSString stringWithFormat:#"myVars.%#", selNSName];
if (![self valueForKeyPath:keyPath]) {
// get the actual type of the property
objc_property_t property = class_getProperty([self class], selName);
const char *attr = property_getAttributes(property);
NSString *attrString = [[NSString alloc] initWithCString:attr encoding:NSUTF8StringEncoding];
NSString *typeAttr = [[attrString componentsSeparatedByString:#","] firstObject];
NSString *typeName = [typeAttr substringWithRange:NSMakeRange(3, typeAttr.length - 4)];
// the default initialization
Class typeClass = NSClassFromString(typeName);
[self setValue:[[typeClass alloc] init] forKeyPath:keyPath];
}
return [self valueForKeyPath:keyPath];
}
// the generated setter method
void dynamicSetterMethodIMP(id self, SEL _cmd, id value) {
// get the property name out of selector name
// e.g. setLazyArray: -> lazyArray
NSString *propertyName = NSStringFromSelector(_cmd);
propertyName = [propertyName stringByReplacingOccurrencesOfString:#"set" withString:#""];
propertyName = [propertyName stringByReplacingOccurrencesOfString:#":" withString:#""];
propertyName = [NSString stringWithFormat:#"%#%#", [propertyName substringToIndex:1].lowercaseString, [propertyName substringFromIndex:1]];
NSString *keyPath = [NSString stringWithFormat:#"myVars.%#", propertyName];
[self setValue:value forKeyPath:keyPath];
}
// dynamic method resolution
+ (BOOL)resolveInstanceMethod:(SEL)aSEL {
if ([NSStringFromSelector(aSEL) containsString:#"set"]) {
class_addMethod([self class], aSEL, (IMP)dynamicSetterMethodIMP, "^?");
} else {
class_addMethod([self class], aSEL, (IMP)dynamicGetterMethodIMP, "v#:");
}
return YES;
}
#end
Documentation
If it's the verboseness that bothers you, I suppose you could compress lazy initialisers that only need one-line initialization using the ternary operator:
- (VMPlacesListFilter *)currentFilter
{
return _currentFilter ? : (_currentFilter = [[VMPlacesListFilter alloc] init]);
}
DISCLAIMER: I don't do this, but it's interesting that it can be done

Factory methods in Objective-C

I make class factories like so,
#implementation Universe {
NSString *foo;
}
+ (instancetype)universeWithMeaning:(NSString *)meaning
{
return [[self alloc] initUniverseWithMeaning:meaning];
}
- (id)initUniverseWithMeaning:(NSString *)meaning
{
if (self = [super init]) {
foo = meaning;
}
return self;
}
- (void)showMeaning
{
NSLog(#"%#", foo);
}
#end
And create object like this,
Universe *universe = [Universe universeWithMeaning:#"42"];
[universe showMeaning]; // Prints 42
This works great, but the method signature of initUniverseWithMeaning: is the same as that of universeWithMeaning:, except that it's an instance method which allows it to save instance variables to the created object.
Is there a way to this without having to implement the initUniverseWithMeaning: instance method?
I know its necessary to be inside of an instance method to be able to access instance variables, so I've been experimenting with blocks. My idea was to pass a block containing instance variable assignations to the class method which would somehow execute it in the instance context.
Implementation,
#implementation Cat {
NSString *lives;
}
+ (Cat *)newCat:(void(^)(void))cat
{
cat(); // **Problem 1**
}
- (void)showLives
{
NSLog(#"%#", lives);
}
#end
Usage,
Cat *cat = [Cat newCat:^void (void) {
self.lives = 9; // **Problem 2**
}];
[cat showLives]; // I'd like this to print 9
Problem 1: How to create a Cat object and execute cat() inside it?
Problem 2: How to make self refer to the object in the block's execution environment?
Anyway, this is more of a curiosity than anything else, it's would only be practically useful to save me from writing alloc (I would just need to include a method prototype for initUniverseWithMeaning: in the .h file.)
For your problem 1 and 2, you can try this
#interface Cat ()
#property (strong) NSString *lives;
#end
#implementation Cat
+ (Cat *)newCat:(void(^)(Cat *me))cat
{
Cat *newcat = [[self alloc] init];
cat(newcat);
return newcat;
}
- (void)showLives
{
NSLog(#"%#", lives);
}
#end
Cat *cat = [Cat newCat:^(Cat *me) {
me.lives = 9;
}];
[cat showLives]; // print 9
but I can't see much use of it... Isn't this simpler?
Cat *cat = [Cat new];
cat.lives = 9;
[cat showLives];
For your real problem
Is there a way to this without having to implement the initUniverseWithMeaning: instance method?
+ (instancetype)universeWithMeaning:(NSString *)meaning
{
Universe *universe = [[self alloc] init];
if (universe) universe->foo = meaning;
return universe;
}
The first example you've posted is the correct way of creating Objective-C factory methods.
An Objective-C factory method is nothing more than a class method wrapper around an instance level init method. Generally speaking, every factory method should have a paired init method that takes the same number and type of arguments.
fooWithBar:(NSString *)bar should be paired with initWithBar:(NSString *)bar, etc.
An exception might come in when you have an init method that takes arguments, but you've create a handful of factory methods with default arguments for this method. For example:
- (instancetype)initWithString:(NSString *)string;
+ (instancetype)fooWithString:(NSString *)string {
return [[self alloc] initWithString:string];
}
+ (instancetype)fooWithBar {
return [[self alloc] initWithString:#"bar"];
}
Now, you can create the object with in the method, then modify it, and return the modified object.
For example:
+ (instancetype)fooWithString:(NSString *)string {
Foo *f = [[self alloc] init];
f.str = string;
return f;
}
But honestly, it's just better to have an initWithString: method.
Every class should have a designated initializer and every object of that class should go through the designated initializer.

Can I pass delegate as a parameter objective-c

I am working with an NSOperationQueue and I want to add new NSOperations to the NSOperationQueue. It is a queue that lives in a singleton instance of a class I have. It would make things a lot easier if I could move everything into the static class by passing the delegate.
Here is my code now as it lives in - this is in a cellForRowAtIndexPath
NSString *key = [NSString stringWithFormat:#"%#%#",cell.dataItem.ItemID, cell.dataItem.ManufacturerID];
if (![self.imgOperationInQueue valueForKey:key]) {
ImageOperation *imgOp = [[ImageOperation alloc] initWithItemID:cell.dataItem.ItemID withManufacturerID:cell.dataItem.ManufacturerID withReurnType:kThumbnail];
imgOp.identifier = [NSString stringWithFormat:#"%i", cell.tag];
imgOp.delegate = self;
[[SharedFunctions sharedInstance] addImageOperationToQueue:imgOp];
[imgOp release];
// store these in the dictionary so we don;t queue up requests more than once
[self.imgOperationInQueue setValue:cell.dataItem.ItemID forKey:key];
}
If I could add the delegate as a parameter I could put all of this code into the shared singleton class and call it from anywhere in my app.
I suppose that I could use an NSNotification - or can I use a block of some sort?
Just create the appropriate init method that passes in the delegate.
- (id)initWithItemID:(NSString *)itemID
withManufacturerID:(NSString *)manufacturerID
withReurnType:(NSInteger)type
delegate:(id<YourDelegate>)theDelegate
{
self = [super init];
if (self)
{
.... // Other assignments
self.delegate = theDelegate;
}
return self;
}

Singletons objective C

I have a NSString *date. I fetch some data from the internet and now I have the date I want in this variable. I want to be able to use this NSString at anytime without calling a method that returns it at any scope within my program.
Where would I put the code to retrieve the date from the internet that the variable will hold? Would it be here? and then would I eventually make date= sharedInstance?
static SingletonClass *sharedInstance = nil;
// Get the shared instance and create it if necessary.
+ (SingletonClass *)sharedInstance
{
if (sharedInstance == nil) {
sharedInstance = [[super allocWithZone:NULL] init];
}
//Do I Put Code here?????
return sharedInstance;
}
Thanks in advance!
If you really want to use a singleton pattern and can target an OS with GCD, then dispatch_once can simplify your singleton code, e.g.
+ (id)sharedFoo
{
static dispatch_once_t pred;
static Foo *foo = nil;
dispatch_once(&pred, ^{ foo = [[self alloc] init]; });
return foo;
}
Depending on your requirements, you can override the init method to provide whatever additional initialization you need.

Singleton in iOS 5?

Hi I had an implementation previous versions of iOS for a singleton as follows:
.h file
#interface CartSingleton : NSObject
{
}
+(CartSingleton *) getSingleton;
.m file
#implementation CartSingleton
static CartSingleton *sharedSingleton = nil;
+(CartSingleton *) getSingleton
{
if (sharedSingleton !=nil)
{
NSLog(#"Cart has already been created.....");
return sharedSingleton;
}
#synchronized(self)
{
if (sharedSingleton == nil)
{
sharedSingleton = [[self alloc]init];
NSLog(#"Created a new Cart");
}
}
return sharedSingleton;
}
//==============================================================================
+(id)alloc
{
#synchronized([CartSingleton class])
{
NSLog(#"inside alloc");
NSAssert(sharedSingleton == nil, #"Attempted to allocate a second instance of a singleton.");
sharedSingleton = [super alloc];
return sharedSingleton;
}
return nil;
}
//==============================================================================
-(id)init
{
self = [super init];
}
However on the web I see people have implemented the Singleton design pattern using this code:
+ (id)sharedInstance
{
static dispatch_once_t pred = 0;
__strong static id _sharedObject = nil;
dispatch_once(&pred, ^{
_sharedObject = [[self alloc] init]; // or some other init method
});
return _sharedObject;
}
Could someone who is experience please guide me.
Im a newbie and thoroughly confused between the old iOS implementation of the Singleton and the new one and which is the correct one?
Thanks a lot
Strictly speaking, you must use:
+ (MySingleton*) instance {
static dispatch_once_t _singletonPredicate;
static MySingleton *_singleton = nil;
dispatch_once(&_singletonPredicate, ^{
_singleton = [[super allocWithZone:nil] init];
});
return _singleton;
}
+ (id) allocWithZone:(NSZone *)zone {
return [self instance];
}
Now you guarantee that one cannot call alloc/init and create another instance.
Explanation: The instance method is at the class level and is your main access method to get a reference to the singleton. The method simply uses the dispatch_once() built-in queue that will only execute a block once. How does the runtime guarantee that the block is only executed once? Using the predicate you supply (of type dispatch_once_t). This low-level call will guarantee that even if there are multiple threads trying to call it, only one succeeds, the others wait until the first one is done and then returns.
The reason we override allocWithZone is because alloc calls allocWithZone passing nil as the zone (for the default zone). To prevent rogue code from allocating and init-ializing another instance we override allocWithZone so that the instance passed back is the already initialized singleton. This prevents one from creating a second instance.
The dispatch_once snippet is functionally identical to other one. You can read about it at http://developer.apple.com/library/mac/#documentation/Darwin/Reference/Manpages/man3/dispatch_once.3.html.
This is what I use for singletons:
+ (MySingleton*) getOne {
static MySingleton* _one = nil;
#synchronized( self ) {
if( _one == nil ) {
_one = [[ MySingleton alloc ] init ];
}
}
return _one;
}
NOTE: In most cases, you do not even need to use #synchronized (but it is safe this way).
A singleton is a special kind of class where only one instance of the class exists for the current process. (In the case of an iPhone app, the one instance is shared across the entire app.) Some examples in UIKit are [UIApplication sharedApplication] (which returns the sole instance of the application itself), and [NSFileManager defaultManager] (which returns the file manager instance). Singletons can be an easy way to share data and common methods across your entire app.
Rather than create instances of the singleton class using alloc/init, you'll call a class method that will return the singleton object. You can name the class method anything, but common practice is to call it sharedName or defaultName.
Please check a link with best answer
:http://www.idev101.com/code/Objective-C/singletons.html