What is the source of the leaky object for this code? - iphone

Anyone able to help re what is the source of the leaky object for this code:
My application compiles without any ANALYZE issues. When I run PROFILER and look at Memory Leaks I see leaks appears. One of these leaks is in my WeekendEvent object. There are 3 Leaked Block row items in instruments per the below (I've noted in the code where these point to):
Malloc +1
Retain +2
Release +1
Question - I assume this implies there is a release, however where would this leak be from. The segments of my code that clicking through on instruments highlights is below. To me it seems OK in that:
the WeekendEvent I create I release after passing into the addWeekendEvent method
in the addWeekendEvent it just adds it to a NSMutableArray, and hence I thought the arrange does any memory management for it's object it contains
I do release the NSMutableArray in the dealloc too
Key Source Code Bits & What Instuments Highlights
// ------Weekends Method (plural)-----
WeekendEvent *weEvent = [[WeekendEvent alloc] init]; // [INSTRUMENTS - 87.5%]
[week addWeekendEvent:weEvent]; // [INSTRUMENTS - 12.5%]
[weEvent release];
//------Weekend *.h ------------
#interface Weekend : NSObject {
NSMutableArray* _events;
}
- (void)addWeekendEvent:(WeekendEvent*)weEvent;
#property (nonatomic, retain) NSMutableArray* events;
#end
//------Weekend *.m -------------
- (void)addWeekendEvent:(WeekendEvent*)weEvent {
[self.events addObject:weEvent];
}
- (void) dealloc {
[_events release];
[super dealloc];
}
EDIT: Some additional code re how the "week" variable above was created/used - so in the Weekends Method the code I posted was within a for loop - the code with the for loop shown therefore was:
for (Weekend *week in self.items) {
// do pass "week.start" to some methods (which is an NSDate) - don't think this would be relevant though?
WeekendEvent *weEvent = [[WeekendEvent alloc] init]; // [INSTRUMENTS - 87.5%]
[week addWeekendEvent:weEvent]; // [INSTRUMENTS - 12.5%]
[weEvent release];
}
// Note - self.items I checked is "released" in the dealloc method
EDIT 2 - Just to confirm, it is an "WeekendEvent" instance that Instruments highlights in it's "leaked objects" column. Just in case this wasn't clear.
EDIT 3 - Re how I setup the items variable - key code bits are:
#interface Weekends : NSObject {
NSMutableArray* _items;
}
#property (nonatomic, retain) NSMutableArray* items;
#synthesize items = _items;
- (void) dealloc {
[_items release];
[super dealloc];
}

The memory management in the code you show is correct, assuming that the rest of your Weekend class looks something like this:
#synthesize events = _events;
- (id)init {
if ((self = [super init]) == nil) { return nil; }
_events = [[NSMutableArray alloc] initWithCapacity:0];
return self;
}
Also, the instruments results match all of your code:
Malloc +1 == WeekendEvent *weEvent = [[WeekendEvent alloc] init];
Retain +2 == [week addWeekendEvent:weEvent];
Release +1 == [weEvent release];
Based on that logic, the most likely candidate is that your week object is not properly released. You haven't shown the code that explains how it was created, but I do notice that the code you did post is for a Weekend class. Are you sure week is not of a different type?

Related

using arc, my ivars are null after init

