why is the NSMutableArray is being destroyed in this loop? - iphone

It is the arrayOfPerformances that is getting broken.
here is the .h for the array:
NSMutableArray * arrayOfPerformances;
}
#property (nonatomic, retain) NSMutableArray * arrayOfPerformances;
and the .m that has the loop:
[dataArray release];
[dataDictionary release];
dataArray = [[NSMutableArray alloc] init];
dataDictionary = [[NSMutableDictionary alloc] init];
NSDate * CurrentDate = start;
int i = 0;
NSMutableArray * arrayOfPerformancesForCurrentDate = [[NSMutableArray alloc] init];
while(YES)
{
i = 0;
if ([arrayOfPerformancesForCurrentDate count] > 0)
{
[arrayOfPerformancesForCurrentDate removeAllObjects];
}
for (i; i < self.arrayOfPerformances.count; i++)
{
Performance * performanceItem = [[Performance alloc] init];
performanceItem = [self.arrayOfPerformances objectAtIndex:i];
NSString * sPerformanceDate = [performanceItem.sDate substringToIndex:10];
NSString * sCurrentDate = [CurrentDate dateDescription];
if([sPerformanceDate isEqualToString:sCurrentDate])
{
[arrayOfPerformancesForCurrentDate addObject:performanceItem];
}
[performanceItem release];
}
if ([arrayOfPerformancesForCurrentDate count] >= 1)
{
[dataDictionary setObject:arrayOfPerformancesForCurrentDate forKey:CurrentDate];
[dataArray addObject:[NSNumber numberWithBool:YES]];
}
else
{
[dataArray addObject:[NSNumber numberWithBool:NO]];
}
TKDateInformation info = [CurrentDate dateInformation];
info.day++;
CurrentDate = [NSDate dateFromDateInformation:info];
if([CurrentDate compare:end]==NSOrderedDescending) break;
}
Any help would be appreciated. I dont understand why this is happening?

