Store UIImageViews in NSMutableDictionary - iphone

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

Related

NSMutableArray not accessible throughout my class?

I'm really frustrated after spending like three hours googling around to solve this problem!! It's probably an easy solution to it aswell.
I'm creating a really simple TableView app for the iPhone. It's supposed to fetch an XML-document and parse it (already fixed) and then put the data into objects called HPobject!
One HPobject represents one day of data from the XML-file. Anyhow!
Then I want the object to be stored in a NSMutableArray so I can grab it later when I'm creating the table rows. But I can't access it! My NSMutableArray is ALWAYS null! No matter what I do!
Here's my code:
//THE .h FILE
#import "TBXML.h"
#import "HPobject.h"
#interface RootViewController : UITableViewController {
NSMutableArray *listOfItems;
}
- (void)traverseElement:(TBXMLElement *)element;
//THE .m FILE
#import "RootViewController.h"
#import "HPobject.h"
#implementation RootViewController
- (void)viewDidLoad
{
NSMutableArray *listOfItems = [[NSMutableArray alloc] init];
TBXML * tbxml = [[TBXML tbxmlWithURL:[NSURL URLWithString:#"http://www.hpprov.se/istasts.php?q=xxxxxxx"]] retain];
if (tbxml.rootXMLElement)
[self traverseElement:tbxml.rootXMLElement]; //Works fine!
[tbxml release];
[super viewDidLoad];
}
- (void) traverseElement:(TBXMLElement *)element {
do {
//Lots of parsing code which all works fine and gets me the variables up next!
HPobject *currentObject = [[HPobject alloc] init];
currentObject.antalRegistrerade = numRegistrerade;
currentObject.inkomstBrutto = numBrutto;
currentObject.inkomstNetto = numNetto;
[listOfItems addObject:currentObject];
NSLog(#"Array: %#", listOfItems); //RETURNS null!
NSLog(#"Reg: %#, Net: %#, Brutt: %#", currentObject.antalRegistrerade, currentObject.inkomstNetto, currentObject.inkomstBrutto); //Returns the correct values!
NSLog(#"%d stycken!", listOfItems.count); //Returns 0!! :(
[currentObject release];
} while ((element = element->nextSibling));
}
You are defining listOfItems locally in viewDidLoad and then you try to access that in another method.
Make sure you are using an instance variable defined in your interface definition (header).
replace this line in viewDidLoad:
NSMutableArray *listOfItems = [[NSMutableArray alloc] init];
with
listOfItems = [[NSMutableArray alloc] init];
I suppose that listOfItems is an ivar. So to fix your problem change this:
NSMutableArray *listOfItems = [[NSMutableArray alloc] init];
to this
listOfItems = [[NSMutableArray alloc] init];
Take a look at the scope of your array. You have created that as a variable of another method. It will not visible in others. Make an instance var.

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

images not being added to NSMutableDictionary, which is within an NSOperation

So I first coded all my methods in a viewcontroller with an NSOperationQueue. After doing some research and a lot of reading I realized i had to subclass my loadImage operation so that I may use isCancelled and cancelAllOperations. So I went ahead and created an nsoperation class and called it from my viewcontroller. ALl the methods are called, even the imageLoaded, but the NSMutableDictionary remains empty. I use the dictionary to populate my tableviewcells using the url as the Key. Also be aware that the operation call in the viewcontroller is within a method which is called by an NSInvocationOperation when the view loads.
#interface loadImages : NSOperation {
NSURL *targetURL;
}
#property(retain) NSURL *targetURL;
- (id)initWithURL:(NSURL*)url;
#end
implementation of nsoperation class which includes some other calls to resize the image
#implementation loadImages
#synthesize targetURL;
- (id)initWithURL:(NSURL*)url
{
if (![super init]) return nil;
[self setTargetURL:url];
return self;
}
- (void)dealloc {
[targetURL release], targetURL = nil;
[super dealloc];
}
- (void)main {
NSLog(#"loadImages.m reached");
StoriesTableViewController *stories = [[StoriesTableViewController alloc] init];
NSMutableDictionary *tempDict = stories.filteredImagesDict;
UIImage *myImage = [[[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[self targetURL]]]autorelease];
UIImage *scaledImage = [[[UIImage alloc] init] autorelease];
CGRect frame = CGRectMake(100.0f, 100.0f, 180.0f, 180.0f);
UIImageView *myImageFrame = [[UIImageView alloc] initWithFrame:frame];
myImage = [[myImage croppedImage:[myImageFrame bounds]]retain];
scaledImage = [[myImage resizedImage:CGSizeMake(120.0f, 120.0f) interpolationQuality:kCGInterpolationHigh]retain];
[tempDict setValue:scaledImage forKey:[self targetURL]];
[stories performSelectorOnMainThread:#selector(imageLoaded:)
withObject:myImage
waitUntilDone:YES];
NSLog(#"targetURL %#",[self targetURL]);
NSLog(#"tempDict count: %d",tempDict.count);
[stories release];
[myImage release];
[myImageFrame release];
[scaledImage release];
}
creation of nsoperation on viewcontroller
for(int i=0;i<storyQuantity;i++) {
NSString *imageString = [[[storiesArray objectAtIndex:i] objectForKey: #"image"] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; // must add trimming to remove characters
NSURL *url = [NSURL URLWithString:imageString];
loadImages *imageOperation = [[loadImages alloc] initWithURL:url];
[queue_ addOperation:imageOperation];
[imageOperation release];
}
If this is running without exceptions and the dictionary is still empty, it most likely means that your value is nil.
This is a common problem with code like that where you have the result of one method going into the next. At any point if there is a problem, all the rest of the chain will not work.
To solve, I would start right above where you assigned the image to the dictionary. You can use either a breakpoint, or an NSLog to determine the value of the image at that point. I prefer to use an NSLog, but a break point would let you look at all the values at once. If scaledImage is nil, then check myImage. Keep going back up the chain until you find the point where the value goes from what you would expect, to nil.

iphone app crashing when I'm using an NSMutableDictionary

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]

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