Can't add object to NSMutableArray in singleton - ios

I made a singleton and i'm trying to add objects to self.timelineArray but i can't. When i do this i have 9 objects:
NSNumber* nmb = [[NSNumber alloc] initWithInt:1];
[self.dataManager.timelineArray addObject:nmb];
After i insert the nmb object, i still have 9 objects.
Here's my singleton header (only important bits):
#interface DataManager : NSObject
#property (nonatomic, strong) NSMutableArray* timelineArray;
Here's my singleton implementation (only important bits):
#import "DataManager.h"
static DataManager* sharedInstance = nil;
#implementation DataManager
+ (DataManager *) sharedInstance{
#synchronized(self)
{
if (sharedInstance == nil)
sharedInstance = [[self alloc] init];
}
return sharedInstance;
}
- (id)init {
if (self = [super init])
{
self.timelineArray = [[NSMutableArray alloc] init];
}
return self;
}
This is just simple coding and i can't seem to figure out why it does not work.

Trying to modify immutable array(NSArray) will lead to this.
Replace
[responseObject objectForKey:#"timeline"] with [[NSMutableArray alloc] initWithArray:[responseObject objectForKey:#"timeline"]
This was based on the comments of the question.

i'll suggest you to add like following
NSNumber* nmb = [[NSNumber alloc] initWithInt:1];
[[DataManager sharedInstance]timelineArray addObject:nmb];
this will always add into the singleton not the instance of singleton

Related

Not creating a new instance of NSMutableDictionary when passing to another class

i have an NSMutableDictionary declared in a class but i want to print get access to the contents of it in another class for example
#interface MyClass0 : NSObject
{
}
#property (nonatomic, strong) NSMutableDictionary *valuee;
#end
and in implementation i do
#implementation MyClass0
- (void)viewDidLoad{
[super viewDidLoad];
[valuee setObject:#"name" forKey:#"Aryan"];
}
#end
Now i create a new class called MyClass1 where i want to access these
#interface MyClass1 : NSObject
{
}
#property (nonatomic, strong) NSMutableDictionary *dict;
#end
and the implementation
#implementation MyClass1
#synthesize dict;
- (void)viewDidLoad{
[super viewDidLoad];
self.dict = [[NSMutableDictionary alloc] init];
MyClass0 *c = [[MyClass0 alloc] init];
self.dict = c.valuee;
// dict is not nil but the contents inside is nil so it clearly creates a new instance
}
#end
You are creating the instance of MyClass0 and valuee is declared but not initialized.
The closest solution to your code is
MyClass0 *c = [[MyClass0 alloc] init];
c.valuee = [[NSMutableDictionary alloc] init];
self.dict = c.valuee;
If a value is assigned to a declared property then an explicit initialization is not necessary.
If it's just a simple NSMutableDictionary that has the same contents every time you can create a class method in MyClass0 like so:
+ (NSMutableDictionary *) getDict {
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
[dict setObject:#"name" forKey:#"Aryan"];//did you mean [dict setObject:#"Aryan" forKey:#"name"]?
return dict;
}
To access this, declare the method in the MyClass0.h file like so: + (NSMutableDictionary *) getDict; and simply call [MyClass0 getDict]; in your MyClass1.m file.
If it doesn't have the same contents every time, you'll have to pass the dictionary forward to each view controller in prepareForSegue:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Make sure your segue name in storyboard is the same as this next line
if ([[segue identifier] isEqualToString:#"MySegue"]) {
MyClass1 *mc = [segue destinationViewController];
mc.dict = self.valuee;
}
}

Objective-C Defining a Global Array for use by several ViewControllers

I've been trying to implement a global NSMutableArray from what I think to be a singleton class that I've implemented.
I can enter ViewController # 2, add and remove objects to the array.
However, when I leave ViewController #2 and come back, the data does not persist, and I have an array with 0 objects.
What do you think I'm doing wrong?
.h
// GlobalArray.h
#interface GlobalArray : NSObject{
NSMutableArray* globalArray;
}
+(void)initialize;
.m
#import "GlobalArray.h"
#implementation GlobalArray
static GlobalArray* sharedGlobalArray;
NSMutableArray* globalArray;
+(void)initialize{
static BOOL initalized = NO;
if(!initalized){
initalized = YES;
sharedGlobalArray = [[GlobalArray alloc] init];
}
}
- (id)init{
if (self = [super init]) {
if (!globalArray) {
globalArray = [[NSMutableArray alloc] init];
}
}
return self;
}
View Controller #2
GlobalArray* myGlobalArray;
myGlobalArray = [[GlobalArray alloc] init];
//Various add and remove code
Thank you for your input.
Following is best approach to share data Globally at Application level. Singleton Class is a key. Singleton is only initialised once, rest of times shared data is returned.
#interface Singleton : NSObject
#property (nonatomic, retain) NSMutableArray * globalArray;
+(Singleton*)singleton;
#end
#implementation Singleton
#synthesize globalArray;
+(Singleton *)singleton {
static dispatch_once_t pred;
static Singleton *shared = nil;
dispatch_once(&pred, ^{
shared = [[Singleton alloc] init];
shared.globalArray = [[NSMutableArray alloc]init];
});
return shared;
}
#end
Following is the way to access/use shared data.
NSMutableArray * sharedData = [Singleton singleton].globalArray;
You create separate instance of GlobalArray in your ViewController#2 with this code:
GlobalArray* myGlobalArray;
myGlobalArray = [[GlobalArray alloc] init];
Instead, you should create accessor method to return your shared instance, something like this:
// GlobalArray.h
#interface GlobalArray : NSObject{
NSMutableArray* globalArray;
}
+(void)initialize;
+(GlobalArray*)sharedInstance;
with implementation:
// GlobalArray.m
// ... your existing code
// accessor method
+(GlobalArray*)sharedInstance
{
return sharedGlobalArray;
}
and then call it from your ViewController#2:
GlobalArray* myGlobalArray = [GlobalArray sharedInstance];
However, using global variables to transfer data between view controllers is bad practice; I suggest you to use more safe methods, create a delegate, for example.
To create a shared global array, if that's really what you want, just put this in the header file:
extern NSMutableArray *myGlobalArray;
and this in your main source file:
NSMutableArray *myGlobalArray;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
myGlobalArray = [NSMutableArray new];
}
Use this code for set and get the array views, for adding and removing do it separate in controller itself.
// GlobalArray.h
#interface GlobalArray : NSObject
#property (nonatomic, strong) NSMutableArray* globalArray;
+ (id)sharedManager;
-(NSMutableArray *) getGlobalArray;
-(void) setGlobalArray:(NSMutableArray *)array;
#end
/*-----------------------------------------*/
#import "GlobalArray.h"
#implementation GlobalArray
+ (id)sharedManager {
static GlobalArray *sharedMyManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedMyManager = [[self alloc] init];
});
return sharedMyManager;
}
- (id)init{
if (self = [super init]) {
if (!globalArray) {
globalArray = [[NSMutableArray alloc] init];
}
}
return self;
}
-(NSMutableArray *) getGlobalArray{
return self.globalArray;
}
-(void) setGlobalArray:(NSMutableArray *)array{
_globalArray = globalArray;
}
#end
-------------------------
//get array
NSArray * array = [[GlobalArray sharedManager] getGlobalArray];
//set array
[[GlobalArray sharedManager] setGlobalArray:array]
-------------------------

Can't add object to NSMutableArray from another class

I am trying to add objects to a NSMutableArray from another class and it won't work. It works perfectly for the other attribute.
I looked at similar questions but couldn't find a suitable answer.
The object iPack :
#interface IPack : NSObject
#property float price;
#property NSMutableArray *cocktails;
#end
In the class of my collection view :
- (void)viewDidLoad {
[super viewDidLoad];
self.iPack = [[IPack alloc] init];
self.iPack.cocktails = [[NSMutableArray alloc] init];
In the class of my cell :
self.collectionView.iPack.price = self.price //perfectly works
NSArray* cock = [NSArray arrayWithObjects:c1,c2,c3,c4,c5, nil];
[self.collectionView.iPack.cocktails addObjectsFromArray:cock]; //line won't work
You haven't shown the [IPack init] method, but I strongly suspect you are not allocating the cocktails array. Simply defining it as a property does not mean it's automatically allocated:
#implementation IPack
- (instancetype)init
{
self = [super init];
if (self) {
_price = 0.0f;
_cocktails = [NSMutableArray new];
}
return self;
}
#end
EDIT
I've just seen this line in your question:
self.iPack.cocktails = [[NSMutableArray alloc] init];
Which would suggest my answer is wrong (despite it being the better way of doing the same thing). Sorry about that; I cannot see why your code doesn't work. Are you sure you are checking correctly?
try this,
in IPack class add a method
#interface IPack : NSObject
#property float price;
#property NSMutableArray *cocktails;
- (instancetype)initWithPrice:(float)price cocktails:(NSMutableArray *)cocktails;
#end
and in implementation
#implementtion IPack
- (instancetype)initWithPrice:(float)price cocktails:(NSMutableArray *)cocktails {
self = [super init];
if (self) {
self.price = price;
self.cocktails = cocktails;
}
}
#end
In the class of my collection view :
remove alloc init in viewDidLoad
that is remove the following lines
self.iPack = [[IPack alloc] init];
self.iPack.cocktails = [[NSMutableArray alloc] init];
In the class of my cell :
NSArray* cock = [NSArray arrayWithObjects:c1,c2,c3,c4,c5, nil];
IPack *ipack = [[IPack alloc] initWithPrice:self.price cocktails:[NSMutableArray arrayArray:cock]];
self.collectionView.iPack = ipack;

Singleton NSMutableDictionary property won't allow setObject:forKey

I have a complete noob question for you. I'm obviously rusty with obj-c. I have a simple shopping cart class implemented as a singleton and just want it to store a single NSMutableDictionary. I want to be able to add objects to this dictionary from anywhere in the app. But for some (I'm sure simple) reason it's just returning null. No error messages.
ShoppingCart.h:
#import <Foundation/Foundation.h>
#interface ShoppingCart : NSObject
// This is the only thing I'm storing here.
#property (nonatomic, strong) NSMutableDictionary *items;
+ (ShoppingCart *)sharedInstance;
#end
ShoppingCart.m:
// Typical singelton.
#import "ShoppingCart.h"
#implementation ShoppingCart
static ShoppingCart *sharedInstance = nil;
+ (ShoppingCart *)sharedInstance
{
#synchronized(self)
{
if (sharedInstance == nil)
sharedInstance = [[self alloc] init];
}
return(sharedInstance);
}
#end
And in my VC I'm trying to set it with:
- (IBAction)addToCartButton:(id)sender
{
NSDictionary *thisItem = [[NSDictionary alloc] initWithObjects:#[#"test", #"100101", #"This is a test products description"] forKeys:#[#"name", #"sku", #"desc"]];
// This is what's failing.
[[ShoppingCart sharedInstance].items setObject:thisItem forKey:#"test"];
// But this works.
[ShoppingCart sharedInstance].items = (NSMutableDictionary *)thisItem;
// This logs null. Specifically "(null) has been added to the cart"
DDLogCInfo(#"%# has been added to the cart", [[ShoppingCart sharedInstance] items]);
}
Thanks
You are never creating a NSMutableDictionary object named items.
You could create it in the init of ShoppingCart.
-(id)init
{
if(self = [super init]) {
_items = [NSMutableDictionary dictionary];
}
return self;
}
or in sharedInstance
+ (ShoppingCart *)sharedInstance
{
#synchronized(self)
{
if (sharedInstance == nil)
sharedInstance = [[self alloc] init];
sharedInstance.items = [NSMutableDictionary dictionary];
}
return(sharedInstance);
}
I might also add it's better (arguably) to set up your shared instance like so:
static ShoppingCart *instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[self alloc] init];
instance.items = [NSMutableDictionary dictionary];
});
return instance;

