I'm getting a leak from using substringWithRange as shown in the line of code below. I though all these functions were Autorelease and you didnt need to alloc/release them manually.
NSCFString is the object being leaked.
What is it I am doing wrong?
aLTR.drew = [substring substringWithRange:NSMakeRange(match.location+1, (match2.location-(match.location+1)))];
What I am trying to do is extract a substring and store it into my storage class. Code for that below.
#import <Foundation/Foundation.h>
#interface LeagueTableRow : NSObject
{
NSString *_teamName;
NSString *_played;
NSString *_won;
NSString *_drew;
NSString *_lost;
NSString *_goalsFor;
NSString *_goalsAgainst;
NSString *_points;
}
#property(nonatomic, copy) NSString *teamName;
#property(nonatomic, copy) NSString *played;
#property(nonatomic, copy) NSString *won;
#property(nonatomic, copy) NSString *drew;
#property(nonatomic, copy) NSString *lost;
#property(nonatomic, copy) NSString *goalsFor;
#property(nonatomic, copy) NSString *goalsAgainst;
#property(nonatomic, copy) NSString *points;
-(id)init;
#end
#import "LeagueTableRow.h"
#implementation LeagueTableRow
#synthesize teamName = _teamName;
#synthesize played = _played;
#synthesize won = _won;
#synthesize drew = _drew;
#synthesize lost = _lost;
#synthesize goalsFor = _goalsFor;
#synthesize goalsAgainst = _goalsAgainst;
#synthesize points = _points;
-(id)init
{
self = [super init];
return self;
}
-(void) dealloc
{
self.teamName = nil;
self.played = nil;
self.won = nil;
self.drew = nil;
self.lost = nil;
self.goalsFor = nil;
self.goalsAgainst = nil;
self.points = nil;
[super dealloc];
}
#end
I'm quiet surprised I got some leaks I though I was managing the memory quiet tidily.
Thanks for the advice and tips.
-Code
In your dealloc, simply release all the string ivars:
[_teamName release];
etc...
Alternatively, you could do:
[self.teamName release];
etc...
I prefer to use the ivars directly, in such situations.
Related
UICRouteAnnotation *startAnnotation = [[UICRouteAnnotation alloc] initWithCoordinate [[routePoints objectAtIndex:0] coordinate]
title:#"Origin"
subtitle:#"Subtitle Here"
annotationType:UICRouteAnnotationTypeStart];
I am trying to add a subtitle to this annotation but don't have much experience with UICRouteAnnotation and was not able to find much documentation on it. Adding "subtitle:" through exceptions.
What am I missing? Why doesn't the subtitle work when doing it like this?
What I didn't realize is that UICRouteAnnotation needed to be modified to accept a subtitle. Here is my updated h and m files for UICRouteAnnotation. Making the below changes fixed my issue so the code I posted in my question works as intended.
Thanks Anna for pointing me in the right direction.
.h file
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
typedef enum UICRouteAnnotationType {
UICRouteAnnotationTypeStart,
UICRouteAnnotationTypeEnd,
UICRouteAnnotationTypeWayPoint,
} UICRouteAnnotationType;
#interface UICRouteAnnotation : NSObject<MKAnnotation> {
CLLocationCoordinate2D coordinate;
NSString *title;
NSString *subtitle;
UICRouteAnnotationType annotationType;
}
#property (nonatomic) CLLocationCoordinate2D coordinate;
#property (nonatomic, readonly, copy) NSString *title;
#property (nonatomic, readonly, copy) NSString *subtitle;
#property (nonatomic) UICRouteAnnotationType annotationType;
- (id)initWithCoordinate:(CLLocationCoordinate2D)coord
title:(NSString *)aTitle
subtitle:(NSString *)aSubTitle
annotationType:(UICRouteAnnotationType)type;
#end
.m file
#import "UICRouteAnnotation.h"
#implementation UICRouteAnnotation
#synthesize coordinate;
#synthesize title;
#synthesize subtitle;
#synthesize annotationType;
- (id)initWithCoordinate:(CLLocationCoordinate2D)coord
title:(NSString *)aTitle
subtitle:(NSString *)aSubTitle
annotationType:(UICRouteAnnotationType)type {
self = [super init];
if (self != nil) {
coordinate = coord;
title = [aTitle retain];
subtitle = [aSubTitle retain];
annotationType = type;
}
return self;
}
- (void)dealloc {
[title release];
[subtitle release];
[super dealloc];
}
#end
In NSMutableArray or NSArray how do you set up the row structure. All the examples I can find just deal with one dimensional integers or strings.
So how do you go about setting up an array row structure like:
Integer, String, Date
You would need to create an array of arrays, or an array of dictionaries, the second approach being better if you'd like to refer to the data by name rather than index:
NSMutableArray *rows = [[NSMutableArray alloc] init];
NSMutableDictionary *firstRow = [NSMutableDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:12], #"fieldWithNumber",
[NSString stringWithFormat:#"A formatted string %ld", 34], #"fieldWithString",
[NSDate date], #"fieldWithDate",
nil];
[rows addObject:firstRow];
// etc.
You can make custom class and add collection of these objects in an array.
For example please assume that we have to do some rows about places then create a class PLACE.h
#interface PLACE : NSObject
{
NSString *title;
NSString *summary;
NSString *url;
NSString *latitude;
NSString *longitude;
}
#property (nonatomic, retain) NSString *title;
#property (nonatomic, retain) NSString *summary;
#property (nonatomic, retain) NSString *url;
#property (nonatomic, retain) NSString *latitude;
#property (nonatomic, retain) NSString *longitude;
#end
PLACE.m
#implementation PLACE
#synthesize title;
#synthesize summary;
#synthesize url;
#synthesize latitude;
#synthesize longitude;
- (void) dealloc
{
[title release];
[summary release];
[url release];
[latitude release];
[longitude release];
[super dealloc];
}
#end
Create instance of the class PLACE for each place and hold the objects in the array. I think that solves your problem.
An array is just a collection of objects.
Just create an object that has an integer, date and string and then add instances of those to the array.
I have made a very simple custom object pictureData.
Here is the .h file
#import <Foundation/Foundation.h>
#interface pictureData : NSObject {
NSString *fileName;
NSString *photographer;
NSString *title;
NSString *license;
}
#property (nonatomic, retain) NSString *fileName;
#property (nonatomic, retain) NSString *photographer;
#property (nonatomic, retain) NSString *title;
#property (nonatomic, retain) NSString *license;
+(pictureData*)picDataWith:(NSDictionary*)dictionary;
#end
The .m file
#import "pictureData.h"
#implementation pictureData
#synthesize fileName;
#synthesize photographer;
#synthesize title;
#synthesize license;
+ (pictureData*)picDataWith:(NSDictionary *)dictionary {
pictureData *tmp = [[[pictureData alloc] init] autorelease];
tmp.fileName = [dictionary objectForKey:#"fileName"];
tmp.photographer = [dictionary objectForKey:#"photographer"];
tmp.title = [dictionary objectForKey:#"title"];
tmp.license = [dictionary objectForKey:#"license"];
return tmp;
}
-(void)dealloc {
[fileName release];
[photographer release];
[title release];
[license release];
}
#end
I then set up these objects in an array, like so:
NSString *path = [[NSBundle mainBundle] pathForResource:#"pictureLicenses" ofType:#"plist"];
NSArray *tmpDataSource = [NSArray arrayWithContentsOfFile:path];
NSMutableArray *tmp = [[NSMutableArray alloc] init];
self.dataSource = tmp;
[tmp release];
for (NSDictionary *dict in tmpDataSource) {
pictureData *pic = [pictureData picDataWith:dict];
NSLog(#"%#", pic.title);
[self.dataSource addObject:pic];
}
Everything works smashingly. I have a table view which loads the proper picture images, and information, no problem. Upon running Instruments for leaks, I see that my pictureData object is leaks with every allocation.
I would assume that with having my object autoreleased I would not have to worry about manually allocating and deallocating them.
Perhaps is my issue that I use autorelease, which the autoReleasePool keeps a retain count of +1 and then when I add a pictureData object to my array, that also retains it? Thank you all for your time!
edit: Don't forget to call super! Thank you Sam!
Change dealloc to:
-(void)dealloc {
[fileName release];
[photographer release];
[title release];
[license release];
[super dealloc];
}
(call [super dealloc])
In your function, change the return value to include autorelease, like
+ (pictureData*)picDataWith:(NSDictionary *)dictionary
{
...
...
return [tmp autorelease];
}
When you add pictureData object to dataSource, you increase the retain count, so you should autorelease it while returning.
Hope it helps.
I'm getting a memory leak with instruments in a class that I've created. This is the class:
.h
#import <Foundation/Foundation.h>
#interface RDItem : NSObject {
}
#property int Id;
#property (nonatomic, retain) NSString *nombre;
#property (nonatomic, retain) NSString *thumbnail;
#property (nonatomic, retain) NSString *thumbnailPush;
#property int defaultColorId;
#property int idTema;
#property (nonatomic, retain) NSString *selectedFrame;
#property (nonatomic, retain) NSString *mergedFrame;
#property (nonatomic, retain) NSMutableArray *colors;
#property (nonatomic, retain) NSMutableArray *textures;
#property (nonatomic, retain) NSMutableArray *styles;
-(void)initialize;
#end
.m
#import "RDItem.h"
#implementation RDItem
#synthesize Id;
#synthesize nombre;
#synthesize thumbnail;
#synthesize thumbnailPush;
#synthesize defaultColorId;
#synthesize idTema;
#synthesize selectedFrame;
#synthesize mergedFrame;
#synthesize colors;
#synthesize textures;
#synthesize styles;
-(void)initialize
{
colors = [[NSMutableArray alloc] init];
textures = [[NSMutableArray alloc] init];
styles = [[NSMutableArray alloc] init];
}
-(void)dealloc
{
[colors release];
[textures release];
[styles release];
}
#end
This class have 3 NSMutableArray where I'll store data. In order to prepare and initialice this class, I've developed the method initialize where the 3 arrays are created. In dealloc are released.
The leaks tool detects a leak each time this class is used because the initialize method.
Which is the best way to initialize these arrays?
Thanks.
EDIT
Hi I've solved the leak with RDItem but now appears another lear in a very similar class:
.h
#import <Foundation/Foundation.h>
#interface RDTema : NSObject {
}
#property int Id;
#property (nonatomic, retain) NSString *idManifest;
#property (nonatomic, retain) NSString *idTema;
#property (nonatomic, retain) NSString *nombre;
#property (nonatomic, retain) NSString *thumbnail;
#property (nonatomic, retain) NSString *thumbnailPush;
#property (nonatomic, retain) NSMutableArray *items;
#property (nonatomic, retain) NSMutableArray *colors;
#property (nonatomic, retain) NSMutableArray *textures;
#property (nonatomic, retain) NSMutableArray *styles;
-(void)initialize;
#end
.m
#import "RDTema.h"
#implementation RDTema
#synthesize Id;
#synthesize idManifest;
#synthesize idTema;
#synthesize nombre;
#synthesize thumbnail;
#synthesize thumbnailPush;
#synthesize items;
#synthesize colors;
#synthesize textures;
#synthesize styles;
-(void)initialize
{
/*
self.items = [[NSMutableArray alloc] init];
self.colors = [[NSMutableArray alloc] init];
self.textures = [[NSMutableArray alloc] init];
self.styles = [[NSMutableArray alloc] init];
*/
self.items = [NSMutableArray array];
self.colors = [NSMutableArray array];
self.textures = [NSMutableArray array];
self.styles = [NSMutableArray array];
}
-(void)dealloc
{
[idManifest release];
[idTema release];
[nombre release];
[thumbnail release];
[thumbnailPush release];
[items release];
[colors release];
[textures release];
[styles release];
[super dealloc];
}
Now I'm getting a leak in these lines:
self.items = [NSMutableArray array];
self.colors = [NSMutableArray array];
self.textures = [NSMutableArray array];
self.styles = [NSMutableArray array];
Anyone can explain why is happening in this class and not in RDItem class now? Are the same :(
Thanks.
This is a better suggested implementation
-(void)initialize
{
self.colors = [NSMutableArray array];
self.textures = [NSMutableArray array];
self.styles = [NSMutableArray array];
}
-(void)dealloc
{
self.colors = nil;
self.textures = nil;
self.styles = nil;
}
I think that you are getting the leak because you call your initialize message more than once and you are not releasing the variables.
Normally, you should use setters or getters to access your ivars, so the appropiate operations are called (like the release message before assigning a new value on setter).
And remember to call [super dealloc] as the last instruction for your dealloc ;)
Without seeing the code where you are initialising the RDItem i can't say for sure.
But i expect that you are not releasing your previous RDItem before creating your new one. So post the code where you are creating your RDItems so we can say for sure
I think, that leak are in arrays filling code, not init. For example, you alloc and init some NSString and put it in your NSMutable array without release or autorelease it. Or something like this. Make shure that you filling your arrays right way.
Just init them when you need it. Calling alloc and init holds to arrays whose content is nil. Call alloc initWithObjects: and fill the arrays.
I have this class
#import <Foundation/Foundation.h>
#interface SubscriptionArray : NSObject{
NSString *title;
NSString *source;
NSString *htmlUrl;
}
#property (nonatomic,retain) NSString *title;
#property (nonatomic,retain) NSString *source;
#property (nonatomic,retain) NSString *htmlUrl;
#end
and the implementation file is this one:
#import "SubscriptionArray.h"
#implementation SubscriptionArray
#synthesize title,source,htmlUrl;
-(void)dealloc{
[title release];
[source release];
[htmlUrl release];
}
#end
When I use the class like in this example I get an EXEC_BAD_ACCESS error:
for (NSDictionary *element in subs){
SubscriptionArray *add;
add.title=[element objectForKey:#"title"]; //ERROR Happens at this line
add.source=[element objectForKey:#"htmlUrl"];
add.htmlUrl=[element objectForKey:#"id"];
[subscriptions addObject:add];
}
Can someone help me?
P.S. Subscriptions is a NSMutableArray
You need to allocate your SubscriptionArray object like so: SubscriptionArray *add = [[SubscriptionArray alloc] init];
Your for loop will therefore look something like this:
for (NSDictionary *element in subs){
SubscriptionArray *add = [[SubscriptionArray alloc] init];
add.title=[element objectForKey:#"title"];
add.source=[element objectForKey:#"htmlUrl"];
add.htmlUrl=[element objectForKey:#"id"];
[subscriptions addObject:add];
[add release];
}
You need to initialize your SubscriptionArray. i.e.
SubscriptionArray *add = [SubscriptionArray new];