This part doesn't look right:
Performance * performanceItem = [[Performance alloc] init]; <--
performanceItem = [self.arrayOfPerformances objectAtIndex:i]; <--
NSString * sPerformanceDate = [performanceItem.sDate substringToIndex:10];
NSString * sCurrentDate = [CurrentDate dateDescription];
if([sPerformanceDate isEqualToString:sCurrentDate])
{
[arrayOfPerformancesForCurrentDate addObject:performanceItem];
}
[performanceItem release]; <--
You alloc+init performanceItem but then set it to an object in arrayOfPerformances and then you release it (while it's pointing to the object in arrayOfPerformances).
Change that section to this:
Performance *performanceItem = [self.arrayOfPerformances objectAtIndex:i];
NSString * sPerformanceDate = [performanceItem.sDate substringToIndex:10];
NSString * sCurrentDate = [CurrentDate dateDescription];
if([sPerformanceDate isEqualToString:sCurrentDate])
{
[arrayOfPerformancesForCurrentDate addObject:performanceItem];
}
//don't release performanceItem

I don't think arrayOfPerformances of being destroyed. It appears you aren't even initializing it anywhere.

Related

New a better way of initializing classes and objects

Here is a code that I thought of to initialize my picker with. Is there a better way to write this?
The interface
#interface roomsClass : NSObject {
NSInteger roomID;
NSString *name;
NSString *desc;
}
#property (nonatomic, readwrite) NSInteger roomID;
#property (nonatomic, copy) NSString *name;
#property (nonatomic, copy) NSString *desc;
#end
#interface typesClass : NSObject {
NSInteger typeID;
NSString *name;
}
#property (nonatomic, readwrite) NSInteger typeID;
#property (nonatomic, copy) NSString *name;
#end
The implementation
NSMutableArray *tempArrayA = [[NSMutableArray alloc] init];
self.roomsArray = tempArrayA;
[tempArrayA release];
roomsClass *tempObjA1 = [[roomsClass alloc] init];
tempObjA1.roomID = 202;
tempObjA1.name = #"MH202";
tempObjA1.desc = #"Lab";
[roomsArray addObject:tempObjA1];
[tempObjA1 release];
roomsClass *tempObjA2 = [[roomsClass alloc] init];
tempObjA2.roomID = 207;
tempObjA2.name = #"MH207";
tempObjA2.desc = #"Office";
[roomsArray addObject:tempObjA2];
[tempObjA2 release];
roomsClass *tempObjA3 = [[roomsClass alloc] init];
tempObjA3.roomID = 208;
tempObjA3.name = #"MH208";
tempObjA3.desc = #"Office";
[roomsArray addObject:tempObjA3];
[tempObjA3 release];
roomsClass *tempObjA4 = [[roomsClass alloc] init];
tempObjA4.roomID = 209;
tempObjA4.name = #"MH209";
tempObjA4.desc = #"Lab";
[roomsArray addObject:tempObjA4];
[tempObjA4 release];
roomsClass *tempObjA5 = [[roomsClass alloc] init];
tempObjA5.roomID = 210;
tempObjA5.name = #"MH210";
tempObjA5.desc = #"Lab";
[roomsArray addObject:tempObjA5];
[tempObjA5 release];
roomsClass *tempObjA6 = [[roomsClass alloc] init];
tempObjA6.roomID = 211;
tempObjA6.name = #"MH211";
tempObjA6.desc = #"Office";
[roomsArray addObject:tempObjA6];
[tempObjA6 release];
NSMutableArray *tempArrayB = [[NSMutableArray alloc] init];
self.typesArray = tempArrayB;
[tempArrayB release];
typesClass *tempObjB1 = [[typesClass alloc] init];
tempObjB1.typeID = 1;
tempObjB1.name = #"Desktop";
[typesArray addObject:tempObjB1];
[tempObjB1 release];
typesClass *tempObjB2 = [[typesClass alloc] init];
tempObjB2.typeID = 2;
tempObjB2.name = #"Laptop";
[typesArray addObject:tempObjB2];
[tempObjB2 release];
typesClass *tempObjB3 = [[typesClass alloc] init];
tempObjB3.typeID = 3;
tempObjB3.name = #"Monitor";
[typesArray addObject:tempObjB3];
[tempObjB3 release];
typesClass *tempObjB4 = [[typesClass alloc] init];
tempObjB4.typeID = 4;
tempObjB4.name = #"Server";
[typesArray addObject:tempObjB4];
[tempObjB4 release];
typesClass *tempObjB5 = [[typesClass alloc] init];
tempObjB5.typeID = 5;
tempObjB5.name = #"Printer";
[typesArray addObject:tempObjB5];
[tempObjB5 release];
typesClass *tempObjB6 = [[typesClass alloc] init];
tempObjB6.typeID = 6;
tempObjB6.name = #"Projector";
[typesArray addObject:tempObjB6];
[tempObjB6 release];
typesClass *tempObjB7 = [[typesClass alloc] init];
tempObjB7.typeID = 7;
tempObjB7.name = #"Other";
[typesArray addObject:tempObjB7];
[tempObjB7 release];
if (roomPicker == nil) {
roomPicker = [[UIPickerView alloc] initWithFrame:CGRectZero];
roomPicker.delegate = self;
roomPicker.dataSource = self;
roomPicker.showsSelectionIndicator = YES;
roomPicker.transform = CGAffineTransformMakeScale(1.0, 1.0);
roomPicker.tag = kRoomPicker;
}
txtRoomID.inputView = roomPicker;
if (typePicker == nil) {
typePicker = [[UIPickerView alloc] initWithFrame:CGRectZero];
typePicker.delegate = self;
typePicker.dataSource = self;
typePicker.showsSelectionIndicator = YES;
typePicker.transform = CGAffineTransformMakeScale(1.0, 1.0);
typePicker.tag = kTypePicker;
}
txtTypeID.inputView = typePicker;
The idea is to have the picker show some text, but when the user selects the text on the UIPickerView, the integer value/id of the selection be placed in the UITextField, rather than the text the user sees.
I am using iOS 4.3.1 on the device, with 4.3 SDK, and Xcode 3.2.6.
one way to reduce the redundancy is called a convenience constructor. a partial implementation is illustrated below:
#interface MONRoomsClass : NSObject {
NSInteger roomID;
NSString *name;
NSString *desc;
}
#property (nonatomic, readwrite) NSInteger roomID;
#property (nonatomic, copy) NSString *name;
/* note: ivar would normally be named 'description' */
#property (nonatomic, copy) NSString *desc;
/* designated initializer */
- (id)initWithRoomID:(NSInteger)inRoomID
name:(NSString *)inName
desc:(NSString *)inDesc;
/* convenience constructor */
+ (MONRoomsClass *)newRoomsClassWithRoomID:(NSInteger)inRoomID
name:(NSString *)inName
desc:(NSString *)inDesc;
/* convenience constructor */
+ (MONRoomsClass *)roomsClassWithRoomID:(NSInteger)inRoomID
name:(NSString *)inName
desc:(NSString *)inDesc;
#end
#implementation MONRoomsClass
- (id)initWithRoomID:(NSInteger)inRoomID
name:(NSString *)inName
desc:(NSString *)inDesc
{
/* error checking omitted */
self = [super init];
if (0 != self) {
roomID = inRoomID;
name = [inName copy];
desc = [inDesc copy];
}
return self;
}
+ (MONRoomsClass *)newRoomsClassWithRoomID:(NSInteger)inRoomID
name:(NSString *)inName
desc:(NSString *)inDesc
{
return [[self alloc] initWithRoomID:inRoomID name:[inName desc:inDesc];
}
+ (MONRoomsClass *)roomsClassWithRoomID:(NSInteger)inRoomID
name:(NSString *)inName
desc:(NSString *)inDesc
{
return [[[self alloc] initWithRoomID:inRoomID
name:inName
desc:inDesc] autorelease];
}
#end
void in_use() {
/* ... */
MONRoomsClass * roomsClass =
[MONRoomsClass newRoomsClassWithRoomID:210
name:#"MH210"
desc:#"Lab"];
[roomsArray addObject:roomsClass];
/* or */
[roomsArray addObject:
[[MONRoomsClass newRoomsClassWithRoomID:210
name:#"MH210"
desc:#"Lab"]
autorelease]];
/* or */
[roomsArray addObject:
[MONRoomsClass roomsClassWithRoomID:210
name:#"MH210"
desc:#"Lab"]];
/* ... */
}
There are a few possibilities for rewriting your array initialisation code. One that comes to mind is:
NSInteger roomIDs[] = { 202, 207, 208, 209, 210, 211 };
NSString *roomNames[] = { #"MH202", #"MH207", #"MH208", #"MH209", #"MH210", #"MH211" };
NSString *roomDescs[] = { #"Office", #"Lab", #"Office", #"Lab", #"Lab", #"Office" };
NSUInteger numberOfRooms = sizeof(roomIDs) / sizeof(NSInteger);
self.roomsArray = [NSMutableArray arrayWithCapacity:numberOfRooms];
for (int i = 0; i < numberOfRooms; i++) {
roomsClass *room = [[[roomsClass alloc] init] autorelease];
room.roomID = roomIDs[i];
room.name = roomNames[i];
room.desc = roomDescs[i];
[self.roomsArray addObject:room];
}
or
typedef struct {
NSInteger roomId;
NSString *name;
NSString *desc;
} RoomData;
RoomData rooms[] = {
{ 202, #"MH202", #"Office" },
{ 207, #"MH207", #"Lab" },
{ 208, #"MH208", #"Office" },
{ 209, #"MH209", #"Lab" },
{ 210, #"MH210", #"Lab" },
{ 211, #"MH211", #"Office" }
};
NSUInteger numberOfRooms = sizeof(rooms) / sizeof(RoomData);
self.roomsArray = [NSMutableArray arrayWithCapacity:numberOfRooms];
for (int i = 0; i < numberOfRooms; i++) {
roomsClass *room = [[[roomsClass alloc] init] autorelease];
room.roomID = rooms[i].roomId;
room.name = rooms[i].name;
room.desc = rooms[i].desc;
[self.roomsArray addObject:room];
}
If you couple those with #Justin’s convenience constructor, the for loop can be simplified to:
for (int i = 0; i < numberOfRooms; i++) {
[self.roomsArray addObject:[roomsClassWithRoomID:roomIDS[i]
name:roomNames[i]
desc:roomDescs[i]]];
}
or
for (int i = 0; i < numberOfRooms; i++) {
[self.roomsArray addObject:[roomsClassWithRoomID:rooms[i].roomId
name:rooms[i].name
desc:rooms[i].desc]];
}

print reverse of a string

I am writing a program which prints the reverse of a string in a textfield, taking input text from the other textfield. When I press enter after entering text into one textfield the result(reverse) should be dispalyed in the other text field.
I have tried like this, but am getting weird results.
.h file:
#import <UIKit/UIKit.h>
#interface reverseVC : UIViewController {
UITextField *textEntered;
UITextField *textDisplay;
}
#property (nonatomic,retain) IBOutlet UITextField *textDisplay;
#property (nonatomic,retain) IBOutlet UITextField *textEntered;
- (NSMutableArray*) stringReverse;
- (IBAction) enter;
#end
.m file
- (NSMutableArray *) stringReverse
{
NSString *value = textEntered.text;
NSArray *tempArray = [[[NSArray alloc] initWithObjects:value,nil] autorelease];
NSMutableArray *arr = [[[NSMutableArray alloc] init] autorelease];
for (int i=[tempArray count]-1; i>=0; i--)
{
[arr addObject:[tempArray objectAtIndex:i]];
NSLog(#"the object is:%c",arr);
}
return arr;
}
-(IBAction)enter
{
textDisplay.text = [NSString stringWithFormat:#"%c",[self stringReverse]];
}
Earlier got warnings like SIG_ABT and EXE_BAD_ACCESS before placing nil and autorelease in array initialisations. Now the warnings are solved but results undesiredly.
Where am I going wrong?
You insert the NSString object in your array. Its count is 1. You have to go from the end of the string to the beginning and append the character to a new string. You ca do it like this:
-(NSString*)reverseString:(NSString*)string {
NSMutableString *reversedString;
int length = [string length];
reversedString = [NSMutableString stringWithCapacity:length];
while (length--) {
[reversedString appendFormat:#"%C", [string characterAtIndex:length]];
}
return reversedString;
}
Another way to reverse strings is to use the reverse string enumerator.
- (NSString *)reverseString:(NSString *)string {
NSMutableString *reversedString = [[NSMutableString alloc] init];
NSRange fullRange = [string rangeOfString:string];
NSStringEnumerationOptions enumerationOptions = (NSStringEnumerationReverse | NSStringEnumerationByComposedCharacterSequences);
[string enumerateSubstringsInRange:fullRange options:enumerationOptions usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
[reversedString appendString:substring];
}];
return reversedString;
}
use this
NSString *str=textEntered.text;//
NSMutableArray *temp=[[NSMutableArray alloc] init];
for(int i=0;i<[str length];i++)
{
[temp addObject:[NSString stringWithFormat:#"%c",[str characterAtIndex:i]]];
}
temp = [NSMutableArray arrayWithArray:[[temp reverseObjectEnumerator] allObjects]];
NSString *reverseString=#"";
for(int i=0;i<[temp count];i++)
{
reverseString=[NSString stringWithFormat:#"%#%#",reverseString,[temp objectAtIndex:i]];
}
NSLog(#"%#",reverseString);
I revers my strings with a few lines of code. Rather late, but just putting it out there :)
- (NSString*) reverseMyString:(NSString*)theString
{
NSString *final = #"";
for(int i = theString.length-1; i>=0; i--)
final = [NSString stringWithFormat:#"%#%c", final, [theString characterAtIndex:i]];
return final;
}
NSString *str = #"hello";
int length = [str length];
NSLog(#"%d",length);
NSMutableString *rev = [[NSMutableString alloc] initWithCapacity:[str length]];
while (length > 0) {
--length;
[rev appendString:[NSString stringWithFormat:#"%c", [str characterAtIndex:length]]];
}
NSLog(#"%#", rev);
Using characterAtIndex doesn't work well with non-ascii characters.
- (NSString *)reverseMyString:(NSString *)string {
NSString *output = [[NSString alloc] init];
for(int i = string.length-1; i>=0; i--) {
output = [output stringByAppendingString:[string substringWithRange:NSMakeRange(i, 1)]];
}
return output;
}

pasing complex string on iphone

i want to parse this string
appDelegate.gpsArray= "\n\n 21.318\n03.863\n\n\n 21.317\n03.864\n\n\n 11.316\n113.864\n\n\n"
so that i cant get value like
1) a[0]=21.318, a[1]=03.863,a[3]=11.317,a[4]=113.846....
or how to get this as 2d array like
2)
a[0,0]=21.318,103.863
a[1,1]=21.318,103.863
i did this but of no use
NSMutableArray *a1 = [[NSMutableArray alloc] init];
[a1 addObjectsFromArray:appDelegate.gpsArray ];
Kindly suggest how to use both ways like 1D and 2D
I'd solve your problem in this way:
NSArray *stringsArray = [appDelegate.gpsArray componentsSeparatedByString:"\n"];
NSMutableArray *result = [NSMutableArray array];
NSNumberFormatter *f = [[NSNumberFormatter alloc] init];
[f setNumberStyle:NSNumberFormatterDecimalStyle];
for (NSString *str in stringsArray ) {
if( ![str isEqualToString:#""] ) {
[result addObject:[f numberFromString:str]];
}
}
[f release];
Then you can convert the result array to two-dimensional array:
NSMutableArray *result2D = [NSMutableArray array];
for ( int i = 0; i < [result count] / 2; i++ ) {
NSMutableArray *innerArray = [[NSMutableArray alloc] init];
[innerArray addObject:[result objectAtIndex:2 * i]];
[innerArray addObject:[result objectAtIndex:2 * i + 1]];
[result2D addObject:innerArray];
[innerArray release];
}

Somehow my singleton properties are getting released

I have a singleton object called PoolManager that loads and saves some data in a plist. Throughout my program when something needs to know about my pool, it asks the [PoolManager sharedPoolManager] for it's properties. I have a single view that's responsible for setting these properties and all others just read from it. It was all working fine, and then for no reason I can tell, it started crashing. I set NSZombieEnabled = YES and can see that when I access one of the two NSString properties, they appear to have been released. The debugger message is: *** -[CFString respondsToSelector:]: message sent to deallocated instance 0x5a336d0
I tried going back to a previous snapshot where everything worked and it still does this. I even used TimeMachine to go back to the project from yesterday and it does it too. I'm baffled.
Here is the singleton object code... It's the surface and shape strings that are apparently zombies. Sorry for all the NSLogs
// MyPoolSingleton.h
#import <Foundation/Foundation.h>
#define kFileName #"data.plist"
#interface PoolManager : NSObject {
float volume;
float length;
float width;
float depth;
NSString *surface;
NSString *shape;
BOOL isMetric;
int fcTarget;
int cyaTarget;
int taTarget;
int chTarget;
int saltTarget;
}
#property float volume;
#property float length;
#property float width;
#property float depth;
#property (nonatomic, retain) NSString *surface;
#property (nonatomic, retain) NSString *shape;
#property BOOL isMetric;
#property int fcTarget;
#property int cyaTarget;
#property int taTarget;
#property int chTarget;
#property int saltTarget;
+ (PoolManager*)sharedPoolManager;
- (void)retrieveState;
- (void)saveState;
- (NSString*)dataFilePath;
#end
// MyPoolSingleton.m
#import "PoolManager.h"
#implementation PoolManager
#synthesize volume;
#synthesize length;
#synthesize width;
#synthesize depth;
#synthesize surface;
#synthesize shape;
#synthesize isMetric;
#synthesize fcTarget;
#synthesize cyaTarget;
#synthesize taTarget;
#synthesize chTarget;
#synthesize saltTarget;
static PoolManager* _sharedPoolManager = nil;
+ (PoolManager*)sharedPoolManager {
#synchronized([PoolManager class])
{
if (!_sharedPoolManager)
[[self alloc] init];
return _sharedPoolManager;
}
return nil;
}
+ (id)alloc {
#synchronized([PoolManager class])
{
NSAssert(_sharedPoolManager == nil, #"Attempted to allocate a second instance of a singleton.");
_sharedPoolManager = [super alloc];
return _sharedPoolManager;
}
return nil;
}
- (id)init {
self = [super init];
return self;
}
- (void)retrieveState {
NSLog(#"--retrieveState");
NSString *filePath = [self dataFilePath];
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
NSLog(#" fileExistsAtPath: reading array from plist");
NSArray *array = [[NSArray alloc] initWithContentsOfFile:filePath];
volume = [[array objectAtIndex:0] floatValue];
NSLog(#" reading array: volume = %1.1f", volume);
length = [[array objectAtIndex:1] floatValue];
NSLog(#" reading array: length = %1.1f", length);
width = [[array objectAtIndex:2] floatValue];
NSLog(#" reading array: width = %1.1f", width);
depth = [[array objectAtIndex:3] floatValue];
NSLog(#" reading array: depth = %1.1f", depth);
self.surface = [array objectAtIndex:4];
NSLog(#" reading array: surface = %#", surface);
self.shape = [array objectAtIndex:5];
NSLog(#" reading array: shape = %#", shape);
isMetric = [[array objectAtIndex:6] boolValue];
NSLog(#" reading array: isMetric = %d", isMetric);
fcTarget = [[array objectAtIndex:7] intValue];
NSLog(#" reading array: fcTarget = %d", fcTarget);
cyaTarget = [[array objectAtIndex:8] intValue];
NSLog(#" reading array: cyaTarget = %d", cyaTarget);
taTarget = [[array objectAtIndex:9] intValue];
NSLog(#" reading array: taTarget = %d", taTarget);
chTarget = [[array objectAtIndex:10] intValue];
NSLog(#" reading array: chTarget = %d", chTarget);
saltTarget = [[array objectAtIndex:11] intValue];
NSLog(#" reading array: saltTarget = %d", saltTarget);
[array release];
}
else {
NSLog(#" !fileExistsAtPath: intitializing values to nil/zero");
volume = 0.0;
length = 0.0;
width = 0.0;
depth = 0.0;
surface = #"";
shape = #"";
isMetric = NO;
fcTarget = 0.0;
cyaTarget = 0.0;
taTarget = 0.0;
chTarget = 0.0;
saltTarget = 0.0;
}
}
- (void)saveState {
NSLog(#"--saveState");
NSMutableArray *array = [[NSMutableArray alloc] init];
NSLog(#" building array: volume = %1.1f", volume);
[array addObject:[NSNumber numberWithFloat:volume]];
NSLog(#" building array: length = %1.1f", length);
[array addObject:[NSNumber numberWithFloat:length]];
NSLog(#" building array: width = %1.1f", width);
[array addObject:[NSNumber numberWithFloat:width]];
NSLog(#" building array: depth = %1.1f", depth);
[array addObject:[NSNumber numberWithFloat:depth]];
NSLog(#" building array: surface = %#", surface);
[array addObject:surface];
NSLog(#" building array: shape = %#", shape);
[array addObject:shape];
NSLog(#" building array: isMetric = %d", isMetric);
[array addObject:[NSNumber numberWithBool:isMetric]];
NSLog(#" building array: fcTarget = %d", fcTarget);
[array addObject:[NSNumber numberWithInt:fcTarget]];
NSLog(#" building array: cyaTarget = %d", cyaTarget);
[array addObject:[NSNumber numberWithInt:cyaTarget]];
NSLog(#" building array: taTarget = %d", taTarget);
[array addObject:[NSNumber numberWithInt:taTarget]];
NSLog(#" building array: chTarget = %d", chTarget);
[array addObject:[NSNumber numberWithInt:chTarget]];
NSLog(#" building array: saltTarget = %d", saltTarget);
[array addObject:[NSNumber numberWithInt:saltTarget]];
[array writeToFile:[self dataFilePath] atomically:YES];
[array release];
}
- (NSString*)dataFilePath {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
return [documentsDirectory stringByAppendingPathComponent:kFileName];
}
- (void)dealloc {
[shape release], shape = nil;
[surface release], surface = nil;
[super dealloc];
}
#end
objectAtIndex: gives an autoreleased object. You should either retain it, or use the property accessor self.surface = ... and self.shape = ... when setting those.
Personally I prefer the following pattern for singletons:
+ (id) sharedPoolManager
{
static id sharedPoolManager = nil;
#synchronized (self) {
if (sharedPoolManager == nil) {
sharedPoolManager = [self new];
}
}
return sharedPoolManager;
}
- (id) init
{
if ((self = [super init]) != nil) {
// Initialize ... nothing special here ...
}
return self;
}
(Note that self in a class method is equivalent to [SomeClass class])
The above is more concise and I prefer to keep any singleton code outside of init and alloc since I can then also create multiple instances if needed. For example in unit tests.
Personally I don't think you have to protect the programmer from creating multiple instances. The contract is clear: sharedPoolManager returns a singleton instance. If that is what you want/need then use that. Otherwise create instances the usual way.

Memory leaks in NSMutableDictionary

My coding contains a memory leak, and somehow I can't find the leak.
Leaks points me in the direction of the way I create "ReportDetailItems"
e.g. areaContainer = [[[ReportDetailItem alloc] init] autorelease];
I've been looking at this for hours and I am at a total loss, the objects reported leaking are "ReportDetailItem", and the NSMutableDictionary contained in those objects.
Please advice.
------[ReportDetailItem.h
#interface ReportDetailItem : NSObject
{
NSNumber *total;
NSMutableDictionary *items;
}
#property (nonatomic, retain) NSNumber *total;
#property (nonatomic, retain) NSMutableDictionary *items;
- (NSString *)description;
#end
------[ReportDetailItem.m
#synthesize items, total;
- (id)init {
if (self = [super init]) {
self.items = [NSMutableDictionary dictionaryWithCapacity:0];
DLog("Alloc: %d", [items retainCount]);
}
return self;
}
- (NSString *)description {
return #"ReportDetailItem";
}
- (void)release {
[super release];
}
- (void)dealloc {
[self.items release];
[self.total release];
items = nil;
total = nil;
[super dealloc];
}
#end
------[Leaking code
NSError *error;
NSArray *data = [self.managedObjectContext executeFetchRequest:request error:&error];
if (data == nil || [data count] == 0) {
DLog(#"No data.")
} else {
for (int i=0; i < [data count]; i++) {
TaskEntity *task = [data objectAtIndex:i];
NSString *areaKey = task.activity.project.area.title.text;
NSString *projectKey = task.activity.project.title.text;
NSString *activityKey = task.activity.title.text;
ReportDetailItem *areaContainer;
if (![dataSource objectForKey:areaKey]) {
areaContainer = [[[ReportDetailItem alloc] init] autorelease];
} else {
areaContainer = [dataSource objectForKey:areaKey];
}
areaContainer.total = [NSNumber numberWithInt:([task.seconds intValue] + [areaContainer.total intValue])];
[dataSource setObject:areaContainer forKey:areaKey];
ReportDetailItem *projectContainer;
if (![areaContainer.items objectForKey:projectKey]) {
projectContainer = [[[ReportDetailItem alloc] init] autorelease];
} else {
projectContainer = [areaContainer.items objectForKey:projectKey];
}
projectContainer.total = [NSNumber numberWithInt:([task.seconds intValue] + [projectContainer.total intValue])];
[areaContainer.items setObject:projectContainer forKey:projectKey];
ReportDetailItem *activityContainer;
if (![projectContainer.items objectForKey:activityKey]) {
activityContainer = [[[ReportDetailItem alloc] init] autorelease];
} else {
activityContainer = [projectContainer.items objectForKey:activityKey];
}
activityContainer.total = [NSNumber numberWithInt:([task.seconds intValue] + [activityContainer.total intValue])];
[projectContainer.items setObject:activityContainer forKey:activityKey];
}
}
I found it, the leak was located in the way I allocated the "dataSource"
---[Leak
- (void)viewDidLoad {
[super viewDidLoad];
self.dataSource = [[NSMutableDictionary alloc] init];
[self fetchData];
}
---[No leak
- (void)viewDidLoad {
[super viewDidLoad];
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
self.dataSource = dict;
[dict release];
[self fetchData];
}
I'm pretty skeptic about the two ways u assign pointers to the ReportDetailItem. Why are you trying to autorelease the object in the first place? If not try this
ReportDetailItem *projectContainer;
if (![areaContainer.items objectForKey:projectKey]) {
projectContainer = [[ReportDetailItem alloc] init];
} else {
projectContainer = [[areaContainer.items objectForKey:projectKey] retain];
}
projectContainer.total = [NSNumber numberWithInt:([task.seconds intValue] + [projectContainer.total intValue])];
[areaContainer.items setObject:projectContainer forKey:projectKey];
if(projectContainer) {
[projectContainer release];
projectContainer = nil;
}