In my class Orders, I've 2 functions 'generateOrderSummary' & 'createOrderSummaryItem':
- (OrderSummary *)generateOrderSummary {
//Cleaning the references but OrderSummaryItem leaks
[self.currentOrderSummary removeAllOrderedItems];
self.currentOrderSummary = nil;
for(MenuItem *menuItem in self.selectedItems) {
OrderSummaryItem *orderSummaryItem = [self createOrderSummaryItem:menuItem];
//Retain count = 1
[orderSummary addOrderedItem:orderSummaryItem withServiceStationCode:menuItem.serviceStationCode withCategory:menuItem.category withCourseOrder:menuItem.courseOrder];
//Retain count = 5;
}
self.currentOrderSummary = orderSummary;
[orderSummary release];
orderSummary = nil;
return self.currentOrderSummary;
}
- (OrderSummaryItem *) createOrderSummaryItem:(MenuItem *)menuItem {
OrderSummaryItem *summaryItem = [[[OrderSummaryItem alloc]init] autorelease];
//Set summaryItem properties
return summaryItem;
}
This' OrderSummary class with 3 NSMutableDictionaries and 1 NSMutableArray all keeping reference to the OrderSummaryItem object.
-(void)addOrderedItem:(OrderSummaryItem *)orderedItem withServiceStationCode:(NSString *)serviceStationCode withCategory:(NSString *)category withCourseOrder:(NSString *)courseOrder {
if (self.serviceStationDict == nil) {
self.serviceStationDict = [NSMutableDictionary dictionaryWithCapacity:1];
}
if (self.categoryDict == nil) {
self.categoryDict = [NSMutableDictionary dictionaryWithCapacity:1];
}
if (self.courseOrderDict == nil) {
self.courseOrderDict = [NSMutableDictionary dictionaryWithCapacity:1];
}
if(self.orderedItems == nil) {
self.orderedItems = [NSMutableArray arrayWithCapacity:1];
}
if(serviceStationCode != nil) {
NSMutableArray *orderedItemsForServiceStation = [self.serviceStationDict objectForKey:serviceStationCode];
if (orderedItemsForServiceStation != nil) {
[orderedItemsForServiceStation addObject:orderedItem];
}
else {
orderedItemsForServiceStation = [NSMutableArray arrayWithCapacity:1];
[orderedItemsForServiceStation addObject:orderedItem];
[self.serviceStationDict setObject:orderedItemsForServiceStation forKey:serviceStationCode];
//Retain count = 2
}
}
if(category != nil) {
NSMutableArray *orderedItemsForCategory = [self.categoryDict objectForKey:category];
if (orderedItemsForCategory != nil) {
[orderedItemsForCategory addObject:orderedItem];
}
else {
orderedItemsForCategory = [NSMutableArray arrayWithCapacity:1];
[orderedItemsForCategory addObject:orderedItem];
[self.categoryDict setObject:orderedItemsForCategory forKey:category];
//Retain count = 3
}
}
if(courseOrder != nil) {
NSMutableArray *orderedItemsForCourseOrder = [self.courseOrderDict objectForKey:courseOrder];
if (orderedItemsForCourseOrder != nil) {
[orderedItemsForCourseOrder addObject:orderedItem];
}
else {
orderedItemsForCourseOrder = [NSMutableArray arrayWithCapacity:1];
[orderedItemsForCourseOrder addObject:orderedItem];
[self.courseOrderDict setObject:orderedItemsForCourseOrder forKey:courseOrder];
//Retain count = 4
}
}
[self.orderedItems addObject:orderedItem];
//Retain count = 5
}
-(void)removeAllOrderedItems{
[self.serviceStationDict removeAllObjects];
self.serviceStationDict = nil;
[self.categoryDict removeAllObjects];
self.categoryDict = nil;
[self.courseOrderDict removeAllObjects];
self.courseOrderDict = nil;
[self.orderedItems removeAllObjects];
self.orderedItems = nil;
}
I'm not able to find out why my OrderSummaryItem is leaking despite cleaning it. My 'generateOrderSummary' function is called every 5 seconds to refresh the view.
if u declare your arrays getter and setter than after alloc it so u have to Release **twice** because its retain count becomes 2 that`s y try that...
Head First Iphone Development in this Books it`s explain well...
try adding autorelease pool here:
for(MenuItem *menuItem in self.selectedItems) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
OrderSummaryItem *orderSummaryItem = [self createOrderSummaryItem:menuItem];
//Retain count = 1
[orderSummary addOrderedItem:orderSummaryItem withServiceStationCode:menuItem.serviceStationCode withCategory:menuItem.category withCourseOrder:menuItem.courseOrder];
//Retain count = 5;
[pool release];}
Maybe there's no leak, just main pool does not drain frequently enough
Related
while removing the runtime memory leaks in my iPad application , I came across this strange memory leak in NSObject+JSONSerializableSupport class in the following method
+ (id) deserializeJSON:(id)jsonObject {
id result = nil;
if ([jsonObject isKindOfClass:[NSArray class]]) {
//JSON array
result = [NSMutableArray array];
for (id childObject in jsonObject) {
[result addObject:[self deserializeJSON:childObject]];
}
}
else if ([jsonObject isKindOfClass:[NSDictionary class]]) {
//JSON object
//this assumes we are dealing with JSON in the form rails provides:
// {className : { property1 : value, property2 : {class2Name : {property 3 : value }}}}
NSString *objectName = [[(NSDictionary *)jsonObject allKeys] objectAtIndex:0];
Class objectClass = NSClassFromString([objectName toClassName]);
if (objectClass != nil) {
//classname matches, instantiate a new instance of the class and set it as the current parent object
result = [[[objectClass alloc] init] autorelease];
}
NSDictionary *properties = (NSDictionary *)[[(NSDictionary *)jsonObject allValues] objectAtIndex:0];
NSDictionary *objectPropertyNames = [objectClass propertyNamesAndTypes];
for (NSString *property in [properties allKeys]) {
NSString *propertyCamalized = [[self convertProperty:property andClassName:objectName] camelize];
if ([[objectPropertyNames allKeys]containsObject:propertyCamalized]) {
Class propertyClass = [self propertyClass:[objectPropertyNames objectForKey:propertyCamalized]];
[result setValue:[self deserializeJSON:[propertyClass deserialize:[properties objectForKey:property]]] forKey:propertyCamalized];
}
}
}
else {
//JSON value
result = jsonObject;
}
return result;
}
I am getting the memory leak on this line
[result setValue:[self deserializeJSON:[propertyClass deserialize:[properties objectForKey:property]]] forKey:propertyCamalized];
Please suggest a solution or tell me where i am going wrong.
I am having a memory leak, and can't figure it out. Basically, what I am doing here is pulling in images to a Mutable Dictionary and returning the dictionary.
- (NSMutableDictionary *)loadImageDataGroup:(NSUInteger)index {
int lim = 5;
int sta = 0;
if (index > lim) {
sta = index-lim;
}
int fin = (((lim*2)+1)+sta);
if (fin > [self imageCount]) {
sta = ([self imageCount]-((lim*2)-1));
fin = [self imageCount];
}
BOOL firstTime = NO;
if ([imagesLoaded count] == 0) {
firstTime = YES;
}
NSMutableDictionary *tempDict = [[[NSMutableDictionary alloc] init] autorelease];
for (int i = sta; i < fin; i++) {
NSString *imageName = [self imageNameAtIndex:i];
if ([imagesLoaded valueForKey:imageName] == nil) {
// This is the Memory Leak...at least that is where Leaks is pointing me.
NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:imageName]];
[tempDict setObject:imageData forKey:imageName];
} else {
[tempDict setObject:[imagesLoaded valueForKey:imageName] forKey:imageName];
}
}
return tempDict;
}
The leak is in the NSData = *imageData spot, and when I pull it up in leaks, it points to NSConcreteData.
Looking at your code, I'm not seeing anything obviously wrong. Be aware that Instruments can produce false positives.
See the following:
Instruments showing false leak?
In my iPhone Project when i select build and analyze (shift + mac + A ) it will give me all potential memory leak in my project... but in my current project it is not working... when i intentionally put a memory leak and select build and analyze... it doesn't give me any potential memory leak as analyzer result
if i write
NSMutableArray *tempArray = [[NSMutableArray alloc] initWithCapacity:6];
NSMutableArray *tempArrayfinal = [[NSMutableArray alloc] initWithCapacity:12];
and doesn't release it... it is not giving me any potential leak but if i write
NSString *leakyString = [[NSString alloc] initWithString:#"Leaky String "];
NSLog(#"%#",leakyString);
here it gives me potential leak as analyzer result...why it is not giving potential leak in NSMutableArray and why it gives potential leak in NSString ?... how can i rely on Build and analyze for memory leak...
I've run the app with Leak tool and it is showing me leak in tempArray and tempArrayfinal
Here is my function
- (void)viewDidLoad
{
[super viewDidLoad];
maxOnSnaxAppDelegate *delegate = (maxOnSnaxAppDelegate *)[[UIApplication sharedApplication] delegate];
lblMessage.tag = MESSAGE_LABEL;
lblGuess.tag = GUESS_LABEL;
lblScore.tag = SCORE_LABEL;
self.gameCompleteView.tag = FINAL_SCORE_VIEW;
lblFinalScore.tag = FINAL_SCORE_LABEL;
lblGuess.text = #"";
lblMessage.text = #"";
lblScore.text = #"";
int row = 0;
int column = 0;
maxImagrArray = [[NSMutableArray alloc] init];
for(UIView *subview in [self.view subviews]) {
if([subview isKindOfClass:[CustomImageView class]])
{
[subview removeFromSuperview];
}
}
for(int i = 0 ; i < 12 ; i++)
{
if(i%3 == 0 && i != 0)
{
row++;
column = -1;
}
if(i != 0 )
{
column++;
//row = 0;
}
CustomImageView *tempImageView = [[CustomImageView alloc] initWithImage:[UIImage imageNamed:#"max-img.png"]];
tempImageView.frame = CGRectMake((column*tempImageView.frame.size.width) + 45, (row*tempImageView.frame.size.height)+ 60, tempImageView.frame.size.width, tempImageView.frame.size.height);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextClearRect(context, tempImageView.bounds);
[self.view addSubview:tempImageView];
tempImageView.tag = i+1;
tempImageView.userInteractionEnabled = YES;
[maxImagrArray addObject:tempImageView];
[tempImageView setIndex:i];
[tempImageView release];
}
NSMutableArray *tempArray = [[NSMutableArray alloc] initWithCapacity:6];
NSMutableArray *tempArrayfinal = [[NSMutableArray alloc] initWithCapacity:12];
for(int i = 0 ; i < 12 ; i++)
{
if(i < 6)
{
int temp = (arc4random() % 10) + 1;
NSString *tempStr = [[NSString alloc] initWithFormat:#"%d",temp];
[tempArray insertObject:tempStr atIndex:i];
[tempArrayfinal insertObject:tempStr atIndex:i];
[tempStr release];
}
else
{
int temp = (arc4random() % [tempArray count]);
[tempArrayfinal insertObject: (NSString *)[tempArray objectAtIndex:temp] atIndex:i];
//int index = [(NSString *)[tempArray objectAtIndex:temp] intValue];
[tempArray removeObjectAtIndex:temp];
}
CustomImageView *tmpCustom = [maxImagrArray objectAtIndex:i];
tmpCustom.frontImageIndex = [(NSString *)[tempArrayfinal objectAtIndex:i] intValue];
NSLog(#"%d",tmpCustom.frontImageIndex);
}
[maxImagrArray release];
delegate.time = 60.0;
timer = nil;
timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(countDown) userInfo:nil repeats:YES];
delegate.view = self.view;
//[tempArray release];
//[tempArrayfinal release];//these 2 lines are deliberately commented to see
//...it is not showing any potential memory leak though....
delegate.viewController = self;
}
please help...
[tempArray insertObject:tempStr atIndex:i];
[tempArrayfinal insertObject:tempStr atIndex:i];
are the culprits... when i uncomment these 2 lines.. it stops giving me the warning... i don't know why...
You shouldn't really rely on the Build and Analyze tool. It does not always catch all leaks. Threre is no substitute for following the memory management rules from apple (apart from garbage collection on OS X). However, I'm not sure why it isn't catching such a simple leak. I tried at line in a method and it did give me a result. Are you sure its not in an if statement, because I've found that sometimes in an if statement it won't correct you.
So I'm running instruments on my app, and getting a leak that I could have sworn I was doing right.
+ (NSMutableArray *)decode:(NSDictionary *)encoded_faculty_array
{
NSArray *faculty_id_data = [encoded_faculty_array objectForKey:#"faculty_id"];
NSArray *faculty_first_name = [encoded_faculty_array objectForKey:#"first_name"];
NSArray *faculty_last_name = [encoded_faculty_array objectForKey:#"last_name"];
NSMutableArray* faculty_array = [[NSMutableArray alloc] init];
for(int a = 0; a < [faculty_id_data count]; a++)
{
Faculty *new_fac = [[Faculty alloc] initWithFacultyId:[Dearray clean:[faculty_id_data objectAtIndex:a] withDefault:#"0"]
andFirstName:[Dearray clean:[faculty_first_name objectAtIndex:a] withDefault:#"Name not found"]
andLastName:[Dearray clean:[faculty_last_name objectAtIndex:a] withDefault:#" "]
andBio:nil
andDegrees:nil
andTitle:nil];
[faculty_array addObject:new_fac];
[new_fac release];
}
[faculty_array autorelease];
return faculty_array;
}
It's reporting a leak on new_fac. I released it immediately after I called it though. Any idea what could be causing that problem?
Thanks.
EDIT
Here is code for intializing the Faculty instance new_fac:
- (id) initWithFacultyId:(NSString *)new_id andFirstName:(NSString *)new_first_name andLastName:(NSString *)new_last_name andBio:(NSString *)new_bio andDegrees:(NSString *)new_degrees andTitle:(NSString *)new_title
{
if (self = [super init]) {
self.faculty_id = new_id;
self.first_name = new_first_name;
self.last_name = new_last_name;
self.bio = new_bio;
self.degrees = new_degrees;
self.title = new_title;
}
return self;
}
You could try checking to see if the properties of Faculty and make sure those NSStrings(firstName, lastName etc) are being released properly.
If those strings are properties that are 'retained' they should be released in Faculty dealloc.
I have an NSArray of names, I want to sort them alphabetically into a UITableView and separate them into sections.
I have a tagged section at the top, being section 0. I want the names sorted aplhabetically to come after that. So all names beginning with A get put into section 1, B into section 2, and so on.
I need to be able to somehow get the number of rows for each section, and then put the objects in each section.
How do I do this?
Here is a method for a category on NSArray to do grouping:
#interface NSArray (Grouping)
- (NSArray*) groupUsingFunction: (id (*)(id, void*)) function context: (void*) context;
#end
#implementation NSArray (Grouping)
- (NSArray*) groupUsingFunction: (id (*)(id, void*)) function context: (void*) context
{
NSArray* groupedArray = nil;
NSMutableDictionary* dictionary = [NSMutableDictionary new];
if (dictionary != nil)
{
for (id item in self)
{
id key = function(item, context);
if (key != nil)
{
NSMutableArray* array = [dictionary objectForKey: key];
if (array == nil) {
array = [NSMutableArray arrayWithObject: item];
if (array != nil) {
[dictionary setObject: array forKey: key];
}
} else {
[array addObject: item];
}
}
}
groupedArray = [NSMutableArray arrayWithArray: [dictionary allValues]];
[dictionary release];
}
return groupedArray;
}
#end
You can use it like this:
id GroupNameByFirstLetter(NSString* object, void* context)
{
return [object substringToIndex: 1];
}
NSInteger SortGroupedNamesByFirstLetter(id left, id right, void* context)
{
return [[left objectAtIndex: 0] characterAtIndex: 0] - [[right objectAtIndex: 0] characterAtIndex: 0];
}
NSMutableArray* names = [NSArray arrayWithObjects: #"Stefan", #"John", #"Alex",
#"Sue", #"Aura", #"Mikki", #"Michael", #"Joe", #"Steve", #"Mac", #"Fred",
#"Faye", #"Paul", nil];
// Group the names and then sort the groups and the contents of the groups.
groupedNames_ = [[names groupUsingFunction: GroupNameByFirstLetter context: nil] retain];
[groupedNames_ sortUsingFunction: SortGroupedNamesByFirstLetter context: nil];
for (NSUInteger i = 0; i < [groupedNames_ count]; i++) {
[[groupedNames_ objectAtIndex: i] sortUsingSelector: #selector(compare:)];
}
I modified St3fans answer to be a bit more modern and work with Blocks instead:
#interface NSArray (Grouping)
- (NSArray*) groupUsingBlock:(NSString* (^)(id object)) block;
#end
- (NSArray*) groupUsingBlock:(NSString* (^)(id object)) block
{
NSArray* groupedArray = nil;
NSMutableDictionary* dictionary = [NSMutableDictionary new];
if (dictionary != nil)
{
for (id item in self)
{
id key = block(item);
if (key != nil)
{
NSMutableArray* array = [dictionary objectForKey: key];
if (array == nil) {
array = [NSMutableArray arrayWithObject: item];
if (array != nil) {
[dictionary setObject: array forKey: key];
}
} else {
[array addObject: item];
}
}
}
groupedArray = [NSMutableArray arrayWithArray: [dictionary allValues]];
[dictionary release];
}
return groupedArray;
}
You can use it like this:
NSArray *grouped = [arrayToGroup groupUsingBlock:^NSString *(id object) {
return [object valueForKey:#"name"];
}];
You should probably create an array of arrays, one for each letter, and store your names that way. While you can use a single array for storage, there's no quick way to do the segmentation you're looking for. Sorting, sure, but not section-ization.