Having problems with adding objects to NSMutableArray - objective-c

I am having problem with adding objects to NSMutableArray *array.
// Controller.m
#import "Controller.h"
#implementation Controller
- (void)parser:(NSString *)string{
[array addObject:string];
NSLog(#"answerArray(1): %#",[array objectAtIndex:1]);
[array retain];
}
#end
// Controller.h
#import <Foundation/Foundation.h>
#interface Controller : NSObject {
NSMutableArray *array;
}
- (void)parser:(NSString *)string;
#end
NSLog(#"answerArray(1): %#",[array objectAtIndex:1]);
Results: answerArray(1): (null)

First off, you're over-retaining the array.
Second, you didn't provide the code for initializing the array, so I guess it's not allocated and initialized. This will cause the code to message a nil object and thus return nil.
You should create an init method for the Controller object, and allocate a new NSMutableArray object (and retain it).
Also, a proper dealloc to release the array.

NSMutabaleArray starts at index 0

Here is the method I added to Controller class:
- (id)init {
self = [super init];
if(self){
array = [[NSMutableArray alloc] init];
}
return self;
}
- (void)dealloc {
[array release];
[super dealloc];
}

Related

NSMutableArray resetting itself when WindowDidLoad is done

When I pass a NSMutableArray from a controller class to a NSWindowController class using #property and #synthesize I am able to use the objects of the array in the windowDidLoad method.
However, after the method is done and I click a button on the window triggerig an IBAction, the passed value is nil.
Can anyone explain me why this is happening and how I can preserve the NSMutableArray?
Here is the code:
passClass.h
#import <Foundation/Foundation.h>
#class ResultWindowController;
#interface passClass : NSObject {
#private
IBOutlet NSTextField *searchField;
ResultWindowController *resultWindowController;
}
- (IBAction)passIt:(id)sender;
#end
passClass.m
#import "passClass.h"
#import "ResultWindowController.h"
#implementation passClass
- (IBAction)passIt:(id)sender {
NSString *searchString = searchField.stringValue;
NSMutableArray array = [[NSMutableArray alloc]init];
[array addObject:searchString];
[array addObject:searchString];
if(!resultWindowController) {
resultWindowController = [[ResultWindowController alloc] initWithWindowNibName:#"ResultWindow"];
resultWindowController.array =[[NSMutableArray alloc]initWithArray:array copyItems:YES];
[resultWindowController showWindow:self];
}
}
#end
ResultWindowController.h
#import <Cocoa/Cocoa.h>
#interface ResultWindowController : NSWindowController <NSTableViewDataSource> {
IBOutlet NSTableView *resultView;
NSMutableArray *resultList;
//NSMutableArray *array;
}
- (IBAction)returnValue:(id)sender;
#property (nonatomic,strong) NSMutableArray *array;
#end
ResultWindowController.m
#import "Results.h"
#interface ResultWindowController ()
#end
#implementation ResultWindowController
//#synthesize array;
- (id)initWithWindow:(NSWindow *)window
{
self = [super initWithWindow:window];
if (self) {
// Initialization code here.
resultList = [[NSMutableArray alloc] init];
}
return self;
}
- (void)windowDidLoad
{
[super windowDidLoad];
for (NSInteger i = 0; i< [array count];i++)
{
Results *result = [[Results alloc]init];
result.resultName = [self.array objectAtIndex:i];
[resultList addObject:result];
[resultView reloadData];
NSLog (#"self.array: %#", self.array);
// works fine, tableview gets populated, array is correct
}
}
- (NSInteger) numberOfRowsInTableView:(NSTableView *)resultView{
return [resultList count];
}
- (id)tableView:(NSTableView *)resultView objectValueForTableColumn:(NSTableColumn *)resultColumn row:(NSInteger)row{
Results *result = [resultList objectAtIndex:row];
NSString *identifier = [resultColumn identifier];
return [result valueForKey:identifier];
}
- (IBAction)selectedSeries:(id)sender {
NSLog (#"self.array: %#", self.array);
//when I break here the array is nil
}
#end
Here is the NSLog result:
2013-12-26 10:36:49.487 MyProgram[545:303] self.array: (
"test",
"test"
)
2013-12-26 10:37:24.044 MyProgram[545:303] self.array: (null)
Try to remove NSMutableArray *array; from ResultWindowController class declaration and leave only the property declaration for it.
Or you could try initiating the array property in your ResultVWindowsContorller init class and in the - (IBAction)passIt:(id)sender just add objects to array.
I honestly can't see how this works at all unless, in -windowDidLoadNib you are expecting array to be empty.
When you synthesise a property, the default name of the instance variable that is used is prefixed by an underscore. Thus the class in your code has two instance variables, array and _array.
There are several ways to fix this. Here's what I think what you should do is delete the instance variable in your interface definition. Then you'll start getting compilation errors every for each time you use it. Fix them by using the property instead, so for example, the line
result.resultName = [array objectAtIndex:i];
in -windowDidLoadNib becomes
result.resultName = [self.array objectAtIndex:i];

Memory leak after switching to #property declaration?

Why Im having a memory leak here:
.h:
#property (nonatomic, retain) NSDictionary *info;
and then in my .m:
#synthesize info = _info;
and Im having one leak here:
- (id)initWithData:(NSDictionary *)data
{
self = [super init];
if (self) {
self.info = [[NSDictionary alloc] initWithDictionary:data];
}
return self;
}
And another leak here:
-(void)dealloc {
[self.info release];
[super dealloc];
}
Your leak stems from your property declaration and the way you assign it, when you declare a property as "retain" using the setter will retain the var for you, so doing
self.info = [[NSDictionary alloc] initWithDictionary:data];
Retains the var, and since alloc also retain the var you get a +2 retain count, you should either autorelease the object or assign it like
_info = [[NSDictionary alloc] initWithDictionary:data];
also when you release a property do so by setting it to nil
self.info=nil
Your constructor should use
self.info = [NSDictionary dictionaryWithDictionary:data];
Your dealloc should be simplified to
- (void)dealloc {
self.info = nil;
[super dealloc];
}

Mutable array contents are lost between methods

I have this code in my .m file, which is a Cocos 2D CCLayer class. I initialize an array in the init method and then I try to use contents of this array in the nextFrame method. But when the nextFrame method gets called, the contents of the array seem empty. When I try to get the first item, I receive an error message saying:
Program received signal "EXC_BAD_ACCESS"
How can I successfully access the contents of this array in my nextFrame method?
NSMutableArray *cars;
-(id) init {
cars = [NSMutableArray array];
Car *car;
car = [[Car alloc] init];
[cars addObject:car];
self.isTouchEnabled = YES;
}
- (void) nextFrame:(ccTime)dt {
Car *car = [cars objectAtIndex:i]; // Program received signal "EXC_BAD_ACCESS"
}
Car.h
#import <Foundation/Foundation.h>
#import "cocos2d.h";
#interface Car : NSObject {
NSInteger type;
CCSprite *sprite;
}
#property (readwrite, assign) NSInteger type;
#property (retain) CCSprite *sprite;
#end
Car.m
#import "Car.h"
#implementation Car
#synthesize type;
#synthesize sprite;
- (id)init
{
self = [super init];
if (self) {
// Initialization code here.
}
return self;
}
- (void) dealloc {
[sprite release];
[super dealloc];
}
#end
You're assigning the result of [NSMutableArray array] to an instance variable. That is an autoreleased object, which essentially means it doesn't have any owners and thus will feel free to go away after the current runloop iteration*. You need to retain it if you want it to stick around (or just use [[NSMutableArray alloc] init], which returns an object you own).
* Basically. You should see the Cocoa memory mangement guide for more details. It's pretty short but full of essential information.

Why do I crash? Dealloc/release + property/retain weirdness

Code in my controller:
CalcBorderBlocks *calcBB = [[CalcBorderBlocks alloc] init];
NSMutableArray *blockArray = [calcBB calc:341241133];
[calcBB release]; // Releases calcBB.
Code in CalcBorderBlocks.h:
#import <Foundation/Foundation.h>
#interface CalcBorderBlocks : NSObject {
#private
NSMutableArray *blockArray_;
}
#property(nonatomic, retain) NSMutableArray *blockArray;
- (NSMutableArray *)calc:(int)blockID;
#end
Code in CalcBorderBlocks.m:
#import "CalcBorderBlocks.h"
#implementation CalcBorderBlocks
#synthesize blockArray = blockArray_;
- (id)init {
self = [super init];
if (self) {
blockArray_ = [[NSMutableArray alloc] init]; // Retain count should be 1
}
return self;
}
- (NSMutableArray *)calc:(int)blockID {
// Do stuff
return self.blockArray;
}
- (void)dealloc {
[blockArray_ release]; // Normal cleanup, yet crashes! Works fine if I comment out this line.
[super dealloc];
}
#end
If you're doing anything with blockArray after this line:
[calcBB release]; // Releases calcBB.
Then that's the cause of the crash.
You're releasing calcBB which in turn releases blockArray in dealloc.
I suspect you need to retain blockArray, process it as required then release it afterwards.
CalcBorderBlocks *calcBB = [[CalcBorderBlocks alloc] init];
NSMutableArray *blockArray = [[calcBB calc:341241133] retain];
[calcBB release]; // Releases calcBB.
// Process blockArray as needed
[blockArray release];
This:
CalcBorderBlocks *calcBB = [[CalcBorderBlocks alloc] init];
NSMutableArray *blockArray = [calcBB calc:341241133];
[calcBB release]; // Releases calcBB.
usually means that blockArray is retained but also autoreleased. If you want to keep it alive, you'll have to retain it yourself, otherwise it will be released by the autorelease pool after a while.
Post the backtrace of the crash. More likely than not, it is because you overreleased something in the array (or the array itself somewhere else.

Why does this crash?

I made a class. This is the h file.
// MyClass.h
#import <Foundation/Foundation.h>
#interface MyClass : NSObject <NSCoding> {
NSString *string1;
NSString *string2;
}
#property (nonatomic, retain) NSString *string1;
#property (nonatomic, retain) NSString *string2;
#end
This is the m file.
// MyClass.m
#import "MyClass.h"
#implementation MyClass
#synthesize string1, string2;
- (void)encodeWithCoder:(NSCoder *)coder;
{
if (self = [super init]){
[coder encodeObject:string1 forKey:#"string1"];
[coder encodeObject:string2 forKey:#"string2"];
}
}
- (id)initWithCoder:(NSCoder *)coder;
{
self = [[MyClass alloc] init];
if (self != nil)
{
string1 = [coder decodeObjectForKey:#"string1"];
string2 = [coder decodeObjectForKey:#"string2"];
}
return self;
}
- (void)viewDidUnload {
self.string1 = nil;
self.string2 = nil;
}
- (void)dealloc {
[super dealloc];
[string1 release];
[string2 release];
}
#end
I created an array of these objects like this:
MyClass *object1 = [[MyClass alloc] init];
object1.string1 = #"object1 string1";
object1.string2 = #"string1 string2";
MyClass *object2 = [[MyClass alloc] init];
object2.string1 = #"object2 string1";
object2.string2 = #"object2 string2";
theArray = [[NSMutableArray alloc] initWithObjects:object1, object2, nil];
Then I saved the array like this:
[[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:theArray] forKey:#"savedArray"];
Then I loaded the array from disk like this.
NSUserDefaults *currentDefaults = [NSUserDefaults standardUserDefaults];
NSData *dataRepresentingSavedArray = [currentDefaults objectForKey:#"savedArray"];
if (dataRepresentingSavedArray != nil)
{
NSArray *oldSavedArray = [NSKeyedUnarchiver unarchiveObjectWithData:dataRepresentingSavedArray];
if (oldSavedArray != nil)
{
theArray = [[NSMutableArray alloc] initWithArray:oldSavedArray];
}
else {
theArray = [[NSMutableArray alloc] init];
}
}
The program crashes when it gets to this line in - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
cell.textLabel.text = [[theArray objectAtIndex:indexPath.row] string1];
Why does it crash there? It doesn't crash if I don't load the array from NSUserDefaults. However, I don't see anything I did wrong with saving or loading the array.
Edit:
I can also make it crash with this line of code:
NSLog(#"%#", [[theArray objectAtIndex:0] string1]) ;
In addition to cobbal's excellent points, your initWithCoder: method isn't using setters and therefore the strings aren't being retained. When you try to access string1 at your crash line, that string has probably already been released. Do this in initWithCoder: instead:
self.string1 = [coder decodeObjectForKey:#"string1"];
self.string2 = [coder decodeObjectForKey:#"string2"];
To address cobbal's first point, don't do any init at all in encodeWithCoder:. Just encode your object. Check out Apple's Archives and Serializations Programming Guide for Cocoa for more details about encoding and decoding objects.
A few things jump out at me
you're calling init in encodeWithCoder:. since you're not initializing anything here you should not be changing self
you're calling alloc in initWithCoder:. Once you're in an init method you shouldn't have to call alloc, just call self = [super init].
you have a viewDidUnload method. Even if this were called in an NSObject subclass, you probably don't want to get rid of your data when the view is unloaded.
you're calling [super dealloc] at the beginning of your dealloc method. It should go at the end.
I didn't read all of your code, so I am not sure if this is the problem, but in dealloc you should call [super dealoc] only after releasing the instance variables.
If it crashes due to being out of bounds, check that your UITableViewController correctly implements
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
and
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
to reflect the NSArray you're using as data source.