Mutable array contents are lost between methods - objective-c

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.

Related

Objective-c : cannot init a class object

I am getting an issue cannot init a class object even after adding lines to the constructor such as
self = [super init];
or
self = [[super init] alloc];
And I am not sure what to do.
This is the specific error:
file:///%3Cunknown%3E: test failure: -[LinkedListTest testAdd] failed: *** +[NList<0x8e14> init]: cannot init a class object.
.m
#interface NList()
#property (weak, nonatomic, readwrite) NSObject *head;
#property (nonatomic,readwrite) NSInteger *size;
#end
#implementation NList
#synthesize size = _size;
- (id) init:(NSInteger *)size {
//is this even necessary? I don't want object methods.. or do I ?
if (self){
_head = nil;
_size = size;
}
return self;
}
.h
#interface NList : NSObject
#property (nonatomic,readonly) NSInteger *size;
#property (weak, readonly, nonatomic) NSObject *head;
- (void)add:(NSObject *)node;
#end
test class
- (void)testAdd
{
NList *testList = [[NList init] alloc];
// Card *testCardOne = [[Card init] alloc];
// [testList add:(testCardOne)];
XCTAssertNotNil(testList.head);
}
I have tried adding the line
self = [[super init] alloc];
to the constructor to no avail.
No visible interfacce for nlist declares
or self = [super init]
complains cannot init a class object!
EDIT
I realized that it is not asking me for the size! the constructor requires a size parameter...how do I do this! Ahh [looks up docs]
A few things.
You need a default constructor
- (id)init {
self = [super init];
if (self) {
self.head = nil;
}
return self;
}
Now that you have a default constructor (that calls the superclasses constructor), you need a more specific one for your purposes.
- (id)initWithSize:(int)size {
self = [self init]; // sets head, calls super constructor.
if (self) {
self.size = size;
}
return self;
}
Edit: Note, the last one had to be in your .h file so it is visible.
And also, when instantiating this class, call
NList *list = [[NList alloc] initWithSize:mySize];
You're a little backwards.
How about:
NList *testList = [[NList alloc] init:SIZE];
where size is the SIZE init you want to use.
Alloc comes before init when you're instantiating Objective-C objects.

Adding an object to Mutable array is not possible

I am trying add a Song* object to a Mutable array and I am stumped as the count of the array is not increasing in spite of adding the object.
Song.h
#import <Foundation/Foundation.h>
#interface Song : NSObject
#property(copy, nonatomic) NSString *title, *album, *artist;
#property(copy, nonatomic) NSNumber *playTime;
#end
Song.m
#import "Song.h"
#implementation Song
#end
Playlist.h
#import <Foundation/Foundation.h>
#class Song;
#interface Playlist : NSObject
#property(copy, nonatomic) NSMutableArray *playListArray;
-(void) addSong: (Song *) tempSongToBeAdded;
-(void) removeSong: (Song *) tempSongToBeremoved;
-(void) listOfSongs;
-(NSUInteger) entries;
#end
Playlist.m
#import "Playlist.h"
#import "Song.h"
#implementation Playlist
-(void) addSong: (Song *) tempSongToBeAdded{
NSLog(#"%s song is being added.", [tempSongToBeAdded.title UTF8String]);
[self.playListArray addObject:tempSongToBeAdded];
}
-(void) removeSong: (Song *) tempSongToBeremoved{
[self.playListArray removeObject:tempSongToBeremoved];
}
-(NSUInteger) entries{
return [self.playListArray count];
}
-(void) listOfSongs{
NSLog(#"Hi");
for (Song *tempSong in self.playListArray) {
NSLog(#"title: %s", [tempSong.title UTF8String]);
}
}
#end
Main.m
#import <Foundation/Foundation.h>
#import "Song.h"
#import "Playlist.h"
int main(int argc, const char * argv[])
{
#autoreleasepool {
Song *song1 = [[Song alloc] init];
song1.title = #"Manasa";
song1.album = #"Ye Maya Chesava";
song1.artist = #"A. R. Rahman";
song1.playTime = [NSNumber numberWithDouble:4.56];
Playlist *playlist1 = [[Playlist alloc] init];
[playlist1 addSong:song1];
NSLog(#"The total number of songs are %lu",[playlist1 entries]);
[playlist1 listOfSongs];
}
return 0;
}
I am getting the entries in the playlist as 0 and and the list of songs as empty. I am not getting any compile errors and I have no idea why the objects are not getting added to the array.
Your variable playListArray is never initialized and is always nil. You need to initialize it using:
playListArray = [[NSMutableArray] alloc] init];
You can add an init method in your Playlist class where you initialize this object.
- (id)init
{
self = [super init];
if (self)
{
playListArray = [[NSMutableArray] alloc] init];
}
return self;
}
EDIT:
The problem seems to be how you declared the property
#property(copy, nonatomic) NSMutableArray *playListArray;
It is declared as copy, that means that even when you do playListArray = [[NSMutableArray] alloc] init], your variable playListArray gets a copy of the initialized array, but the copy protocol is inherited from NSArray, not from NSMutableArray, so you get an immutable array. You can check this in the NSMutableArray documentation. You need to change copy for retain (you're not using ARC, right?).
In fact I see that you're using copy for most of your properties, if there's no particular reason for this, I would change them to retain.

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];

Having problems with adding objects to NSMutableArray

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];
}

Objective C one class not seeing the other

I have these two classes MobRec & MobDef and I want to reference an array pointer of (MobDef) *mobInfo from MobRec. #import the mobdefs.h file in MobRec.h or .m but no luck any ideas?
MobRec.h
// Basic class unit
#interface MobRec : NSObject {
NSString *mName;
int speed;
}
#end
MobDef.h
// Master Class holding an array of units
#interface MobDef : NSObject {
NSMutableArray *mobInfo;
}
#property(retain) NSMutableArray *mobInfo;
#end
MobDef.m
#synthesize MobInfo;
- (id)init { // to add a new node and initialize it
mobInfo = [[NSMutableArray alloc] init];
MobRec *aNewMobRec = [[MobRec alloc] init];
[mobInfo addObject:aNewMobRec];
[aNewMobRec release];
}
The problem is that individual files have no knowledge of other files in your project, since Objective-C is a derivative of C. You need to #import the header files of any other classes that you need to use:
// ModDef.m
#import "MobDef.h"
#import "ModRec.h"
#implementation MobDef
#synthesize mobInfo; // case matters here
- (id)init
{
mobInfo = [[NSMutableArray alloc] init];
MobRec* aNewMobRec = [[MobRec alloc] init];
[mobInfo addObject:aNewMobRec];
[aNewMobRec release];
}
#end
Well, your #synthesize doesn't match #property declaration - you're declaring properties for mobInfo but generating synthesized accessors for MobInfo.
Of are you getting some other error?