NSMutableDictionary EXC_BAD_ACCESS - iphone

I know there are many questions about this topic but non of them work for me because mine is a little weird.
First of all I create a static singleton class. and declare a variable of NSMutableDictionary
static NSMutableDictionary* mydic
#implementation mySingleton
-(mySingleton*)getInstance
{
static mySingleton *sharedInstance;
#synchronized(self)
{
if(!sharedInstance)
{
sharedInstance = [[mySingleton alloc] init];
mydic = [[NSMutableDictionary alloc] initWithCapacity:1];
}
return sharedInstance;
}
}
-(NSMutableDictionary*)getDictionary
{
return myDic;
}
then I call this NSMutableDictionary from another class like the below.
NSMutableDictionary* singletonDictionary = [[mySingleton getInstance] getDictionary];
MyOtherClass* myclass = [singletonDictionary objectForKey:key];// Key is NSString
// Here I can see whole the values I added to myClass for that key
NSArray *checkKey = [singletonDictionary allKeys];
for(int i = 0; i < [singletonDictionary count]; i++)
{
NSLog(#"%#",[checkKey objectAtIndex:i]);// here I can see my key is there
}
[singletonDictionary removeObjectForKey:key];// here it crashes EXC_BAD_ACCESS
I am gonna get crazy about this problem. If someone has an idea please share it with me.
EDIT :
MyOtherClass * myinstance = [[MyOtherClass alloc] init];
// Fill up the instance with the desired variable here
// Forexample
// myinstance.name = [NSString stringWithFormat:#"myInstanceName"];
.
.
.
[[[mySingleton getInstance] getDictionary] setObject:myinstance forKey:key]// key is an NSString*
[myinstance release];
Thanks for help.
Omer Faruk KURT

So many problems, where to start...?
At least, it seems your getInstance method is not returning anything; it should probably return mySingleton. This could explain your EXEC_BAD_ACCESS, as singletonDictionary is probably nil as things stand.
Your singleton instantiation is wrong too - you need to check if the singleton has already been created, and return it if it has. Otherwise you can reallocate singletons, which is absurd.
Static references are poor design here, better to subclass and declare members in the header file.
This might fix your problems, but you're clearly jumping in at the deep end and you're going to encounter more trouble. I think you need to find good examples of code in texts or online and study those. If you do that pretty soon you'll learn the ropes.

The NSMutableDictionary retains objects added to the dictionary. When the objects are removed they are released. As a result, removing an object from the dictionary accesses the object. If you have previously released the object and it is dealloc'ed, then this can cause an exception to be raised. If you examine the state of the object prior to removing from the dictionary you will likely see that it has already been released and dealloced.

Related

how to fetch data from NSMutableArray ObjectAtIndex from integer value? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
I want to fetch data from my NSMutableArray, I am doing this
-(void)ViewDidLoad{
A_array = [[NSMutableArray alloc] init];
A_array = [NSMutableArray arrayWithObjects:#"4",#"6",#"2",#"3",#"0",#"5",#"1",#"2",#"4",#"1",#"0",#"2",#"4",#"2",#"0",#"3",nil]
var_Count_Answer_A = 0; // int
}
-(void)method_Second {
NSLog(#"%#",[A_array objectAtIndex:var_Count_Answer_A]); // This line is crashing if I click button again. First time line works fine but if we click button again and var_Count_Answer = 2 then it will crash.
NSString *str1 = [[NSString alloc]initWithFormat:#"%#",[A_array objectAtIndex:var_Count_Answer_A]]; // If I comment on NSLOG then this line will crash
A = [str1 integerValue];
NSLog(#"A is %d",A);
var_Count_Answer_A ++;
}
if I try this NSLog(#"%#",[A_array objectAtIndex:5]); // works fine
NSLog(#"%#",[A_array objectAtIndex:var_Count_Answer_A]); // var_Count_Answer_A =5; and crash
Any Idea or Suggestions would be highly appreciated.
Your code hurt my eyes
There are certain coding standards to be followed while writing code in Objective-C. Every language got one. They make code readable and understandable. You can refer to Cocoa Coding Guidelines and help yourself writing better looking code.
Explain Properly
Without the error message before crash no one can help you. Next time when you post about a crash, also explain the error message you got.
Was it a EXEC_BAD_ACCESS? If so it is the awesome garbage collector sweeping your array object away. Anyway your code sores my eyes and I am taking the privilege refactoring the code. Maybe it will help you.
A little bit of refactoring
NSArray *aArray;
- (void)viewDidLoad
{
[super viewDidLoad];
aArray = #[#"1", #"2", #"3", #"4"];
// or use[[NSArray alloc]initWithObjects:#"1", #"2", #"3", #"4", #"5"];
//Why do you need a mutable array while initializing it static?
}
- (void)methodSecond
{
static int counter = 0;
if (aArray) {
if (counter<aArray.count) {
NSLog(#"A is %u",[[aArray objectAtIndex:counter++]integerValue]);
} else {
counter = 0;
[self methodSecond];
}
}
}
Understand what you are doing
So a detail explanation of what I guess your problem is:
You're using [NSArray initWithObjects:] this creates an autoreleased object, and we got no control over its life time. And they get released if they are not referenced immediately after creating, which is probably whats happening your case. In my experience, mutable autoreleased object always sources bad access problems. So it is better to have the object alloc and inited, ie.. [[NSArray alloc]initWithObjects:] and I observe you are not adding/removing array members in run-time. There is no purpose of having a MutableArray.
In your code, you're creating two objects. The first array object is allocated and immediately dereferenced in the next line. Which is probably a mistake.
If you want to know more about auto-released objects. Read this.
Use
A_array = [[NSMutableArray alloc] initWithObjects:#"4",#"6",#"2",#"3",#"0",#"5",#"1",#"2",#"4",#"1",#"0",#"2",#"4",#"2",#"0",#"3",nil];
Instead you used.
A_array = [[NSMutableArray alloc] init];
A_array = [NSMutableArray arrayWithObjects:#"4",#"6",#"2",#"3",#"0",#"5",#"1",#"2",#"4",#"1",#"0",#"2",#"4",#"2",#"0",#"3",nil];
As I review Your Project is ARC disable try this Working fine for me.
ViewControler.h
#interface MasterViewController : UIViewController
{
NSMutableArray *A_array;
int var_Count_Answer_A;
}
ViewControler.m
-(void)viewDidLoad {
[super viewDidLoad];
A_array = [[NSMutableArray alloc] initWithObjects:#"4",#"6",#"2",#"3",#"0",#"5",#"1",#"2",#"4",#"1",#"0",#"2",#"4",#"2",#"0",#"3",nil];
var_Count_Answer_A = 0;
var_Count_Answer_A = 0; // int
}
-(IBAction)method_Second:(id)sender {
NSLog(#"%#",[A_array objectAtIndex:var_Count_Answer_A]);
NSString *str1 = [[NSString alloc]initWithFormat:#"%#",[A_array objectAtIndex:var_Count_Answer_A]]; // If I comment on NSLOG then this line will crash
int A = [str1 integerValue];
NSLog(#"A is %d",A);
var_Count_Answer_A++;
}
But As Everyone know at last there must be occur this exception.
NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 16 beyond bounds [0 .. 15]'
As trying to access array index object that does not exist.
And if you still have some error then First Enable NSZombie in your project Follow this.
-> "Product" menu, select "Edit Scheme", go to the "YourAp.app" stage in the left panel, and the "Arguments" tab on the right. You can then add NSZombieEnabled to the "Environment Variables" section and set the value to YES.
And Now Share your Crash Log.
in your code you are usimng two different varaibles once check thosetwo.
var_Count_Answer and var_Count_Answer_A
This error occurs because you are using an auto-released object.
When you call like:
A_array = [NSMutableArray arrayWithObjects:#"4",#"6",#"2",#"3",#"0",#"5",#"1",#"2",#"4",#"1",#"0",#"2",#"4",#"2",#"0",#"3",nil]
The A_array is an autoreleased object, you can't say when it'll be released. That is why this error occurs.
Solution:
Declare a property for the array like:
#property (nonatomic, strong) NSMutableArray *A_array;
Then modify your methods like:
-(void)ViewDidLoad
{
_A_array = [NSMutableArray arrayWithObjects:#"4",#"6",#"2",#"3",#"0",#"5",#"1",#"2",#"4",#"1",#"0",#"2",#"4",#"2",#"0",#"3",nil]
var_Count_Answer_A = 0; // int
}
-(void)method_Second
{
NSLog(#"%#",[_A_array objectAtIndex:var_Count_Answer_A])
NSString *str1 = [[NSString alloc]initWithFormat:#"%#",[_A_array objectAtIndex:var_Count_Answer_A]];
A = [str1 integerValue];
NSLog(#"A is %d",A);
var_Count_Answer_A ++;
}

iPhone - Problems with releasing memory - memory leaks

I'm having the code as below.
- (void)viewDidLoad
{
NSArray* myarr = [self createArray];
for (NSString* str in myarr)
{
NSLog(#"%#",str);
}
[myarr release];
}
-(NSArray*)createArray
{
NSArray* arr1 = [[NSArray alloc] initWithObjects:#"APPLE",#"MAC",#"IPHONE",nil];
return arr1;
}
When I "Build & Analyze", its showing two leaks. One at [myarr release] saying, incorrect decrement of the reference count of an object that is owned at this point. and Other at return arr1, saying, Potential leak of an object allocated on line 152 and stored into arr1.
From my above code, the method "createArray" is returning a pointer and I'm releasing it as well. Is my way of coding right or wrong?
From my above code, the method "createArray" is returning a pointer and I'm releasing it as well. Is my way of coding right or wrong?
that depends on how you look at it.
1) the ref counting looks ok
2) the static analyzer flags objc methods based on names, in some cases. so the issue will likely vanish if you rename createArray to newArray, or something named new*. so it expects a convention (the ones used by Apple) to be followed.
therefore, it's the message that's bit shallow, it doesn't really analyze the program, but bases its findings/results on convention -- and not an actual evident issue which a human can read.
If you're just using the array in your viewDidLoad method, then you don't need to alloc an array in there at all. You can just use an autoreleased array returned as 7KV7 suggested. You can return an autoreleased array in your -(void)createArray as well without alloc'ing an object. Here is an example.
- (void)viewDidLoad
{
NSArray* myarr = [self createArray];
for (NSString* str in myarr)
{
NSLog(#"%#",str);
}
}
-(NSArray*)createArray
{
return [NSArray arrayWithObjects:#"APPLE",#"MAC",#"IPHONE",nil];
}
If you don't have to alloc an object to use it, it makes for less, and cleaner code, IMO.
Try this
- (void)viewDidLoad
{
NSArray* myarr = [[NSArray alloc] initWithArray:[self createArray]];
for (NSString* str in myarr)
{
NSLog(#"%#",str);
}
[myarr release];
}
-(NSArray*)createArray
{
NSArray* arr1 = [[NSArray alloc] initWithObjects:#"APPLE",#"MAC",#"IPHONE",nil];
return [arr1 auotrelease];
}
The problem with your code is that
You do not allocate myarr using alloc or new so you do not take ownership of the object. Hence the issue in release.
You allocate arr1 so you take ownership of the object and you return arr1. Hence you do not release it. That is the reason for the leak.

iPhone memory management (with specific examples/questions)

Hey all. I know this question's been asked but I still don't have a clear picture of memory management in Objective-C. I feel like I have a pretty good grasp of it, but I'd still like some correct answers for the following code. I have a series of examples that I'd love for someone(s) to clarify.
Setting a value for an instance variable:
Say I have an NSMutableArray variable. In my class, when I initialize it, do I need to call a retain on it?
Do I do
fooArray = [[[NSMutableArray alloc] init] retain];
or
fooArray = [[NSMutableArray alloc] init];
Does doing [[NSMutableArray alloc] init] already set the retain count to 1, so I wouldn't need to call retain on it? On the other hand, if I called a method that I know returns an autoreleased object, I would for sure have to call retain on it, right? Like so:
fooString = [[NSString stringWithFormat:#"%d items", someInt] retain];
Properties:
I ask about the retain because I'm a bit confused about how #property's automatic setter works.
If I had set fooArray to be a #property with retain set, Objective-C will automatically create the following setter, right?
- (void)setFooArray:(NSMutableArray *)anArray {
[fooArray release];
fooArray = [anArray retain];
}
So, if I had code like this: self.fooArray = [[NSMutableArray alloc] init]; (which I believe is valid code), Objective-C creates a setter method that calls retain on the value assigned to fooArray. In this case, will the retain count actually be 2?
Correct way of setting a value of a property:
I know there are questions on this and (possibly) debates, but which is the right way to set a #property?
This?
self.fooArray = [[NSMutableArray alloc] init];
Or this?
NSMutableArray *anArray = [[NSMutableArray alloc] init];
self.fooArray = anArray;
[anArray release];
I'd love to get some clarification on these examples. Thanks!
According to Apple's Object Ownership Policy, any method that begins with the words alloc or new, or contains copy is owned by the caller.
To obtain ownership of an object, you must retain it.
So, in your first example, the retain is unnecessary because you already own the object.
The correct way to do this:
fooArray = [[NSMutableArray alloc] init];
Since autoreleased objects are owned by the current autorelease pool, you must call retain on them to gain ownership of them, so this example is correct:
fooString = [[NSString stringWithFormat:#"%d items", someInt] retain];
This would work fine as well:
self.fooString = [NSString stringWithFormat:#"%d items", someInt]; //retained by property setter
And for your last example using the property setter, this would be the correct way to do it:
NSMutableArray *anArray = [[NSMutableArray alloc] init];
self.fooArray = anArray;
[anArray release];
Instead of having to do the above, I'd suggest the following solution:
self.fooArray = [NSMutableArray arrayWithCapacity:10];
arrayWithCapacity: will return an autoreleased NSMutableArray, which is the retain-ed by the property setter method. :)
Ideally you would want to use the accessors whenever possible, especially when dealing with objects as they help avoid many memory issues. So even for instance variables, you should do:
self.fooArray = ...;
instead of
fooArray = ...;
The reason why you should declare properties for object instance variables is because the memory management is slightly more complicated, and recreating it by hand each time is tricky. The correct setter for a nonatomic, retained property would look like:
- (void)setFoo:(NSArray *)aFoo {
if (foo == aFoo) {
return;
}
NSArray *oldFoo = foo;
foo = [aFoo retain];
[oldFoo release];
}
You are right about the instance variable having a retain count of 2 when you do something like this (assuming foo is retained):
self.foo = [[NSMutableArray alloc] init];
The first retain count is coming from alloc, and the second one from your synthesized setter. Any of these should work:
// longer, explicit version, releases immediately (more efficient)
NSMutableArray *aFoo = [[NSMutableArray alloc] init];
self.foo = aFoo;
[aFoo release];
// autoreleased, not so bad unless you're a memory management freak
self.foo = [[[NSMutableArray alloc] init] autorelease];
// an even shorter version of the above
self.foo = [NSMutableArray array];
To create private properties, you can declare them as a class extension in the .m implementation file. To give an example, consider a simple Person object, which has a name, and a boolean property didSave which simply indicates whether the object has been saved to some database or not. Since we don't want to expose this to the outside world, but still keep the benefits of properties inside the implementation file, we can create the header file will all instance variables (public, private, protected) and only public properties:
// Person.h
#interface Person {
NSString *name;
#private
BOOL didSave;
}
#property (nonatomic, retain) NSString *name;
#end
But declare private properties inside the implementation:
// Person.m
// property is declared as a class extension, making it
// invisible to the outside world.
#interface Person ()
#property BOOL didSave;
#end
#implementation
// synthesize as normal
#synthesize name, didSave;
#end
First of all, with this line:
fooArray = [[NSMutableArray alloc] init];
fooArray will automatically have a retain count of 1.
Second, yes, it's 2. And your guess on the setter implementation is correct.
Third, the latter one is right

Can't Figure Out How To Fix Memory Leaks on iPhone

I was running Leaks tool and discovered a massive leak in my Dictionary mutableDeepCopy but I can't figure out what's wrong with the code. Any suggestions?
#interface RootViewController : UIViewController{
NSDictionary *immutableDictionary;
NSMutableDictionary *mutableDictionary;
}
Here is the line of code that's highlighted in Instruments
self.mutableDictionary = [self.immutableDictionary mutableDeepCopy];
Here is the method for creating a mutable copy of a Dictionary
#interface NSDictionary(MutableDeepCopy)
-(NSMutableDictionary *)mutableDeepCopy;
#end
Here is method implementation, I've highlighted the code that Leaks saids is leaking 100%
- (NSMutableDictionary *) mutableDeepCopy {
NSMutableDictionary *dictionaryToReturn = [NSMutableDictionary dictionaryWithCapacity:[self count]];
NSArray *keys = [self allKeys];
for(id key in keys) {
id value = [self valueForKey:key];
id copy = nil;
if ([value respondsToSelector:#selector(mutableDeepCopy)]) {
copy = [value mutableDeepCopy];
} else if ([value respondsToSelector:#selector(mutableCopy)]) {
copy = [value mutableCopy]; //This is the Leak
}
if (copy == nil) {
copy = [value copy];
}
[dictionaryToReturn setValue:copy forKey:key];
}
return dictionaryToReturn;
}
You need to analyse this in light of Apple's Memory Management Rules.
Starting with this line:
self.mutableDictionary = [self.immutableDictionary mutableDeepCopy];
I would expect mutableDeepCopy to return an object I own, so at some point I need to release or autorelease it. e.g.
NSMutableDeepCopy* temp = [self.immutableDictionary mutableDeepCopy];
self.mutableDictionary = temp;
[temp release];
or
self.mutableDictionary = [[self.immutableDictionary mutableDeepCopy] autorelease];
So now we need to look at mutableDeepCopy. Because it has 'copy' in the name it needs to returned an "owned" object which, in practice means "forgetting" to release the returned object. You have already failed to do that when you create the returned object in the first line, since dictionaryWithCapacity: gives you an object you do not own. Replace it with
NSMutableDictionary *dictionaryToReturn = [[NSMutableDictionary alloc] initWithCapacity:[self count]];
Now you own it.
It is important that you make your mutableDeepCopy obey the rules because it means you can treat the objects returned from mutableDeepCopy, mutableCopy and copy in exactly the same way. In all three cases you own the object copy that you insert into the array. Because you own it, you must release it or it'll leak as you found out. So, at the end of the loop, you need
[copy release];
That'll stop the leak.
How is your property declared? If is is retain or copy, then this doesn't leak.
Your problem is that the name mutableDeepCopy suggests that it returns a retained object, and not an autoreleased one as it actually does.
Edit:
And at the mutableDeepCopy itself, you need to release the copy variable after adding to the dictionary.
mutableCopy increments the retain count of the object, as does setValue:forKey:. This means that when dictionaryToReturn is dealloc'ed, the object that had mutableCopy called still has a retain count of one.
Try doing this instead:
copy = [[value mutableCopy] autorelease];

NSDictionary functionality question

So I am trying to save arrays into an NSDictionary on the fly. Let me show you the code and explain what is going on.
for (int x= 0; x <[appDelegate.people count]; x++) {
Person *aPerson = [[Person alloc] init];
aPerson = [appDelegate.people objectAtIndex:x];
if ([appDelegate.groupedBusiness objectForKey:aPerson.business_name] == nil) {
NSMutableArray *newBusiness = [[NSMutableArray alloc] init];
//if the business does not exist in the dict, add the person to the business and add it to dict.
[newBusiness addObject:aPerson];
[appDelegate.groupedBusiness setObject:newBusiness forKey:aPerson.business_name];
[newBusiness release];
newBusiness = nil;
//NSLog(#"%#", appDelegate.groupedBusiness);
} else {
NSMutableArray *existingBusiness= [appDelegate.groupedBusiness objectForKey:aPerson.business_name];
[existingBusiness addObject:aPerson];
//THIS IS THE LINE I AM NOT SURE ABOUT!!!
[appDelegate.groupedBusiness setObject:existingBusiness forKey:aPerson.business_name];
[existingBusiness release];
existingBusiness = nil;
//NSLog(#"%#", appDelegate.groupedBusiness);
}
}
Alright, so the appDelegate has an array of "People" that has a whole bunch of attributes about a person. I am trying to set up a dictionary to sort them by their business names. I am doing this by creating an array and saving it in the dictionary with the business_name as the key. Each iteration of the loop I check to see if the key exists, if it does, pull out the existing array, add the person you are checking, and resave it to the dictionary. However, this does not appear to be happening. Is there some exotic behavior in the NSDictionary class that would prevent that? I have poured over the class web page and can't find anything. Sorry if this is a noobie question, I am still trying to understand the objective-c classes. Thanks!
Why do you release existingBusiness? You are not creating an object, just taking the pointer from an array. When you invoke release, retainCount became 0 and object deallocs.
Just remove the following two lines:
[existingBusiness release];
existingBusiness = nil;
and everything should work fine.
You're way overcomplicating this, not to mention leaking a couple things.
for (Person *aPerson in appDelegate.people) {
NSMutableArray *business = [appDelegate.groupedBusiness objectForKey:aPerson.business_name];
if (!business) {
business = [NSMutableArray array];
[appDelegate.groupedBusiness setObject:business forKey:aPerson.business_name];
}
[business addObject:aPerson];
}
Not an answer, but some coding style issues.
Use fast iteration if you don't need the index:
for (Person *aPerson in appDelegate.people) {
Use convenience constructors; it makes your code more readable (remember to remove the "release" at the end):
NSMutableArray *newBusiness = [NSMutableArray arrayWithObject:aPerson];
Avoid duplicate logic where possible:
NSMutableArray * business = [appDelegate.groupedBusiness objectForKey:aPerson.business_name;
if (!business) {
business = [NSMutableArray array];
}
[business addObject:aPerson];
[appDelegate.groupedBusiness setObject:business forKey:aPerson.business_name];
The "setObject:existingBusiness" call does changes nothing apart from wasting CPU cycles, but in the case above, it makes the code somewhat more readable.
[appDelegate.groupedBusiness setObject:existingBusiness forKey:aPerson.business_name];
[existingBusiness release];
existingBusiness = nil;
This should all be removed. existingBusiness is already in the dict, and it's a mutable object - when you're adding a person to it, this will be reflected in the dictionary as well as it's the same object you're dealing with. Apart from that you have a couple of memory leaks as Daniel points out.