MOST NEW TESTING:
I placed a NSLog(#"%p", self.myArray);
after the array assignment and I am seeing a address actually logged.....!?!?!
2012-03-06 01:33:52.618 ArrayTest[9883:f803] 0xae0f160
Seems that Xcode is all wacked out if it cant see the addess of that ivar in either local variables or with the tool tip highlight method...
Thoughts?
NEWEST TESTING:
I created a brand new project.
It seems that simple assigning of objects to ivars is not working at all. If I look at the address of myArray after the assignment of the newly created array it has a null address.
output of nslog
2012-03-06 01:30:37.283 ArrayTest[9848:f803] (
)
(lldb)
//
// ViewController.h
// ArrayTest
//
// Created by Ben J Brown on 3/6/12.
// Copyright (c) 2012StudioBflat. All rights reserved.
//
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
{
NSMutableArray *myArray;
}
#property (strong) NSMutableArray *myArray;
#end
//
// ViewController.m
// ArrayTest
//
// Created by Ben J Brown on 3/6/12.
// Copyright (c) 2012 StudioBflat. All rights reserved.
//
#import "ViewController.h"
#implementation ViewController
#synthesize myArray;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSMutableArray *array = [NSMutableArray arrayWithCapacity:16];
self.myArray = array;
NSLog(#"%#",self.myArray);
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
} else {
return YES;
}
}
#end
OLDER DATA:
In my viewDidLoad I have:
NSLog(#"%#",self.collectionOfImageViews);
self.collectionOfImageViews = [[NSMutableArray alloc] initWithCapacity:NUMBER_OF_COLUMNS*NUMBER_OF_ROWS];
NSLog(#"%#",self.collectionOfImageViews);
However later on when I access that array the array has an address but all the objects that I added to it are gone, and when I send a count message to that object(the NSMutableArray) it throws this in the console:
-[UIImage count]: unrecognized selector sent to instance 0x6b7ab40
My properties in my interface:
#property(strong) NSMutableArray* collectionOfImageViews;
and I have #synthesize collectionOfImageViews; right after my #implmentation... what am I missing here?
Here is where I make the collection:
NSLog(#"%#",self.collectionOfImageViews);
self.collectionOfImageViews = [[NSMutableArray alloc] initWithCapacity:NUMBER_OF_COLUMNS*NUMBER_OF_ROWS];
NSLog(#"%#",self.collectionOfImageViews);
looking at the array it has a null address right after this action....
Concerning that earlier weird error where I had it consoling out that it was a UIImage not responding to count... I fixed that kinda by changing the order of the ivar declarations in the interface:
#import <UIKit/UIKit.h>
#import "TiledImageView.h"
#interface ViewController : UIViewController <TiledImageViewDelegation>
{
NSMutableArray *collectionOfImageViews;
UIImage *sourceImage;
UIImageView *currentTappedView;
}
#property(strong) NSMutableArray* collectionOfImageViews;
#property(strong) UIImage* sourceImage;
#property(strong) UIImageView* currentTappedView;
#end
As for where I fill the mutable array later here is that code:
iView = [[TiledImageView alloc] initWithImage:[UIImage imageWithCGImage:tempImage]];
iView.userInteractionEnabled = YES;
iView.delegate = self;
iView.contentMode = UIViewContentModeScaleAspectFit;
[iView setTag:index];
[iView setPosX:column];
[iView setPosY:row];
[collectionOfImageViews addObject:iView];
I'm pretty darnd confused because this is simple ivar setting and getting.. and alloc and initialization... something I have done many times before but it seems my ivars are not staying alive... I'm new to ARC.
This seems to be an LLDB bug. Use GDB for debugging instead.
edit: It obviously is a bug within lldb, i have filed a bug report back in march (it was marked as a duplicate of another bug which was later marked as closed) - the issue has been resolved in newer Xcode versions.
The fact that u get () means that there is nothing wrong with the array. You can test it easily by adding any other object like an NSNumber and then logging the array again, you should see your object there. About the memory address, If you are using the debugger you should set the break point AFTER the instruction where the array is allocated, then you will be able to see the contents of the array. Otherwise if your break point is not there who knows what you will be seeing.
Finally the -[UIImage count]: unrecognized selector sent to instance 0x6b7ab40
Means you are trying to make an UIImage object perform a count method, which doesn't exist, You probably want the count on the array not the object inside. So the problem is in where you are calling this method, you seem to have a hard time when it comes to referencing either the object or the ivar, to avoid this, on the synthesize change the #synthesize collectionOfImageViews; to #synthesize collectionOfImageViews = collectionOfImageViews;
Also try changing the compiler like others have suggested.

Memory Management in Objective-C

I wanna ask if I allocated an instance variable for private use in that class, should i release it immediately on site, or i can depend on dealloc function. (because maybe i will need it on other function) ?
//Player.h
#interface Player : NSObject
{
NSMutableArray * objectArray;
}
- (void)awake;
- (void)add;
#end
//Player.m
#implementation Player : NSObject
{
-(id) init {
self = [super init];
if (self != nil ){
[self awake];
[self add];
}
return self;
}
- (void) awake {
objectArray = [[NSMutableArray alloc] init]; //is it cause leakage?
[objectArray addObject:#"foobar"];
}
- (void) add {
[objectArray addObject:#"foobar2"];
}
- (void) dealloc {
[objectArray release];
[super dealloc];
}
}
#end
or should i using property to set the objectArray iVar?
//Player.h
#interface Player : NSObject
{
NSMutableArray * objectArray;
}
#property (nonatomic,retain)NSMutableArray* objectArray;
- (void)awake;
- (void)add;
#end
//Player.m
#implementation Player : NSObject
{
-(id) init {
self = [super init];
if (self != nil ){
[self awake];
[self add];
}
return self;
}
- (void) awake {
self.objectArray = [[NSMutableArray alloc] init autorelease]; //cause leakage?
[objectArray addObject:#"foobar"];
}
- (void) add {
[objectArray addObject:#"foobar2"];
}
- (void) dealloc {
[objectArray release];
[super dealloc];
}
}
#end
if both of them doesn't cause a leakage, what type should i use?
should i always set iVar property, and access iVar value with self even if i only want to use it in this class?
I like to take the stance that if the instance variable should not be visible outside of the class then it should not be implemented as a property. But it's a personal thing that other developers may not agree with.
Either way you would need to release the objectArray in your classes dealloc method - which is what you're currently doing.
However you need to be careful with your awake method - if it's invoked multiple times then objectArray is leaked. This is the downside of not using properties. A use of self.objectArray = [[NSMutableArray alloc] init] here would have released the previous object.
In my opinion, you should only declare properties in your header if other objects are allowed to use them. There is no good reason why you would provide an -add: method (as in your example) that adds something to your array while also providing a getter for your array so other objects can manipulate it directly. It's called encapsulation.
If you do want to have the benefits of generated getters/setters for your implementation file, you can always use a class continuation (a nameless category) inside your implementation file and include your property declarations there. That way you get real, auto-generated properties that are only visible to your class' implementation.
Personally, I wouldn't use any getter or setter methods in your example. Just allocate the NSArray in your -init and release it in -dealloc. If this -awake method of yours might be called multiple times, just add an [objectArray removeAllObjects] call and you're sure to have an empty array without worrying about memory management.
It is very likely that memory will leak in your first example because you are not sending release to the previously set instance variable (if it already existed).
This is why you should use property setters - they handle all of this stuff for you.
Also, since you are obtaining ownership of the instance variable through the property (which is defined with the retain keyword), you will definitely leak memory if you don't send the instance variable the -release message in your -dealloc method.
So the verdict is that you should use the second example, not the first.

scrolling table: message sent to deallocated instance

i've been dancing with a tambourine for a while, but still don't know what's the reason for that error.
I've got a tableView with history of user queries data from sqlite base. I'm new to iPhone developing, so my code may be a bit excessive. The hierarchy is:
HistoryModel
model-object with some init methods
HistoryDataController
gets data from database and presents an array of HistoryModel objects
HistoryViewController
subclass of UITableView, displays data
AppDelegate
there i initially store an array of HistoryModel objects (by getting it from HistoryDataController) for HistoryViewController to access it.
The problem is, when i scroll the table or open the tab with it for the second time - it crashes with -[CFString retain]: message sent to deallocated instance
Code:
HistoryModel.h
pretty unnecessary class for that case, but i want that worked to repeat in several identical cases, but a bit more complicated
#interface HistoryModel : NSObject {
int entry_id;
NSString *word;
}
- (id)initWithWord:(NSString *)word;
- (id)initWithWord:(NSString *)word andId:(int)entry_id;
#property int entry_id;
#property (retain) NSString *word;
#end
HistoryModel.m
#implementation HistoryModel
#synthesize entry_id, word;
- (id)initWithWord:(NSString *)_word {
[super init];
word = _word;
return self;
}
- (id)initWithWord:(NSString *)_word andId:(int)_entry_id {
entry_id = _entry_id;
return [self initWithWord:_word];
#end
HistoryDataController.h
i use the entity of that class as getter of data and a storage for HistoryModel objects (in historyEntries property)
#interface HistoryDataController : NSObject {
NSMutableArray *historyEntries;
int limit;
}
#property (nonatomic, retain) NSMutableArray *historyEntries;
#property int limit;
- (id)initWithHistoryData;
- (id)initWithHistoryDataLimitedBy:(int)limit;
HistoryDataController.m
#implementation HistoryDataController
#synthesize historyEntries, limit;
- (id)initWithHistoryDataLimitedBy:(int)_limit {
[super init];
// Getting data from database
{some DB stuff}
NSMutableArray *tmp_historyEntries = [[NSMutableArray alloc] init];
while(result == SQLITE_ROW)
{
HistoryModel *currentHistoryEntry = [[HistoryModel alloc] initWithWord:[NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 1)] ];
[tmp_historyEntries addObject:currentHistoryEntry];
result = sqlite3_step(statement);
}
historyEntries = tmp_historyEntries;
{some DB stuff}
return self;
}
#end
HistoryViewController.h
subclass of UITableViewController, gets data stored in AppDelegate's property and displays in the table
#interface HistoryViewController : UITableViewController {
IBOutlet UITableView *historyTable;
SynonymsAppDelegate *appDelegate;
}
#property (retain) UITableView *historyTable;
#end
HistoryViewController.m
#implementation HistoryViewController
#synthesize historyTable, historyEntriesToShow;
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
appDelegate = (SynonymsAppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate initHistoryList];
[self.tableView reloadData];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
{standart cell stuff}
HistoryModel *historyEntry = [appDelegate.historyList objectAtIndex:indexPath.row];
cell.textLabel.text = historyEntry.word;
return cell;
}
#end
SynonymsAppDelegate.h
when history tab opens, it gets data of historyList property, that was formed by HistoryDataController :)
#interface SynonymsAppDelegate : NSObject <UIApplicationDelegate, UITabBarControllerDelegate> {
...
NSMutableArray *historyList;
}
...
#property (retain) NSMutableArray *historyList;
- (void)initHistoryList;
#end
SynonymsAppDelegate.m
#implementation SynonymsAppDelegate
#synthesize window, tabBarController, historyList;
- (void)initHistoryList {
HistoryDataController *historyDataController = [[HistoryDataController alloc] initWithHistoryData];
historyList = historyDataController.historyEntries;
}
#end
Fuf. Sorry for so much code, but i believe that's all necessary.
As a result of half the day spent on this question, i may guess, that problem is somehow connected with HistoryModel entity, because when i delete "retain" for word #property, the error switches for -[CFString isEqualToString:]: message sent to deallocated instance
I'm not really experienced in memory management, but i guess this HistoryModel objects inside historyEntry in HistoryViewController or in historyList in AppDelegate releases somehow, when scrolling the table or opening the tab for the second time.
But this's just my guessing.
Really appreciate the help.
You definitely have an issue in your -[HistoryModel initWithWord] You should retain (or better yet copy) the string that is being passed.
I would write it like this:
- (id)initWithWord:(NSString *)_word {
[super init];
self.word = _word; // this is same as [self setWord:_word]
return self;
}
There are some who would say using the setter in your init is not a good practice. I'm not of that camp. But in any case, you need to be retaining or copying that string.
Then you have a similar issue in your app delegate where you are leaking each HistoryDataController as you create a new one. (and that happens every time that tableview appears). And you really should be retaining that array as well (although that hasn't caused a problem yet because you're leaking the HistoryDataControllers and therefore masking that issue so far.)
My general advice to you would be don't put off memory management. To come back later and try to get it right is complicated and error-prone even for an experienced developer. It is much, much easier to build the correct memory management techniques into the code as you write it. This means it's well worth your time to read the memory management guide first before you start coding something like this. You'll save yourself a lot of time and frustration.

Memory Leaks in Cocoa

I'm working on an iphone application and having some trouble with memory leaks. I've read some docs about garbage collection that it make it sound simple but I must be missing something. I've got a viewController that needs access to an array which may need to repopulated from time to time. Here is a simplified version of what I have:
//AppDelegate.m
- (NSMutableArray *)getMathFacts {
//Some database stuff
NSMutableArray * arr = [[NSMutableArray alloc] init];
while (sqlite3_step(math_fact_statement) == SQLITE_ROW) {
[arr addObject:[[NSNumber numberWithInt:sqlite3_column_int(math_fact_statement, 0)] autorelease]];
}
return arr;
}
//ViewController.h
#interface ReviewViewController : UIViewController {
NSMutableArray *reviewArr;
}
#property (retain, nonatomic) NSMutableArray *reviewArr;
//ViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
[self loadMathFacts];
}
- (void)loadMathFacts {
self.reviewArr = [appDelegate getMathFacts];
}
- (void)loadAllMathFacts {
self.reviewArr = [appDelegate getAllMathFacts];
}
-(IBAction) getAll {
[reviewArr release];
[self loadAllMathFacts]
}
GetAllMathFacts is similar to getMathFacts, it just has a different SQL statement.
When I run this checking for Leaks it is like a sieve. It seems like something simple, but I feel like I've tried everything and it just moves the leak around.
Any advice would be appreciated.
Thanks
The iPhone OS actually doesn't have garbage collection. What you're doing with retain/release is called reference counting.
The solution to your problem is probably to make getMathFacts return an autoreleased object (change return arr; to return [arr autorelease];), because the definition of the property reviewArr is probably something like #property (retain) NSArray *reviewArr;, which means every time you call self.reviewArr = something;, something is retained, which means after you set reviewArr in loadMathFacts and loadAllMathFacts, reviewArr is retained one time too much.
In getMathFacts, you do a
NSMutableArray * arr = [[NSMutableArray alloc] init];
that array is owned by you. It has a retain count of 1. Later when
- (void)loadMathFacts {
self.reviewArr = [appDelegate getMathFacts];
}
that same array is now retained by reviewArr and the retain count goes to 2.
When you then do a
-(IBAction) getAll {
[reviewArr release];
[self loadAllMathFacts]
}
in the first release statement, your array is now getting released once and the retain count goes to 1. In [self loadAllMathFacts]
- (void)loadAllMathFacts {
self.reviewArr = [appDelegate getAllMathFacts];
}
self.reviewArr will release the the array, before retaining a new array. After this release the retain count is down to 0. I don't see a leak here. Maybe in -getAllMathFacts?
Now, one thing I would change to make things look a little better is this:
- (void)loadMathFacts {
NSMUtableArray array = [appDelegate getMathFacts];
self.reviewArr = array;
[array release];
}
- (void)loadAllMathFacts {
NSMUtableArray array = [appDelegate getAllMathFacts];
self.reviewArr = array;
[array release];
}
-(IBAction) getAll { // you don't need to release in here
[self loadAllMathFacts]
}
Plus you should rename your get method calls to use "new" instead of "get" since the convention is that if you return something that is owned by the caller, it should have new or copy in the name of the method.
As another answerer said, you could use autorelease, although I'd rather use autorelease in other situations. But if you were to do it with autorelease this is how I'd do it:
//AppDelegate.m
- (NSMutableArray *)getMathFacts {
//Some database stuff
NSMutableArray * arr = [[NSMutableArray alloc] init];
while (sqlite3_step(math_fact_statement) == SQLITE_ROW) {
[arr addObject:[[NSNumber numberWithInt:sqlite3_column_int(math_fact_statement, 0)] autorelease]];
}
return [arr autorelease];
}
do the same with -getAllMathFacts. You should still change the code to be more like above, except you don't have to release after doing the self.reviewArray, and you don't have to change the name of the methods. What you have to remember is that if even autoreleased objects can leak if you call retain on them and then forget about them. The nice thing about autorelease is that the object is kept around for the duration of a runloop, long enough to hand it to some other object and let them decide whether they want to retain it or let it expire.
I hope I haven't missed anything. Go through my logic, and feel free to poke holes in it or ask questions. I can easily have missed something.
By the way, self.reviewArr when you have:
#property (retain, nonatomic) NSMutableArray *reviewArr;
does the following:
- (void)setReviewArr:(NSMutableArray*)array
{
NSMutableArray* oldReviewArr = reviewArr;
reviewArr = [array retain];
[oldReviewArr release];
}
As of Xcode 3.2 there is support for running the Clang analyzer. To do this choose Build->Build & Analyze. This will run the analyzer which is really a wonderful tool for finding reference counting issues.
For Xcode prior to 3.2, this might help: Using Clang Static Analyzer from within XCode

