Big problem with memory between methods - objective-c

i don't understand this problem:
i've 2 class A and B, in A view i've two Button, ButtonCreate and ButtonAccess.
In B there is this method:
-(NSDictionary *) returnData
{
NSDIctionary *data= [NSDictionary withObjectsAndKeys.....];
return data;
}
In A i've also a property #property(nonatomic, retain) NSDictionary *dictio, and in .m file #synthesize dictio = _dictio.
ButtonCreate IBAction -->
B *secondaryClass = [[B alloc] init];
_dictio = [[secondaryClass returnData] retain];
[B release];
ButtonAccess IBAction -->
NSString *value = [_dati ObjectForKey... ];
Problem: if i push more than once ButtonCreate, in Instruments i see a memory leak, but if i cut off the "retain" in ButtonCreate method, i've a crash when i access data from ButtonAccess.
I really don't understand how can i do...can you help me?
Thanks a lot.

Try this in A, i think it could solve your problem:
ButtonCreate IBAction --> B *secondaryClass = [[B alloc] init];
self.dictio = [secondaryClass returnData];
[B release];

It appear you are trying to release B, rather than the instance of B which you named secondaryClass.
B *secondaryClass = [[B alloc] init];
_dictio = [[secondaryClass returnData] retain];
[B release];
Should it not instead be:
...
[secondaryClass release];

You didn't release the old value of _dictio, and you didn't release secondaryClass
B *secondaryClass = [[B alloc] init];
if (_dictio != nil)
[_dictio release];
_dictio = [[secondaryClass returnData] retain];
[secondaryClass release];
But, since you declared your property as retain, you can just take advantage of the property doing this for you.
B *secondaryClass = [[B alloc] init];
self.dictio = [secondaryClass returnData]; // sends retain to new, release to old
[secondaryClass release];

Related

Xcode Passing NSMutableArray from one class to another

