Singleton EXC_BAD_ACCESS - objective-c

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

Related

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

making NSArray global

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

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.

NSArray acts weirdly with objects going out of scope

I have a weird problems with NSArray where some of the members of the objects in my array are going out of scope but not the others:
I have a simple object called Section.
It has 3 members.
#interface Section : NSObject {
NSNumber *section_Id;
NSNumber *routeId;
NSString *startLocationName;
}
#property(nonatomic,retain) NSNumber *section_Id;
#property(nonatomic,retain) NSNumber *routeId;
#property(nonatomic,retain) NSString *startLocationName;
#end
#implementation Section
#synthesize section_Id;
#synthesize routeId;
#synthesize startLocationName;
//Some static finder methods to get list of Sections from the db
+ (NSMutableArray *) findAllSections:{
- (void)dealloc {
[section_Id release];
[routeId release];
[startLocationName release];
[super dealloc];
}
#end
I fill it from a database in a method called findAllSection
self.sections = [Section findAllSections];
In find all sections I create some local variables fill them with data from db.
NSNumber *secId = [NSNumber numberWithInt:id_section];
NSNumber *rteId = [NSNumber numberWithInt:id_route];
NSString *startName = #"";
Then create a new Section and store these local variable's data in the Section
Section *section = [[Section alloc] init];
section.section_Id = secId;
section.routeId = rteId;
section.startLocationName = startName;
Then I add the section to the array
[sectionsArray addObject:section];
Then I clean up, releasing local variables and the section I added to the array
[secId release];
[rteId release];
[startName release];
[locEnd_name release];
[section release];
In a loop repeat for all Sections (release local variables and section is done in every loop)
The method returns and I check the array and all the Sections are there. I cant seem to dig further down to see the values of the Section objects in the array (is this possible)
Later I try and retrieve one of the Sections
I get it from the array
Section * section = [self.sections objectAtIndex:row];
Then check the value
NSLog(#" SECTION SELECTED:%#",section.section_Id);
But the call to section.section_Id crashed as section.section_Id is out of scope.
I check the other members of this Section object and they're ok.
After some trial and error I find that by commenting out the release of the member variable the object is OK.
//[secId release];
[rteId release];
[startName release];
[locEnd_name release];
[section release];
My questions are:
Am I cleaning up okay?
Should I release the object added to an array and the local variable in the function?
Is my dealloc okay in Section?
Does this code look ok and should I be looking elsewhere for the problem?
I'm not doing anything complicated just filling array from DB use it in Table Cell.
I can comment out the release but would prefer to know why this works, and if I shouldn't be doing this. The only place that secId is released is in the dealloc.
You should not be releasing secId, rteId, or startName. secId and rteId are pointers to NSNumber instances created with a factory method that returns an already-autoreleased object. Static strings (i.e. #"") do not need to be released. You need to re-read the Memory Management Programming Guide. Then read it again ;-) It will be your friend.
You're releasing objects you don't own. You should read the memory management rules.
I'll second (third) the suggestion to read the memory management rules.
The TL;DR version is anything you alloc and call a method with init in the method name on is your responsibility to release. For instance:
NSString *string = [[NSString alloc] initWithFormat:#"%#", someObject];
In this case you must release string. However:
NSString *string = [NSString stringWithFormat:#"%#", someObject];
Here string is autoreleased. It's basically equivalent to this:
NSString *string = [[[NSString alloc] initWithFormat#"%#", someObject] autorelease];
...meaning that the next time through the event loop (which means possibly as soon as your function returns), the system will send a release message to it for you. Apple calls these "convenience methods".
If you have something like this:
NSString *string = #"foo";
Then string is pointing to an instance of NSString that is created by the runtime when your program initializes and won't go out of scope until your program terminates. Never release these either.
Again, read the guidelines and bookmark them. But this should answer your direct question.

Replace array display method?

I am curious how I might override the description method that is used when you do the following (see below) for an object. I basically want to better format the output, but am unsure about how I might go about setting this up.
NSLog(#"ARRAY: %#", myArray);
many thanks
EDIT_001
Although subclassing NSArray would have worked I instead decided that I would add a category to NSArray (having not used one before) Here is what I added ...
// ------------------------------------------------------------------- **
// CATAGORY: NSArray
// ------------------------------------------------------------------- **
#interface NSArray (displayNSArray)
-(NSString*)display;
#end
#implementation NSArray (displayNSArray)
-(NSString*)display {
id eachIndex;
NSMutableString *outString = [[[NSMutableString alloc] init] autorelease];
[outString appendString:#"("];
for(eachIndex in self) {
[outString appendString:[eachIndex description]];
[outString appendString:#" "];
}
[outString insertString:#")" atIndex:[outString length]-1];
return(outString);
}
#end
gary
If you're doing this a lot, the easiest way to reformat the display of your array would be to add a new prettyPrint category to the NSArray class.
#interface NSArray ( PrettyPrintNSArray )
- (NSSTring *)prettyPrint;
#end
#implementation NSArray ( PrettyPrintNSArray )
- (NSString *)prettyPrint {
NSMutableString *outputString = [[NSMutableString alloc] init];
for( id item in self ) {
[outputString appendString:[item description]];
}
return outputString;
}
#end
Obviously you'd need to alter the for loop to get the formatting the way you want it.
I'm assuming that you myArray variable is an instance of the NSArray/NSMutableArray class.
When NSLog() encounters the # character in its format string, it calls the -description: method on the object. This is a method on the root class, NSObject from which all other Cocoa classes inherit. -description: returns an NSString allowing any object that implements this method to be passed into NSLog(#"#",anyObject) and have a nicely formatted output. The string returned can be anything you care to construct.
For your specific problem, you could subclass NSMutableArray and override the -description: method with your own implementation. Then utilise your subclass instead of NSMutableArray.
For more information on NSObject and -description: see Apple's docs.
From Formatting string objects:
NSString supports the format characters defined for the ANSI C functionprintf(), plus ‘#’ for any object. If the object responds to the descriptionWithLocale: message, NSString sends that message to retrieve the text representation, otherwise, it sends a description message.
So to customize array conversion to string you should change NSArray descriptionWithLocale: implementation. Here's an example of how you can replace object method in run-time.