making NSArray global - objective-c

i have NSarray which i want to acces from all of my methods,(i want it Global), i m going to populate this array in one of my methods defined in .m file(only once).
my question is ... is it really possible to declare a NSArray in .h and define it place somewhere else or it just has to be defined when it is declared(initialization).
MY CURRENT CODE
.h file
#interface slots2ViewController : UIViewController {
NSArray* paylinesArr;
}
i m calling follwing method from ViewDidLoad
.m file
-(void)init_payline_arr
{
NSString* filePath = #"/Users/net4uonline/Desktop/slots2/paylines.txt";//filepath...
NSString *fileContents = [NSString stringWithContentsOfFile: filePath];
paylinesArr = [fileContents componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];
}
i m not able to use paylinesArr array from other methods the app crashes if follwing function is getting called
-(IBAction)ShowVal
{
NSLog(#"number of elements! %#",[paylinesArr count]);
}
Or
should i use NSMutabbleArray instead?
if you want to see then i have uploaded my desktop video while i m using debug tools!
the link to video
in this video i press the record button of the debugger(i have ns zombie enabled and the retain count as well),the app starts,i press spin button and apparently it crashes...then i show you the code which has
paylinesArr = [[fileContents componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]] retain];
which retains the paylineArr

NSMutableArray won't help you! The reason of your error is that your paylinesArr variable is autorelease variable, so probably it was deallocated before ShowVal is called. Try to retain it like
-(void)init_payline_arr {
...
paylinesArr = [[fileContents componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]] retain];
...
}
This should work. But don't forget to release it in viewDidUnload method:
- (void)viewDidUnload {
[super viewDidUnload];
...
[paylinesArr release];
}

Related

Singleton dictionary is empty, and I don't see why