Is there a Queue/FIFO data structure for the iPhone?

Before I roll my own Queue using NSMutableArray, I'd like to know if there is something more standard available. I don't see anything in the Apple docs, but I'll be surprised if there is not a Queue implementation from somewhere that folks are using. Java spoils me!
Implementing a queue based on NSMutableArray is pretty easy, it's probably under 50 lines of code.
EDIT:
Found this with a quick google search:
#interface Queue:NSObject {
NSMutableArray* objects;
}
- (void)addObject:(id)object;
- (id)takeObject;
#end
#implementation Queue
- (id)init {
if ((self = [super init])) {
objects = [[NSMutableArray alloc] init];
}
return self;
}
- (void)dealloc {
[objects release];
[super dealloc];
}
- (void)addObject:(id)object {
[objects addObject:object];
}
- (id)takeObject {
id object = nil;
if ([objects count] > 0) {
object = [[[objects objectAtIndex:0] retain] autorelease];
[objects removeObjectAtIndex:0];
}
return object;
}
#end
Cocoa itself doesn't have a Queue class, and there's not a standard per se, but there are several options, one of which may best fit your needs. See this question (and my answer).
Like you said, you can roll your own using NSMutableArray. If you just need a quick'n'dirty queue (and aren't worried about copying, encoding/decoding, enumeration, etc.) then the solution #Matt suggests is an easy approach. You should also consider adding queue methods to NSMutableArray via a category, which is nice in that your "queue" is also an array (so you can pass it for NSArray parameters), and you get all the NS(Mutable)Array functionality for free.
If performance is important, I recommend using a structure more ideally suited for removing the first element. I wrote CHCircularBufferQueue for my own framework for this very reason. (Not trying to toot my own horn, just trying to save others some time.)
I have made a category containing just the deque method, based on Matt Bridges code.
#interface NSMutableArray (ShiftExtension)
// returns the first element of self and removes it
-(id)shift;
#end
#implementation NSMutableArray (ShiftExtension)
-(id)shift {
if([self count] < 1) return nil;
id obj = [[[self objectAtIndex:0] retain] autorelease];
[self removeObjectAtIndex:0];
return obj;
}
#end
You can use the STL queue from the C++ Standard Library.
Check out the STL priority queue. It requires zero lines of code and it's portable! What more could you want?
You could use the :lastObject method of NSArray. Here is an untested example:
Queue.h
#import <Foundation/Foundation.h>
#interface Queue : NSObject
-(void)enqueue:(id)object;
-(id)dequeue;
#end
Queue.m
#import "Queue.h"
#interface Queue()
#property(nonatomic, strong) NSMutableArray *backingArray;
#end
#implementation Queue
-(id)init {
self = [super init];
if (self) {
self.backingArray = [NSMutableArray array];
}
return self;
}
-(void)enqueue:(id<NSObject>)object {
[self.backingArray addObject:object];
}
-(id)dequeue {
id object = [self.backingArray lastObject];
[self.backingArray removeObject:object];
return object;
}
#end