I know this question has been asked countless of times. But none of them seems to be working! Please help! I am unable to pass arrays from one class to another. Blow are my codes
firstClass has an array declared
#FirstClass.h
- (void)viewDidLoad
{
testArray = [[NSMutableArray alloc] init];
[testArray addObject:#"test"];
[testArray addObject:#"test2"];
[testArray addObject:#"test3"];
//method to pass array
TableViewController *tvc = [[TableViewController alloc] init];
tvc.getData = [[NSMutableArray alloc] init];
tvc.getData = testArray;
NSLog(#"%i", [tvc.getData count]); // returns a value n
Here i get count of 3
}
TableViewController.h
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"%i", [getData count]); // returns a value n
Here i get 0
//Set the title
self.navigationItem.title = #"Countries";
}
I tried
FirstClass *fc = [[FirstClass alloc] init];
getData = fc.testArray;
Doesn't work as well. I tried writing a method and calling the method from my second class.
Ended up with #interface error.
Sorry, this is my first time on objective c. Am java educated.
Please help!
For the second problem, why the fc.testArray does not work is that viewDidLoad is called only after the view property is called. (lazy initialization)
So it works if you do like
FirstClass *fc = [[FirstClass alloc] init];
fc.view;
getData = fc.testArray;

Releasing synthesized property after alloc init

i have a property
//.h
#property (nonatomic, retain) SomeCLass * someSynthInstance;
//.m
#synthesize someSynthInstance = _someSynthInstance;
- (void) foo
{
self.someSynthInstance = [[SomeCLass alloc] init];
//[self.someSynthInstance release]; <- SHOULD I RELEASE HERE???
}
- (void) dealloc
{
self.someSynthInstance = nil;
}
my theory goes, that [alloc, init] creates a count of 1, and the setter, inc that count, so it becomes 2, therefore i should release it, right after
but aim getting exc_bad_access in the application after i changed everything like this, so aim not sure if its ok
you want to be releasing the instance variable rather than the property. so you can do either:
self.someSynthInstance = [[[SomeCLass alloc] init] autorelease]; // puts it in the autoreleasepool so it'll get released automatically at some point in the near future
or
_someSynthInstance = [[SomeCLass alloc] init]; // skip the property
or
self.someSynthInstance = [[SomeCLass alloc] init];
[_someSynthInstance release]; // call release on the instance variable
The standard practice is:
SomeClass *tmpObj = [[SomeClass alloc] init];
self.someSynthInstance = tmpObj;
[tmpObj release];
you should release the class variable instead.. like [_someSynthInstance release]; that should do the trick.
yes you should release after init
SomeCLass *temp = [[SomeCLass alloc] init];
self.someSynthInstance = temp;
[temp release]

NSMutableArray addObject in for loop - memory leak

i'm putting strings (which are filenames of files in a certain directory) into an NSMutableArray with a for loop:
h-file:
#import <Three20/Three20.h>
#interface AlbumController : TTThumbsViewController {
NSMutableArray *images;
}
#property (nonatomic, retain) NSMutableArray *images;
#end
m-file:
#import "AlbumController.h"
#import "PhotoSource.h"
#import "Photo.h"
#implementation AlbumController
#synthesize images;
-(void)createPhotos {
NSString *bundleRoot = [[NSBundle mainBundle] bundlePath];
NSArray *dirContents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:bundleRoot error:nil];
NSArray *onlyJPGs = [dirContents filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"self ENDSWITH '.jpg'"]];
NSMutableArray *pics = [[onlyJPGs copy] autorelease];
if(!self.images) {
self.images = [[NSMutableArray alloc] init];
}
for(int i = 0; i < [onlyJPGs count]; i++)
{
//NSLog([pics objectAtIndex:i]);
NSString *ImgURL = [#"bundle://" stringByAppendingString:[pics objectAtIndex:i]];
Photo *photo = [[Photo alloc] initWithURL:ImgURL smallURL:ImgURL size:CGSizeMake(320, 212)];
[images addObject:photo];
[photo release];
}
}
-(void)viewDidLoad{
[self createPhotos]; // method to set up the photos array
self.photoSource = [[PhotoSource alloc]
initWithType:PhotoSourceNormal
title:#"Chili Pflanzen"
photos:images
photos2:nil
];
}
#end
i do not have any problem in the simulator but on my iPod...
Error message:
Data FOrmatters temporarily unavailable, will re-try after a 'continue'. (Unknown error loading shared library "/Developer/usr/lib/libXcodeDebuggerSupport.dylib")
thanks in advance
I think you should use mutableCopy and not copy on your pics array.
so instead of:
NSMutableArray *pics = [[onlyJPGs copy] autorelease];
you should use:
NSMutableArray *pics = [[onlyJPGs mutableCopy] autorelease];
More information about copy/mutablecopy in this question: Copy & mutableCopy?
Looks like the main issue is with
[images addObject:[[Photo alloc] initWithURL:ImgURL smallURL:ImgURL size:CGSizeMake(320, 212)]];
Here you are alloc'ing Photo but not releasing it. When you add an object to an array it increases the retain count for it.
Try changing it to
Photo *photo = [[Photo alloc] initWithURL:ImgURL smallURL:ImgURL size:CGSizeMake(320, 212)];
[images addObject:photo];
[photo release];
In addition ...
I'd change
self.images = [[[NSMutableArray alloc] init] autorelease];
to
if(!self.images) {
self.images = [[NSMutableArray alloc] init];
}
Otherwise there is the potential for a memory leak if it has already been initialized, as well as that you probably do not want it autoreleased;
Your NSMutableArray instance is autoreleased. You are assigning it to the images ivar. The fact that you have declared it as a retained property doesn't matter, because you aren't assigning it to the property. My guess is that you meant to assign to the property, and the crash is caused by the inadvertent deallocation.
Change:
images = [[[NSMutableArray alloc] init] autorelease];
...to:
self.images = [[[NSMutableArray alloc] init] autorelease];
...or:
images = [[NSMutableArray alloc] init];
Also note that your property is declared as NSArray when you are allocating an instance of NSMutableArray.
Also see the Memory Management Programming Guide.

Get & Edit NSMutableArray from different class file