Objective C - sample Singleton implementation

*I definitely need a break... cause was simple - array was not allocated... Thanks for help. Because of that embarrassing mistake, I flagged my post in order to delete it. I do not find it useful for Users ;) *
I have just tried to create a singleton class in iOS, but I probably I am making a mistake. Code (no ARC is a requirement):
#import "PeopleDatabase.h"
#import "Person.h"
#import <Foundation/Foundation.h>
#interface PeopleDatabase : NSObject{objetive
NSMutableArray* _arrayOfPeople;
}
+(PeopleDatabase *) getInstance;
#property (nonatomic, retain) NSMutableArray* arrayOfPeople;
#end
--
#implementation PeopleDatabase
#synthesize arrayOfPeople = _arrayOfPeople;
static PeopleDatabase* instance = nil;
-(id)init{
if(self = [super init]) {
Person* person = [[[Person alloc] initWithName:#"John" sname:#"Derovsky" descr:#"Some kind of description" iconName:#"johnphoto.png" title:Prof] retain];
[_arrayOfPeople addObject:person];
NSLog(#"array count = %d", [_arrayOfPeople count]); // <== array count = 0
[person release];
}
return self;
}
+(PeopleDatabase *)getInstance {
#synchronized(self)
{
if (instance == nil)
NSLog(#"initializing");
instance = [[[self alloc] init] retain];
NSLog(#"Address: %p", instance);
}
return(instance);
}
-(void)dealloc {
[instance release];
[super dealloc];
}
#end
When invoking getInstance like here:
PeopleDatabase *database = [PeopleDatabase getInstance];
NSLog(#"Adress 2: %p", database);
Address 2 value the same value as in getInstance.
The standard way of creating a singleton is like...
Singleton.h
#interface MySingleton : NSObject
+ (MySingleton*)sharedInstance;
#end
Singleton.m
#import "MySingleton.h"
#implementation MySingleton
#pragma mark - singleton method
+ (MySingleton*)sharedInstance
{
static dispatch_once_t predicate = 0;
__strong static id sharedObject = nil;
//static id sharedObject = nil; //if you're not using ARC
dispatch_once(&predicate, ^{
sharedObject = [[self alloc] init];
//sharedObject = [[[self alloc] init] retain]; // if you're not using ARC
});
return sharedObject;
}
#end
Check this apple doc on how to create singleton instance:
https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CocoaFundamentals/CocoaObjects/CocoaObjects.html
#synchronized(self)
{
if (instance == nil)
NSLog(#"initializing");
instance = [[[self alloc] init] retain];
NSLog(#"Address: %p", instance);
}
You appear to be missing your braces for that if statement. As written, the only thing you do different when instance == nil is emit a log message.
After web reading and personal practicing, my current singleton implementation is:
#interface MySingleton
#property myProperty;
+(instancetype) sharedInstance;
#end
#implementation MySingleton
+ (instancetype) sharedInstance
{
static dispatch_once_t pred= 0;
__strong static MySingleton *singletonObj = nil;
dispatch_once (&pred, ^{
singletonObj = [[super allocWithZone:NULL]init];
singletonObj.myProperty = initialize ;
});
return singletonObj;
}
+(id) allocWithZone:(NSZone *)zone
{
return [self sharedInstance];
}
-(id)copyWithZone:(NSZone *)zone
{
return self;
}
this is a thread safe implementation and avoids the risk to create new objects by calling "alloc init" on your class. Attributes initialization has to occur inside the block, not inside "init" override for similar reasons.
This is an error that can be avoided by some disziplined convention which is to always use curly brackets followed by if and else.
+(PeopleDatabase *)getInstance {
#synchronized(self)
{
if (instance == nil)
NSLog(#"initializing");
instance = [[[self alloc] init] retain];
NSLog(#"Address: %p", instance);
}
return(instance);
}
If instance is nil then the very next statement and only that is executed. And that is the nslog and not the allocation. Then instance is allocated anyway, regardless wether it was used before or not. This will provide you with a new singleton on each call. BTW that causes a leak.
+(PeopleDatabase *)getInstance {
#synchronized(self)
{
if (instance == nil) {
NSLog(#"initializing");
instance = [[[self alloc] init] retain];
NSLog(#"Address: %p", instance);
}
}
return(instance);
}
But this error came in while debugging. It may confuse you but does not solve your original problem. Please add an alloc and init and retain for _arrayOfPeople as well.
-(id)init{
if(self = [super init]) {
Person* person = [[[Person alloc] initWithName:#"John" sname:#"Derovsky" descr:#"Some kind of description" iconName:#"johnphoto.png" title:Prof] retain];
_arrayOfPeople = [[[NSMutableArray alloc] init] retain]; //dont forget the release
[_arrayOfPeople addObject:person];
NSLog(#"array count = %d", [_arrayOfPeople count]); // <== array count = 1 !!!
[person release];
}
return self;
}
In your code _arrayOfPeople is nil and addObject is sent to nil which does not cause an abort but does not do anything either. Then count is sent to nil wich returns 0/nil.
in this function +(PeopleDatabase *)getInstance i think you need to place curly Braces correctly : like this
+(PeopleDatabase *)getInstance {
#synchronized(self)
{
if (instance == nil)
{
NSLog(#"initializing");
instance = [[[self alloc] init] retain];
NSLog(#"Address: %p", instance);
}
return instance ;
}
}

Resources