I have an iOS app that matches incoming text fields to standard fields used to import records. My problem is that a NSMutableDictionary that uses those fields is empty! Here is the code that saves the mapping:
-(void)mapUserFields: (id) sender { // move contents of each textField when user has finished entering it
SingletonDictionary *sd = [SingletonDictionary sharedDictionary];
UITextField *tf = (UITextField *)sender; // textfield contains the pointer to user's half of the equation
int tagValue = (int)tf.tag; // get the tag value
[sd.dictionaryOfUserIndexes setObject:tf.text forKey:[NSString stringWithFormat:#"%d", tagValue]]; // value found in textField id'd by tag
NSLog(#"\nfield.text: %# tagValue: %d nsd.count: %d\n",tf.text, tagValue, sd.dictionaryOfUserIndexes.count);
}
This is the result of the NSLog:
field.text: 1 tagValue: 38 nsd.count: 0
This is the definition of the singleton in the .h file:
#property (nonatomic, retain) NSMutableDictionary *dictionaryOfUserIndexes;
This is the code to initialize the singleton in the .m file:
//-- SingletonDictionaryOfUserIDs --
+ (id) sharedDictionary {
static dispatch_once_t dispatchOncePredicate = 0;
__strong static id _sharedObject = nil;
dispatch_once(&dispatchOncePredicate, ^{
_sharedObject = [[self alloc] init];
});
return _sharedObject;
}
-(id) init {
self = [super init];
if (self) {
dictionaryOfUserIndexes = [NSMutableDictionary new];
}
return self;
}
#end
I believe my problem is because the sd.dictionaryOfUserIndexes is not initialized, but I am not sure if that's true, and if so, how to initialize it (I tried several different variants, all of which created build errors). I looked on SO and Google, but found nothing that addresses this particular issue. Help would be greatly appreciated!
There are a few things we could improve in this code, but the only thing wrong with it is the reference to dictionaryOfUserIndexes in the init method. The code as posted wouldn't compile, unless: (a) you have a line like:
#synthesize dictionaryOfUserIndexes = dictionaryOfUserIndexes;
so that the backing variable is named without the default _ prefix, or (b) you refer to the ivar with the default prefix, as in:
_dictionaryOfUserIndexes = [NSMutableDictionary new];
The other way -- preferable in most every context except within an init method -- is to use the synthesized setter, like:
self.dictionaryOfUserIndexes = [NSMutableDictionary new];
But with that change alone (so it will compile) your code runs fine, adds a value to the dictionary and logs an incremented count.

NSString instance variable crash

I was on a roll learning objective-c, but I just don't get this. I'm declaring an nsstring i-var, i set the value in the init method, and then when I access that ivar in a later instance method, it crashes or behaves unpredictably.
//heres what my declaration looks like
#interface StockData : CCNode {
NSString *myPath;
NSString *myPath2;
}
-(id) init
{
if ( (self = [super init]) ){
myPath = [[NSBundle mainBundle] pathForResource:#"stocks" ofType:#"sqlite"];
myPath2 = #"test";
CCLOG(#"mypath::::%#",[myPath class]);
CCLOG(#"mypath2::::%#",[myPath2 class]);
}
return self;
}
-(void) getChunk{
CCLOG(#"mypath_getchunk::::%#",[myPath class]);//this crashes
CCLOG(#"mypath2_getchunk::::%#", [myPath2 class]);//this doesn't
....
i am using cocos2d, and I am calling getChunk method in an scheduled update method like this:
-(void) updateOncePerSecond:(ccTime)delta{
if(!sd){
sd = [StockData initStockData];
[self addChild:sd];
}
[sd getChunk];
NSLog([sd getDate]);
}
the first time it iterates through I get this:
2012-03-19 20:33:58.591 HelloWorld[6777:10a03] mypath_getchunk::::__NSCFString
2012-03-19 20:33:58.591 HelloWorld[6777:10a03] mypath2_getchunk::::__NSCFConstantString
the second time it iterates through(if it doesn't crash):
2012-03-19 20:33:59.589 HelloWorld[6777:10a03] mypath_getchunk::::NSMallocBlock
2012-03-19 20:33:59.589 HelloWorld[6777:10a03] mypath2_getchunk::::__NSCFConstantString
why does it crash sometimes, and not other times. Why is it turning into a mallocblock? Are NSString's buggy, or am I doing it wrong. other variables seem to be working fine? How can I get my NSCFString to behave like that NSCFConstantString. I like that one better cause it doesn't crash. Any advice would be much appreciated!!!
thanks!
The string pathForResource:ofType: is autoreleased, which means it will be released “sometime later”. If you want to keep it alive, retain it:
myPath = [[[NSBundle mainBundle] pathForResource:#"stocks" ofType:#"sqlite"] retain];
And don't forget to release it later in dealloc.

Can't add object to static NSMutableArray

I have a static variable on appDelegate declared like this:
appdelegate.h file:
+(NSMutableArray*)allBanco;
+(void)setAllBanco:(NSMutableArray*)value;
appdelegate.m file:
static NSMutableArray * allBanco;
+(NSMutableArray*)allBanco
{
return allBanco;
}
+(void)setAllBanco:(NSMutableArray*)value
{
if(allBanco != value)
{
[allBanco release];
allBanco = [value copy];
}
}
I tried to acess it on other class
on .m file:
#import "AppDelegate.h"
[[AppDelegate allBanco] addObject:testeObj];
i cant understand why,i can log the
NSLog(#"%i",[[AppDelegate allBanco] count]);
and goes ok.
I tried :
NSMutableArray * temp = [[[NSMutableArray alloc]init]autorelease];
temp = [AppDelegate allBanco];
[temp addObject:testeObj];
[AppDelegate setAllBanco:temp];
and doest work.
Considering you created your array properly, keep in mind that -copy returns an immutable copy, so you may crash later when modifying it.
Now that you added your error, I'm quite sure this is indeed the problem:
-[__NSArrayI addObject:]: unrecognized selector sent to instance
You tried to add an object in a NSArray, not a NSMutableArray. Try using -mutableCopy.
You haven't created an object for allBanco to point to. Change your method so that you can create one if it doesn't exist yet:
+(NSMutableArray*)allBanco
{
if (!allBanco)
allBanco = [[NSMutableArray alloc] init];
return allBanco;
}

Objective C Reassignment/Memory Management Crash

As a relative Objective-C beginner, I'm obviously still not grasping certain memory management rules. I can't figure out how to make this not crash:
#interface MyClass { NSArray *playerArray4th; }
- (void) viewDidLoad { playerArray4th = [self getAudioPlayersForSoundFile:#"rimshot" ofType:#"aif"]; }
- (NSArray*) getAudioPlayersForSoundFile:(NSString*)soundFileName ofType:(NSString*)soundFileType {
//code instantiating objects....
NSArray *toRet = [[NSArray alloc] initWithObjects:toRetTickPlayer,toRetTickPlayerCopy,toRetTickPlayerCopy2,toRetTickPlayerCopy3, nil];
return toRet;
}
Then later, in a different function:
NSArray *currentArray = playerArray4th;
[currentArray release];
currentArray = nil;
currentArray = [self getAudioPlayersForSoundFile:fileName ofType:ofType];
And it crashes when trying to access the array again:
- (void) playSound:(NSString*)soundType {
AVAudioPlayer *currentPlayer;
if ([soundType isEqualToString:#"4th"]) {
if (playerArray4thCounter >= [playerArray4th count]) playerArray4thCounter = 0;
NSLog(#"Playing from array: %#",playerArray4th);
currentPlayer = [playerArray4th objectAtIndex:playerArray4thCounter];
playerArray4thCounter++;
}
}
Try to learn about properties and about using getters and setters. Don't take shortcuts unless you know exactly what's going on.
So define the playerArray4th property in your header file:
#property (nonatomic,retain) NSArray *playerArray4th;
And then in your .m file create getter/setter:
#synthesize playerArray4th;
Then, always use self.playerArray4th for assigning and getting the variable. The prior objects will be released when needed.
So this will not leak:
self.playerArray4th = [NSArray arrayWithObjects:#"text",#"text",nil];
self.playerArray4th = [NSArray arrayWithObjects:#"new array",#"text",nil];
because the second assignment releases the first array.
Furthermore, read about using autorelease. In short, if you alloc, copy or new, you should either release or autorelease. There's a lot to read about this here on SO which I will not repeat here now.
Don't forget to put self.playerArray4th = nil; in your dealloc method.

Singleton EXC_BAD_ACCESS

so I have a class that I declare as a singleton and in that class I have a NSMutableArray that contains some NSDictionaries with some key/value pairs in them. The trouble is it doesn't work and I don't know why... I mean it crashes with EXC_BAD_ACCESS but i don't know where. I followed the code and it did create a new array on first add, made it to the end of the function ..and crashed ...
#interface dataBase : NSObject {
NSMutableArray *inregistrari;
}
#property (nonatomic,retain) NSMutableArray *inregistrari;
-(void)adaugaInregistrareCuData:(NSDate *)data siValoare:(NSNumber *)suma caVenit:(BOOL)venit cuDetaliu:(NSString *)detaliu;
-(NSDictionary *)raportIntreData:(NSDate *)dataInitiala siData:(NSDate *)dataFinala;
-(NSArray *)luniDisponibileIntreData:(NSDate *)dataInitiala siData:(NSDate *)dataFinala;
-(NSArray *)aniDisponibiliIntreData:(NSDate *)dataInitiala siData:(NSDate *)dataFinala;
-(NSArray *)vectorDateIntreData:(NSDate *)dataI siData:(NSDate *)dataF;
-(void)salveazaInFisier;
-(void)incarcaDinFisier;
+ (dataBase *)shareddataBase;
#end
And here is the .m file
#import "dataBase.h"
#import "SynthesizeSingleton.h"
#implementation dataBase
#synthesize inregistrari;
SYNTHESIZE_SINGLETON_FOR_CLASS(dataBase);
-(void)adaugaInregistrareCuData:(NSDate *)data siValoare:(NSNumber *)suma caVenit:(BOOL)venit cuDetaliu:(NSString *)detaliu{
NSNumber *v=[NSNumber numberWithBool:venit];
NSArray *input=[NSArray arrayWithObjects:data,suma,v,detaliu,nil];
NSArray *keys=[NSArray arrayWithObjects:#"data",#"suma",#"venit",#"detaliu",nil];
NSDictionary *inreg=[NSDictionary dictionaryWithObjects:input forKeys:keys];
if(inregistrari == nil) {
inregistrari=[[NSMutableArray alloc ] initWithObjects:inreg,nil];
}else {
[inregistrari addObject:inreg];
}
[inreg release];
[input release];
[keys release];
}
It made it to the end of that adaugaInregistrareCuData ... ok . said the array had one object ... and then crashed
Try adding "NSZombieEnabled" with value "YES" to your arguments on your executeable:
Right click your executeable, select get info and add that entry to the variables in the bottom list.
This will tell you what datatype has crashed.
Using build & analyze it tells me that you are releasing inreg, input and keys twice.
All three variables will be autoreleased, your manual release will cause the later autorelease to fail and give you your BAD_ACCESS.
Don't manually release them, remove these three lines from your code:
[inreg release];
[input release];
[keys release];