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

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.

Related

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;
}

how do I build up a global like integer array?

How do I build up a global like integer array?
I tried variations of the following:
#interface
int *iArray; //this space will vary depending upon need in the implementation
#implementation
...
int iArrayInit[4] = {1,2,3,4};
iArray = iArrayInit;
-bottom line: I need to keep index values in array that I can access easily, and use of [NSArray intValue] maybe to slow.
thanks
If it needs to be static you can declare an NSMutableArray as static in the implementation file and expose static methods to access it. When using an NSArray the values need to be of type id which NSNumber can do. Here is an example which currently is not thread safe.
//.h file
#interface Foo : NSObject
{
}
+(NSArray*)iArray;
+(void)addiArrayValue:(NSNumber*)value;
#end
//.m file
#implementation Foo
static NSMutableArray *_iArray;
+(void)initialize
{
if([Foo class] == self)
{
_iArray = [[NSMutableArray alloc] init];
}
}
+(NSArray*)iArray
{
return [[_iArray copy] autorelease];
}
+(void)addiArrayValue:(NSNumber*)value
{
[_iArray addObject:value];
}
#end
//Use
[Foo addiArrayValue:[NSNumber numberWithInt:10]];
[Foo addiArrayValue:[NSNumber numberWithInt:12]];
NSLog(#"%#", [Foo iArray]);

How to access a string in a class stored in an array?

I have a string (titleName) stored in a class (newNoteBook) stored in an array (myLibrary). I was trying to access it, but I only get a (null) printed in the log.
What am I doing wrong?
-(void) setupLibrary {
NoteBook *newNoteBook = [[NoteBook alloc] init];
newNoteBook.titleName = #"TEST";
NSLog(#"titleName:%#", newNoteBook.titleName); // this prints TEST in the log
[myLibrary addObject:newNoteBook];
NSLog(#"titleName:%#", [[self.myLibrary objectAtIndex:0] titleName]); // this prints (null) in the log)
}
There is nothing fancy in my class... simply:
#interface NoteBook : NSObject {
NSString *titleName; }
#property (nonatomic, retain) NSString *titleName;
#end
#implementation NoteBook
#synthesize titleName;
Try this
NSLog(#"titleName:%#", ((NoteBook *)[self.myLibrary objectAtIndex:0]).titleName);
Possible reasons:
myLibrary (the instance variable) is nil;
self.myLibrary is nil or its backing instance variable isn’t myLibrary;
[self.myLibrary objectAtIndex:0] is not the same object as newNoteBook because there was at least one other element in self.myLibrary.
Edit: you need to create a new mutable array and assign it to your property/instance variable myLibrary:
self.myLibrary = [NSMutableArray array];
or
myLibrary = [[NSMutableArray alloc] init];
Where you should this depend on how your class is used. If an instance of your class should always have valid myLibrary, a good place to do that is in -init:
- (id)init {
self = [super init];
if (self) {
myLibrary = [[NSMutableArray alloc] init];
}
return self;
}
Alternatively, if you want to lazily create myLibrary only when -setupLibrary is executed, create it in that method:
-(void) setupLibrary {
self.myLibrary = [NSMutableArray array];
NoteBook *newNoteBook = [[NoteBook alloc] init];
…
}
Don’t forget to release it in your -dealloc method:
- (void)dealloc {
[myLibrary release];
[super dealloc];
}
I think you are not type casting object from array -
NSLog(#"titleName:%#", [(NoteBook*)[self.myLibrary objectAtIndex:0] titleName]);
and you should alloc your array before adding object to it -
myLibrary = [[NSMutableArray alloc] init];
NSLog(#"titleName:%#", [self.myLibrary objectAtIndex:0].titleName);
Is correct as they said before you don't need to cast.

invalid CFArrayRef problem with Singleton object

I've built a singleton object to manage some data in my app
#interface MyCommon : NSObject {
NSArray *quizz;
int iCurrentQuestion;
};
+ (MyCommon *)singleton;
#property (retain) NSArray *quizz;
#property (assign) int iCurrentQuestion;
#end
MyCommon.m
#import "MyCommon.h"
// MyCommon.m:
#implementation MyCommon
static MyCommon * MyCommon_Singleton = nil;
#synthesize iCurrentQuestion;
+ (MyCommon *)singleton
{
if (nil == MyCommon_Singleton)
{
MyCommon_Singleton = [[MyCommon alloc] init];
NSLog(#"allocating MyCommon_Singleton at %#",MyCommon_Singleton);
}
else {
NSLog(#"accessing singleton : %#", MyCommon_Singleton);
}
return MyCommon_Singleton;
}
- (NSArray*) getQuizz{
return quizz;
}
- (void) setQuizz:(NSArray *)array {
quizz = [NSArray arrayWithArray:array];
NSLog(#"setQuizz : %#",quizz);
}
There is no problem for writing the quizz object (setQuizz), however when I try to access it for reading, I get a crash : the quizz looks invalid and Xcode notify me an invalid CFArrayRef
I don't know what's wrong with my code.
You provide a custom setter for quizz but it doesn't comply with how the property is declared.
You're not retaining quizz when you're setting a new value. It's likely to be released just after, leading to a crash when you access it.
You should write
- (void)setQuizz:(NSArray *)array {
if (quizz != array) {
NSArray *tmp = quizz;
quizz = [array retain]; // retain the new value
[tmp release]; // release the old one
}
NSLog(#"setQuizz : %#",quizz);
}
this is way more code than it needs to be. First if you are going to be providing your own method you should declare so in the #property declaration which you didn't. Also your not properly retaining your variables. Additionally you should be using dispatch_once() for a thread safe & fast way to guarantee the singleton is only created once.
#interface MyCommon : NSObject {}
#property(nonatomic, retain) NSArray *quiz;
#property (assign) int iCurrentQuestion;
+ (MyCommon *)singleton;
#end
#implementation MyCommon
#synthesize quiz;
#synthesize iCurrentQuestion;
-(id)init {
self = [super init];
if(self) {
quiz = [[NSMutableArray alloc init];
iCurrentQuestion = 0;
}
return self;
}
+ (MyCommon *)singleton {
static MyCommon *singleton = nil;
static dispatch_once_t pred;
dispatch_once(&pred, ^{
singleton = [[MyCommon alloc] init];
});
return singleton;
}
#end
then you just do
[MyCommon singleton].quiz = //some array

Singleton Class iPhone

Ok, I'm trying to avoid global variables, so I read up on singleton classes.
This is a try to set and read a mutable array, but the result is null.
//Content.h
#interface Content : NSObject {
NSMutableArray *contentArray;
}
+ (Content *) sharedInstance;
- (NSMutableArray *) getArray;
- (void) addArray:(NSMutableArray *)mutableArray;
#end
.
//Content.m
#implementation Content
static Content *_sharedInstance;
+ (Content *) sharedInstance
{
if (!_sharedInstance)
{
_sharedInstance = [[Content alloc] init];
}
return _sharedInstance;
}
- (NSMutableArray *) getArray{
return contentArray;
}
- (void) addArray:(NSMutableArray *)mutableArray{
[contentArray addObject:mutableArray];
}
#end
And in a ViewController I added #import "Content.h", where I try to call this:
NSMutableArray *mArray = [NSMutableArray arrayWithObjects:#"test",#"foo",#"bar",nil];
Content *content = [Content sharedInstance];
[content addArray:mArray];
NSLog(#"contentArray: %#", [content getArray]);
You need to alloc and init the array first. Personally I'd do it in the init method of the content class like so:
-(id)init{
if(self = [super init]){
…the rest of your init code…
contentArray = [[NSMutableArray alloc] init];
}
return self;
}
You never actually alloc/initialise the contentArray array.