I am trying to access and change a array from a different class file. When using a NSLog, I get a result of (null). Below is my code:
RootViewController.h
NSMutableArray *listOfItems;
#property (nonatomic, retain) NSMutableArray *listOfItems;
RootViewController.m
#synthesize listOfItems;
listOfItems = [[NSMutableArray alloc] init];
[listOfItems addObject:#"One"];
[listOfItems addObject:#"Two"];
[listOfItems addObject:#"Three"];
SecondViewController.m
RootViewController *test = [[RootViewController alloc] init];
NSLog(#"Results: %#", test.listOfItems);
I get the following results in my console: Results: (null)
Thanks in advance,
Coulton
P.S. Obviously I have left out a bunch of code. I just tried to make it easier to read. If you need to see anything else, I would be more than happy to post more. Just ask
EDIT #1:
I am getting hundreds of NSLog Messages that look something like this:
*** __NSAutoreleaseNoPool(): Object 0x4e39020 of class __NSArrayI autoreleased with no pool in place - just leaking
And here's my init code:
- (id) init {
//NSLog(#"%#", theUserID);
// Set up database connection
NSString *myDB = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"database.db"];
database = [[Sqlite alloc] init];
[database open:myDB];
//Initialize the array.
listOfItems = [[NSMutableArray alloc] init];
// Add to array to display in the tableView
NSArray *listOfItemsTwo = [database executeQuery:#"SELECT * FROM albums"];
for (NSDictionary *rowone in listOfItemsTwo) {
NSString *getName = [rowone valueForKey:#"name"];
if (getName != NULL) {
[listOfItems addObject:getName];
[getName release];
}
}
return self;
}
I guess you reversed RootViewController.m and RootViewController.h snippets right?
Are you sure that the
listOfItems = [[NSMutableArray alloc] init];
gets called? Maybe you can put a breakpoint there.
EDIT: Order of RootViewController.m and RootViewController.h has been fixed in the question. It's not clear from the question where the above line is in the code. That's a important piece of information.
EDIT2: Example of init method.
#implementation RootViewController
- (id) init
{
listOfItems = [[NSMutableArray alloc] init];
[listOfItems addObject:#"One"];
return self;
}
#end

Objective C - UITableView after calling reloadData my object properties are null/nil

I have a ViewController defined as follows:
#interface SectionController : UITableViewController {
NSMutableArray *sections;
}
- (void) LoadSections;
When LoadSection is call it makes a call to NSURLConnection to load a url which in turn calls
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
[connection release];
[responseData release];
NSDictionary *results = [responseString JSONValue];
NSMutableArray *jSections = [results objectForKey:#"Items"];
sections = [NSMutableArray array];
for (NSArray* jSection in jSections)
{
Section* section = [Section alloc];
section.Id = [jSection objectForKey:#"Id"];
section.Description = [jSection objectForKey:#"Description"];
section.Image = [jSection objectForKey:#"Image"];
section.Parent = [jSection objectForKey:#"Parent"];
section.ProductCount = [jSection objectForKey:#"ProductCount"];
[sections addObject:section];
[section release];
}
[jSections release];
[results release];
[delegate sectionsLoaded];
[self.view reloadData];
}
The data parses correctly and I now have sections filled with many items.
Calling [self.view reloadData] forces a callback to the delegate method cellForRowAtIndexPath which should then present the data into the cell however its at this point that sections is now nil again.
Can someone please point out my mistake? I must admit I am a newbie to objective c and it probably a pointer issue. What is need to do is retain the value of sections after calling reloadData.
Many thanks.
Seeing the new code the problem is obvious:
sections = [NSMutableArray array];
should become
[sections release];
sections = [[NSMutableArray alloc] init];
note that the array does not become again "nil", is instead deallocated and you get an invalid reference, which might (should) generate a crash on dereferencing.
I suggest you to read some articles on reference counted memory management as it might be not obvious if you are new to Objective-C, and often leads to mistake (i.e: autorelease is not magic at all)
best way to avoid all memory leaks here is just simply use #property (nonatomic, retain) NSMutableArray *sections; by using property you can be sure that all men management works will be correctly managed by system. Just don't forget that property retains value when you doing setSections:, so that you need to pass autoreleased object here.
self.sections = [NSMutableArray array];
...
[self.sections addObject:section];
Also to avoid all problem try to make all objects which should live only in this method autorelease. Like this:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSString *responseString = [[[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding] autorelease];
NSDictionary *results = [responseString JSONValue];
NSMutableArray *jSections = [results objectForKey:#"Items"];
self.sections = [NSMutableArray array];
for (NSArray* jSection in jSections) {
Section* section = [[[Section alloc] init] autorelease];
section.Id = [jSection objectForKey:#"Id"];
section.Description = [jSection objectForKey:#"Description"];
section.Image = [jSection objectForKey:#"Image"];
section.Parent = [jSection objectForKey:#"Parent"];
section.ProductCount = [jSection objectForKey:#"ProductCount"];
[self.sections addObject:section];
}
[delegate sectionsLoaded];
[self.view reloadData];
}
And also most of object you trying to release already autoreleased:
all params passed into your method shouldn't be released manually, check I think JSONValue also should returns autoreleased object and anything you getting by enumerating or by call objectForKey: