iphone app crashing when I'm using an NSMutableDictionary - iphone

Got this code in my controllers (void)viewDidLoad method
self.purchasesPerClassification = [NSMutableDictionary
dictionaryWithObjects:[NSArray arrayWithObjects:#"Moo",nil]
forKeys:[NSArray arrayWithObjects:#"MooKey",nil]
];
as far I can under stand these are auto release as I have not used alloc init,
and in my dealloc i have
[self.purchasesPerClassification release];
this is part of a controller with UITableViewController and this controller is created an loaded from a main container and added to the main contollers navigationController this seems to make my app crash in the simulator as when I dont have it in the code it works fine any pointers on why this is crashing
heres the .h
#interface FirstAiderInsurancePurchasesViewController : UITableViewController {
NSArray * availableClassifications;
NSMutableDictionary * purchasesPerClassification;
}
#property(nonatomic, retain) NSArray * availableClassifications;
#property(nonatomic, retain) NSMutableDictionary * purchasesPerClassification;
#end
and heres the .m parts
#implementation FirstAiderInsurancePurchasesViewController
#synthesize availableClassifications;
#synthesize purchasesPerClassification;
- (void)viewDidLoad {
[super viewDidLoad];
self.availableClassifications = [NSMutableArray arrayWithObjects:#"Completed",#"Recover's",nil];
self.purchasesPerClassification = [NSMutableDictionary dictionaryWithObjects:[NSArray arrayWithObjects:#"Object",nil]
forKeys:[NSArray arrayWithObjects:#"ObjectKey",nil]];
}
- (void)dealloc {
[super dealloc];
self.availableClassifications = nil;
self.purchasesPerClassification = nil;
}
I've tried both
[purchasesPerClassification release];
as well and its crashing when I go back to the root controller

Firstly, what is the property definition of purchasesPerClassification?
Anyway, assuming it's copy or retain, you probably want either:
self.purchasesPerClassification = nil;
or
[purchasesPerClassification release];

[NSMutableDictionary dictionaryWithObjects] return an autoreleased instance
you have not to [self.purchasesPerClassification release];
but [purchasesPerClassification release]

Related

objective-c beginner: getter setter prob and EXC_BAD_ACCESS error

Iam getting an EXC_BAD_ACCESS all the time and I cannot figure out why...
Simple task:
The Parser Class pases XML with touchXML in an NSMutableArray called listArray.
In the Method grabCountry I can access the listArray and listArray.count works well.
Now I need the listArray.count in another Class the MasterViewController.
But Im getting an EXC_BAD_ACCESS error all the time.
Please help!
Here is the code snipplet:
Parser.h
#import <Foundation/Foundation.h>
#interface Parser : NSObject
#property (strong, retain) NSMutableArray *listArray;
#property (strong, retain) NSURL *url;
-(void) grabCountry:(NSString *)xmlPath;
#end
Parser.m
#import "Parser.h"
#import "TouchXML.h"
#implementation Parser
#synthesize listArray;
#synthesize url;
-(void) grabCountry:(NSString *)xmlPath {
// Initialize the List MutableArray that we declared in the header
listArray = [[NSMutableArray alloc] init];
// Convert the supplied URL string into a usable URL object
url = [NSURL URLWithString: xmlPath];
//XML stuff deleted
// Add the blogItem to the global blogEntries Array so that the view can access it.
[listArray addObject:[xmlItem copy]];
//works fine
NSLog(#"Amount: %i",listArray.count);
}
#end
MasterViewController.h
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
#import "TouchXML.h"
#import "Parser.h"
#class Parser;
#interface MasterViewController : UITableViewController{
Parser *theParser;
}
#end
MasterViewControlelr.m
- (void)viewDidLoad
{
NSString *xmlPath = #"http://url/to/xml.xml";
theParser = [[Parser alloc] init];
//Starts the parser
[theParser grabCountry:xmlPath];
//Here I want to access the Array count, but getting an BAD ACCESS error
NSLog(#"Amount %#",[theParser.listArray count]);
[super viewDidLoad];
}
Can anyone explain me what the problem here is?
Thanks!
Internally, each #property has a corresponding instance variable.
In your -grabCountry method, you are directly accessing the instance variable in the statement listArray = [[NSMutableArray alloc] init]; (same with url = [NSURL URLWithString: xmlPath];), instead of the #property's setter method, causing the NSMutableArray that you alloc-init'd to not be retained by the property. To invoke the #property's setter method, you should call
NSMutableArray *temp = [[NSMutableArray alloc] init];
self.listArray = temp; // or [self setListArray:temp];
[temp release];
If you want to have Xcode show an error when you are directly accessing the instance variable of an #property, you can have #synthesize listArray = _listArray, which changes the name of the instance variable to _listArray.
Generally, if there is an alloc-init, there must be a corresponding release (except if using Automatic Reference Counting).
Also, in the [listArray addObject:[xmlItem copy]]; statement, the call to copy is not needed, as NSArrays retain every object that is added to them. Calling copy also increases the retain count, which is another leak. Instead, you should just have [self.listArray addObject:xmlItem];
You are getting EXC_BAD_ACCESS because in NSLog(#"Amount %#",[theParser.listArray count]);, you are using %# format specifier, which is for NSStrings. You want to print the array's count, an integer, so you should be using %d or %i.

Store UIImageViews in NSMutableDictionary

I have simple question. This is my header file :
#import <UIKit/UIKit.h>
#interface FirstFaceController : UIViewController
#property (nonatomic,retain) NSMutableDictionary *face1Layers;
#end
This .m, here i init my Dictionary and put where UIImageView :
#import "FirstFaceController.h"
#implementation FirstFaceController
#synthesize face1Layers;
-(void) dealloc {
[face1Layers release];
[super dealloc];
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.face1Layers = [NSMutableDictionary dictionary];
[self.face1Layers setObject:
[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"pic.png"]]
forKey:#"pic"];
[self.view addSubview:[self.face1Layers objectForKey:#"pic"]];
if ( [[face1Layers objectForKey:#"pic"] superview] == nil ) {
//....
}
}
Then i call [[face1Layers objectForKey:#"pic"] superview] i have "EXC_BAD_ACCESS".
Why?
Try to do this:
NSMutableDictionary* tempDict = [[NSMutableDictionary alloc] init];
self.face1Layers = tempDict;
UIImageView* picView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"pic.png"]];
[self.face1Layers setObject:picView forKey:#"pic"];
[picView release];
[tempDict release];
Do not create and insert yours NSMutableDictionary and UIImageView throught a single line of code because you have leaks.
In the first case, if you do the following you have a retain count of two. face1Layers has a retain policy.
self.face1Layers = [[NSMutableDictionary alloc] init];
You can avoid this splitting the code as I explained before or send an autorelease message to the initialized object.
In the second case, when you add an object in NSDictionary or NSArray (and theirs subclasses), these classes retain added objects.
Hope it helps.
Well, I think there are a couple of things wrong here:
You never allocate the dictionary as in NSMutableDictionary alloc init
The UIImageView is allocated but never released. I would allocate before setting it as object, and then add it, and then release it

iPhone - Objective-C - Memory Leak with initWithArray

I am using the code below to set my two NSArray ivars:
The issue is, I keep getting a memory leak on the following lines:
followingFriendsArray = [[NSArray alloc] initWithArray:friend.Following];
followerFriendsArray = [[NSArray alloc] initWithArray:friend.Followers];
Is this not the correct way to set ivars from an existing NSArray of items? Any help would be appreciated. I've also tried to autorelease the above two lines, but when I actually access them in another method I get an error that they've already been released.
I have included my Interface and Implementation code below:
Interface .h:
NSArray *followingFriendsArray;
NSArray *followerFriendsArray;
#property (nonatomic, retain) NSArray *followingFriendsArray;
#property (nonatomic, retain) NSArray *followerFriendsArray;
Implementation .m:
- (void)handlerGetFollowingInformation:(id)value {
BOOL success = [Utility checkWebServiceErrors:value controller:self.navigationController];
if (success) {
Friend *friend = (Friend *)value;
followingFriendsArray = [[NSArray alloc] initWithArray:friend.Following];
followerFriendsArray = [[NSArray alloc] initWithArray:friend.Followers];
}
}
This is how I need to access the arrays:
- (void)followersButtonTapped:(id)sender {
FollowingVC *fvc = [[FollowingVC alloc] initWithNibName:#"FollowingViewController" bundle:nil];
fvc.friends = followerFriendsArray;
[self.navigationController pushViewController:fvc animated:YES];
[fvc release];
}
I release my two ivars in the following way as per usual:
- (void)viewDidUnload {
self.followingFriendsArray = nil;
self.followerFriendsArray = nil;
[super viewDidUnload];
}
- (void)dealloc {
[followingFriendsArray release];
[followerFriendsArray release];
[super dealloc];
}
I mean the code works just fine, it's just that I'm concerned about said memory leaks when I run the "Leaks" performance tool.
OK
you should not use autorelease in this case, but you have to release the arrays by calling :
[followingFriendsArray release];
[followerFriendsArray release];
you can do it:
when you don't need to use them any more.
in the dealloc method in your .m file.
option 2looks like that -
- (void)dealloc {
[followingFriendsArray release];
[followerFriendsArray release];
[super dealloc];
}
BTW -
if you don't manipulate the arrays after creating them (add / remove objects) you should use an immutable array (NSArray).
Good Luck
Your method handlerGetFollowingInformation is assigning new values to followingFriendsArray and followerFriendsArray without releasing the previous contents. If you call this method more than once on the same instance you will leak.
CRD is right that the arrays are not released inside the handlerGeFollowingInformation method but the fix is maybe overkill. What you need to do is to use self. so that the setter method is called which does that automatically. You could should look like this:
- (void)handlerGetFollowingInformation:(id)value {
BOOL success = [Utility checkWebServiceErrors:value controller:self.navigationController];
if (success) {
Friend *friend = (Friend *)value;
self.followingFriendsArray = [[NSArray alloc] initWithArray:friend.Following];
self.followerFriendsArray = [[NSArray alloc] initWithArray:friend.Followers];
}
}
Easy fix but hard to spot and I ran into this issue over and over again especially when I started to dealloc are the properties.
-Andy

iPhone: Memory Leak in Custom Class and NSMutableDictionary

I've spent a couple of days trying to find out what's going on. I have read loads of Memory Management documentation and I am sick to death of hearing "for every alloc you need a release" - I know that and I still can't figure out why my code is producing memory leaks.
I am writing a simple custom class with an NSMutableDictionary as one of its properties. Basically it mimics an XMLELement. I cannot for the life of me figure out why the allocation of a dictionary is causing a memory leak. The leak occurs on the device as well as the simulator - 5 leaks on the device, and 20 on the simulator.
The leak occurs when I declare and allocate the variable *tmp.
There is also a leak when I set the attribute details (name and value).
This is driving me nuts. Please help!
Part of the code:
#interface IMXMLElement : NSObject {
NSString *strElementName;
NSString *strElementValue;
NSMutableDictionary *dictAttributes;
}
#property (nonatomic, retain) NSString *strElementName;
#property (nonatomic, retain) NSString *strElementValue;
#property (nonatomic, retain) NSMutableDictionary *dictAttributes;
#end
#implementation IMXMLElement
#synthesize strElementName;
#synthesize strElementValue;
#synthesize dictAttributes;
-(id)initWithName:(NSString *)pstrName
{
self = [super init];
if (self != nil)
{
self.strElementName = pstrName;
**LEAK NSMutableDictionary *tmp = [[NSMutableDictionary alloc] init];
self.dictAttributes = tmp;
[tmp release];
}
return self;
}
-(void)setAttributeWithName:(NSString *)pstrAttributeName
andValue:(NSString *)pstrAttributeValue
{
**LEAK [self.dictAttributes setObject:pstrAttributeValue forKey:pstrAttributeName];
}
-(void)dealloc
{
[strElementName release];
[strElementValue release];
[dictAttributes release];
[super dealloc];
}
The access this class using the following code:
NSString *strValue = [[NSString alloc] initWithFormat:#"Test Value"];
IMXMLElement *xmlElement = [[IMXMLElement alloc] initWithName:#"Test_Element"];
[xmlElement setAttributeWithName:#"id" andValue:strValue];
When you have strings as properties, declare them as copy, not retain.
NSMutableDictionary *tmp = [[NSMutableDictionary alloc] init];
self.dictAttributes = tmp;
[tmp release];
the above is unnecessary, instead do:
(retain count will automatically be incremented for this autorelease object)
self.dictAttributes = [NSMutableDictionary dictionaryWithCapacity:0];
in dealloc do:
(retain count will automatically be decremented)
self.dictAttributes = nil;
normally for properties you just set them to nil instead of explicitly releasing them
since the get/setter handles that for you.
Try [dictAttributes removeAllObjects] before releasing dictAttributes.
Edit:
Also, you will positive allocation because you are allocating memory for "tmp". The memory will be retained because you now have a reference from dictAttributes.
You then have more positive allocation when you add elements to the dictionary, which also need to be allocated and are kept in memory by the dictionary's internal references
Typical syntax is NSMutableDictionary *tmp = [[[NSMutableDictionary alloc] init] autorelease];

How to Keep an NSArray in Memory as Long as App is Running

Can anybody tell me how to make sure an NSArray exist in memory as long as the app is running?
Thanks......
You can retain the object in application delegate class and on application terminate release.
i.e
in application delegate class
#interface MyAppDelegate : NSObject <UIApplicationDelegate>
{
UIWindow *window;
NSMutableArray *arrayObjects;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) NSMutableArray *arrayObjects;
Now you can allocate the arrayObjects using the instance of delegate class and you can also use the value stored in arrays.
MyAppDelegate *appDelegate = (MyAppDelegate*)[[UIApplication sharedApplication]delegate];
appDelegate.arrayObjects = [[NSMutableArray alloc] initWithObjects:#"Object 1",#"Object 2",#"Object 3",nil];
This will preserve value in your array.Now You can use array any where in application after proper initialization.
If you're trying to preserve the array until the application exits, allocate it in your App Delegate's -init method and release it in the App Delegate's -dealloc method. Unless you make a mistake in your memory management and release the array too many times, it will be available for the entire lifecycle of the application.
For example:
#interface MyApp <NSApplicationDelegate>
{
NSArray *myArray;
}
#end
#implementation MyApp
- (id)init
{
if (nil != (self = [super init]))
{
myArray = [[NSArray alloc] init];
}
return self;
}
- (void)dealloc
{
[myArray release], myArray = nil;
[super dealloc];
}
#end
If I understand you correctly you want to store a NSArray instance to disk?
In that case use [NSKeyedArchiver archiveRootObject:myArray toFile:path]
The folder to store the file at can be determined with:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];