Objective C - NSMutableSet not working properly - objective-c

I have an NSMutableSet that I am trying to add labels to. After each label added, I check the set's count and it comes back as 0. Any help will be appreciated
In my .h file:
#interface MainMenu : CCLayerColor {
NSMutableSet* letters;
}
In my .m file:
-(void)initiateLetters{
//Grab the window size
CGSize size = [[CCDirector sharedDirector] winSize];
int i;
for(i=0;i<100;i++){
CCLabelTTF *label;
int r = rand() % 35 + 60;
char c = (char) r;
label = [CCLabelTTF labelWithString:[NSString stringWithFormat:#"%c",c] fontName:#"Courier" fontSize:30];
[label setColor:ccc3(0,0,0)];
[label setOpacity:255/2];
//Generate a random number for the x variable, y will be 0
int x = (arc4random() % (int)size.width);
int y = size.height+(arc4random() % 50)+25;
[label setPosition:ccp(x,y)];
[self addChild:label];
[letters addObject:label];
//Here's what's printing 0:
printf("%lu",[letters count]);
}
}

You have to instantiate the set before you can add things to it. You can do that in an overridden implementation of init:
- (id)init
{
self = [super init];
if (self) {
letters = [[NSMutableSet alloc] init];
}
return self;
}
…or at the beginning of your initiateLetters method:
- (void)initiateLetters
{
letters = [[NSMutableSet alloc] init];
...
Instead, the code you posted is simply sending addObject: to nil, which does nothing.

the array is probably nil. Did you create it in the class init method ?
something like
-(id) init {
if (self = [super init]){
// ...
letters = [[NSMutableSet set] retain]; // not using ARC
// ...
}
return self;
}
and of course
-(void) dealloc {
// ...
[letters release]; // not using ARC
[super dealloc];
}

Related

How to add a CCsprite to layer from array

Hi guys I really need some help, I have been stuck in this part of my game for over a week now and I can't seem to get past this issue, So have look at my code below,
#import "HelloWorldLayer.h"
#import "AppDelegate.h"
#implementation HelloWorldLayer
+(CCScene *) scene
{
// 'scene' is an autorelease object.
CCScene *scene = [CCScene node];
// 'layer' is an autorelease object.
HelloWorldLayer *layer = [HelloWorldLayer node];
// add layer as a child to scene
[scene addChild: layer];
// return the scene
return scene;
}
-(id) init
{
// always call "super" init
// Apple recommends to re-assign "self" with the "super's" return value
if( (self=[super init]) ) {
moles = [[NSMutableArray alloc] init];
winSize = [[CCDirector sharedDirector]winSize];
CCSprite *mole1 = [CCSprite spriteWithFile:#"lightsabericonblue.png"];
[self starCreateCurrentLevel:mole1];
}
return self;
}
-(void)starCreateCurrentLevel:(CCSprite *)mole1{
starCountCurrentLevel = 10;
for (int i = 0; i < starCountCurrentLevel;) {
[moles addObject:mole1];
starCountCurrentLevel--;
}
[self schedule:#selector(tryPopMoles:) interval:1];
}
- (void)tryPopMoles:(ccTime)dt {
if(moles.count != 0){
for (CCSprite *mole in moles) {
if (arc4random() % moles.count == 0) {
if (mole.numberOfRunningActions == 0) {
[self popMole:mole];
}
}
}
}else if(moles.count == 0){
NSLog(#"No More Moles To Spawn");
[self unschedule:#selector(tryPopMoles:)];
}
}
- (void) popMole:(CCSprite *)mole {
mole.position = ccp(150, 150);
[self addChild:mole];
}
- (void) dealloc
{
[moles release];
moles = nil;
[super dealloc];
}
#end
When I run this code i get the following error, * Assertion failure in -[HelloWorldLayer addChild:z:tag:], /Users/....../libs/cocos2d/CCNode.m:335.
I when i add the child in the init method its fine but I don't want to do that, I want to be able to call the try pop mole which will then call the pop mole based on if there is anymore sprites left in the array, I have a feeling I am missing something or doing something wrong.
UPDATE -
#import "HelloWorldLayer.h"
#import "AppDelegate.h"
#pragma mark - HelloWorldLayer
CGSize winSize;
int enemyX;
int enemyY;
int randomAngleY;
int randomAngleX;
int winSizeX;
int winSizeY;
int minDuration = 1;
int maxDuration = 4.0;
int rangeDuration;
int actualDuration;
int starCountCurrentLevel;
int test = 0;
#implementation HelloWorldLayer
+(CCScene *) scene
{
CCScene *scene = [CCScene node];
HelloWorldLayer *layer = [HelloWorldLayer node];
[scene addChild: layer];
return scene;
}
-(id) init
{
if( (self=[super init]) ) {
moles = [[NSMutableArray alloc] init];
winSize = [[CCDirector sharedDirector]winSize];
[self starCreateCurrentLevel];
}
return self;
}
-(void)starCreateCurrentLevel{
starCountCurrentLevel = 10;
for (int i = 0; i < starCountCurrentLevel;) {
[moles addObject:[CCSprite spriteWithFile:#"lightsabericonblue.png"]];
starCountCurrentLevel--;
}
[self schedule:#selector(tryPopMoles:) interval:3];
}
- (void)tryPopMoles:(ccTime)dt {
NSMutableArray *tempArray = [NSMutableArray arrayWithArray:moles];
for (int randomIndex = tempArray.count -1; randomIndex < tempArray.count; randomIndex--) {
CCSprite * sprite = (CCSprite *)[tempArray objectAtIndex:randomIndex];
//CCSprite *sprite = [tempArray objectAtIndex:randomIndex];
[self popMole:sprite];
NSLog(#"Enemy Added");
[tempArray removeObject:sprite];
}
if([tempArray count] == 0){
NSLog(#"No More Moles To Spawn");
[self unschedule:#selector(tryPopMoles:)];
}
}
- (void) popMole:(CCSprite *)sprite {
winSizeX = winSize.width - sprite.contentSize.width + 25;
winSizeY = winSize.height - 25 - sprite.contentSize.height + 17;
randomAngleX = arc4random() % winSizeX;
randomAngleY = arc4random() % winSizeY;
enemyX = arc4random() % winSizeX ;
enemyY = arc4random() % winSizeY;
rangeDuration = maxDuration - minDuration;
actualDuration = (arc4random() % rangeDuration) + minDuration;
sprite.position = ccp(enemyX, enemyY);
[self addChild:sprite];
}
- (void) dealloc
{
[moles release];
moles = nil;
[super dealloc];
}
#end
You're only creating the sprite once, but trying to add it several times. (Remember, these are pointers to objects, so you're always referring to exactly the same sprite.) If you want 10 versions of the same sprite (at different positions, scales, speeds, whatever), you'll need to create the sprite (via the creator method) 10 times. You can do a copy on the original one, or just create it on the fly:
-(void)starCreateCurrentLevel:(CCSprite *)mole1{
starCountCurrentLevel = 10;
for (int i = 0; i < starCountCurrentLevel;) {
//[moles addObject:mole1];
// ^^ You're adding the same sprite (meaning same pointer reference) again and again. Try this instead:
[moles addObject:[CCSprite spriteWithFile:#"lightsabericonblue.png"]];
starCountCurrentLevel--;
}
Of course, now you don't need to pass mole1 into your method. You may (depending on your need) consider passing in a spriteFrameName or something.

The animation just run one time?

The problems is the animation just run one time then cannot repeat again. Do I need to add one more NSTimer in somewhere ?
Anything I missing ? Looking for help and advice. Thanks a lot !
And here is the code.
First, in ViewController.h & ViewController.m
#interface ViewController : UIViewController {
GameView* gameView;
}
- (void)viewDidLoad
{
[super viewDidLoad];
if(gameView == nil) {
gameView = [[GameView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
gameView.backgroundColor = [UIColor clearColor];
}
[self.view addSubview:gameView];
[[AppEngine sharedInstance] addSnow:CGPointMake((random() % 320),(random() % -20))];
[[AppEngine sharedInstance] addSnow:CGPointMake((random() % 320),(random() % -20))];
[[AppEngine sharedInstance] addSnow:CGPointMake((random() % 320),(random() % -20))];
[[AppEngine sharedInstance] addSnow:CGPointMake((random() % 320),(random() % -20))];
[[AppEngine sharedInstance] addSnow:CGPointMake((random() % 320),(random() % -20))];
}
In the GameView.h & .m
#interface GameView : UIView <UIAccelerometerDelegate>{
CADisplayLink* displayLink;
}
-(void) timeStep;
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
displayLink = [CADisplayLink displayLinkWithTarget:self selector:#selector(timeStep)];
[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}
return self;
}
-(void) timeStep {
[[AppEngine sharedInstance] timeStep];
[self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect {
[[UIImage imageNamed:#"Christmas.jpg"] drawInRect:CGRectMake(0,0,320,480)]; // set the background image
CGContextRef context = UIGraphicsGetCurrentContext();
for(MySnow* snowObject in [AppEngine sharedInstance].snowObjectArray)
{
CGContextSaveGState(context);
CGContextTranslateCTM(context, snowObject.x, snowObject.y);
NSString *imagePath = [NSString stringWithFormat:#"snowflake0%d.png",snowObject.type];
[[UIImage imageNamed: imagePath] drawInRect:CGRectMake(-16,-16,32,32)];
CGContextRestoreGState(context);
}
}
Third, in the snow.h & m
#interface MySnow : NSObject
{
float x,y;
float vx, vy;
float rotSpeed;
float rotation;
int type;
}
#property (nonatomic) float x,y;
#property (nonatomic) float vx, vy, rotSpeed,rotation;
#property (nonatomic) int type;
-(id) initWithStartPoint:(CGPoint) startPoint withType:(int) type;
-(void) timeStep;
#implementation MySnow
#synthesize x,y,vx,vy,rotation,rotSpeed,type;
-(id) initWithStartPoint:(CGPoint) startPoint withType:(int) _type {
self = [super init];
if(self) {
x = startPoint.x;
y = startPoint.y;
vx = RANDOM_FLOAT() * 1 + 0.1;
vy = RANDOM_FLOAT() * 2 + 0.1;
type = _type;
}
return self;
}
-(void) timeStep {
y += vy;
}
Finally, in AppEngine.h & m
#interface AppEngine : NSObject {
NSMutableArray* snowObjectArray;
float ax, ay;
}
#property (readonly) NSMutableArray* snowObjectArray;
#property (nonatomic) float ax,ay;
+(AppEngine*) sharedInstance;
+(void) destoryInstance;
-(void) timeStep;
-(void) addSnow:(CGPoint) point;
static AppEngine* _sharedEngine;
#implementation AppEngine
#synthesize snowObjectArray;
#synthesize ax,ay;
+(AppEngine*) sharedInstance {
if(_sharedEngine == nil)
_sharedEngine = [[AppEngine alloc] init];
return _sharedEngine;
}
+(void) destoryInstance {
if(_sharedEngine != nil) {
_sharedEngine = nil;
}
}
-(id) init {
self = [super init];
if(self) {
snowObjectArray = [[NSMutableArray alloc] init];
}
return self;
}
-(void) addSnow:(CGPoint) point {
int type = (arc4random() % 9) + 1; // random snow image 01 to 09
MySnow* snowObject = [[MySnow alloc] initWithStartPoint:point withType:type];
[snowObjectArray addObject:snowObject];
}
-(void) timeStep {
NSMutableArray* removeArray = [NSMutableArray array];
for(MySnow* item in snowObjectArray) {
[item timeStep];
if(item.y > 400 || item.y < -100)
[removeArray addObject:item];
}
[snowObjectArray removeObjectsInArray:removeArray];
[removeArray removeAllObjects];
}
Is this your code? Can you explain how it starts the animation?
It looks to me like the AppEngine's timeStep method has code that specifically deletes each item in the snowObjectsArray once it reaches some boundary. However, if this is your code, why don't you understand what it does?
EDIT: OK, so this is from a lecture.
If you want the animation to continue, here's what I would do:
Take the last block of code from your viewDidLoad method (the code that creates and adds snow objects) and put it in a separate method. Make viewDidLoad call that method. Let's call the method makeItSnow.
Then, at the end of your AppEngine timeStep method, if the object count in snowObjectArray drops to 0, call makeItSnow.
That approach would make a set of snowflakes start at the top, fall down and disappear, and then another group of snowflakes start. If you want a continuous stream of snowflakes to fall, then change the timeStep method to count the number of snowflake objects it deletes, and at the end of the method add that many snowflakes back to the array. That would cause your program to add a new snowflake as each one disappears.
Yet another approach would be to add a repeating timer to AppEngine, and make that timer create another snowflake. That would keep adding snowflakes on a regular interval.

Casting in Objective-C does not work as expected

I am new to programming with Objective-C and Stackoverflow, and I need some help.
I'm trying to get an object from a NSMutableArray and check one of its internal properties. I figured the best way to do this is by doing the following cast:
GenericRoom *room = (GenericRoom*)[myRooms objectAtIndex: currentIndex + side];
if (room.myType == EMPTY) {
return YES;
}
The problem is that when I create a class of type GenericRoom, your constructor already defines myType as EMPTY. When I insert the instances in NSMutrableArray, I changed to myType TAVERN this way:
NSMutableArray *myRooms = [[NSMutableArray alloc] initWithCapacity:15];
for (int i = 0: i <15: i + +) {
    GenericRoom tmpRoom * = [[GenericRoom alloc] initWithType: TAVERN];
    myRooms insertObject: tmpRoom atIndex i];
}
But when I do the cast that quote up there, it simply creates a new instance of the object GenericRoom, instead of copying the object inside NSMutableArray, making its result is always YES, my failing vereficação.
Is there any better way to solve this problem?
Thank you all.
EDIT: The complete code
GenericRoom.h
#import <Foundation/Foundation.h>
#import "cocos2d.h"
enum Rooms {
EMPTY, TAVERN, WARRIORGUILD, MAGEGUILD
}roomsType;
#interface GenericRoom : CCLayer {
CCSprite *mySprite;
enum Rooms myType;
}
#property (nonatomic, retain) CCSprite *mySprite;
#property enum Rooms myType;
#property int test;
- (id)initWithSprite: (NSString *)file;
- (id)initWithType: (enum Rooms)roomType;
#end
GenericRoom.m
#import "GenericRoom.h"
#implementation GenericRoom
#synthesize mySprite, myType, test;
-(id)init {
if (self = [super init]) {
}
return self;
}
-(id)initWithType: (enum Rooms) roomType {
if (self = [super init]) {
myType = roomType;
}
return self;
}
-(id)initWithSprite: (NSString *)file {
if (self = [super init]) {
mySprite = [CCSprite spriteWithFile:file];
[self addChild: mySprite];
}
return self;
}
#end
RoomManager.h
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#import "GenericRoom.h"
#import "RoomTavern.h"
#import "RoomEmpty.h"
enum Sides {
LEFT, RIGHT, UP, DOWN
}theSides;
#interface RoomManager : CCLayer {
CGSize size;
NSMutableArray *myRooms;
}
- (void) CreateRoom: (enum Rooms)roomType;
#end
RoomManager.m
#implementation RoomManager
-(id)init {
if (self = [super init]) {
size = [[CCDirector sharedDirector] winSize];
myRooms = [[NSMutableArray alloc] initWithCapacity:15];
for (int i = 0; i < 15; i++) {
GenericRoom *tmpRoom = [[GenericRoom alloc] initWithType:TAVERN];
tmpRoom.test = 10;
[myRooms insertObject:tmpRoom atIndex:i];
}
[self CreateRoom:TAVERN];
}
return self;
}
- (void) CreateRoom: (enum Rooms)roomType {
switch (roomType) {
case TAVERN:
{
//Create the Tavern Main Room
RoomTavern *tmpRoom = [[RoomTavern alloc] initWithSprite:#"room-hd.png"];
tmpRoom.mySprite.position = ccp(size.width/2,size.height/2);
[self addChild:tmpRoom];
[myRooms removeObjectAtIndex:8];
[myRooms insertObject:tmpRoom atIndex:8];
if ([self CheckAdjacentRooms:8 andSide:LEFT]) {
RoomEmpty *tmpEmptyRoom = [[RoomEmpty alloc] initWithSprite:#"roomToBuild-hd.png"];
tmpEmptyRoom.mySprite.position = ccp(tmpRoom.mySprite.position.x - tmpRoom.mySprite.contentSize.width, tmpRoom.mySprite.position.y);
[self addChild:tmpEmptyRoom];
[myRooms insertObject:tmpEmptyRoom atIndex:7];
}
break;
}
default:
break;
}
}
- (BOOL) CheckAdjacentRooms: (int)currentIndex andSide:(enum Sides)side {
int leftRightSide = 0;
if(side == LEFT)
leftRightSide = -1;
else if (side == RIGHT)
leftRightSide = 1;
GenericRoom *roomTmp = (GenericRoom *)[myRooms objectAtIndex:currentIndex + side];
if (roomTmp.myType == EMPTY) {
return YES;
}
else
return NO;
}
#end
To enhance #Dan F answer. Read this ...
http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/objectivec/Chapters/ocObjectsClasses.html#//apple_ref/doc/uid/TP30001163-CH11-SW7
... what's nil messaging. Your locally declared myRooms variable hides your myRooms property (= instance variable). In other words, myRooms is nil. And what happens ...
GenericRoom *room = (GenericRoom*)[myRooms objectAtIndex: currentIndex + side];
Because of nil messaging rules, [myRooms objectAtIndex:...] returns nil, thus your room is set to nil.
if (room.myType == EMPTY) {
return YES;
}
And room.myType sends message myType to room object. And because room is nil, return value is 0 - enums does contain integer scalar values - this is the reason why it returns 0. And I assume that EMPTY is first element in your enum = has value 0. And 0 == 0 => returns YES even when your myRooms instance variable is nil.
If your code above is how it appears in your actual project, then the problem is you are re-declaring your myRooms object. When you write this line:
NSMutableArray *myRooms = [[NSMutableArray alloc] initWithCapacity:15];
you are creating a new locally-scoped object named myRooms that is lost when you exit the current scope (method, block, etc.)
What you need to do to fix this is simply remove the NSMutableArray * at the beginning of the line, and it will assign the newly allocated array to your property. Like so:
myRooms = [[NSMutableArray alloc] initWithCapacity:15];
Your initialiser seems to have some flaws, that might cause your issues.
// NOTE: `Rooms` instead of `enum Rooms`
- (id)initWithType:(Rooms)roomType
{
if (self = [super init])
{
// NOTE: accessor is used, otherwise the value is cleared when out of scope
self.myType = roomType;
}
return self;
}

Exc_Bad_Access on main function and unable to pass instance variables through classes

Updated post
Now, I have a EXC_BAD_ACCESS on the main 2 times out of 7 and I don't know why the heightOfPumpView result is 0 from the pumpCustomView class when the result of pumpViewHeight is 607.
PumpViewController.m
#import "PumpViewController.h"
#import "PumpModel.h"
#import "PumpCustomView.h"
#implementation PumpViewController
#synthesize labels;
#synthesize heightOfPumpView;
- (id)init
{
if (self = [super init])
{
labels = [[PumpModel alloc]init];
PumpCustomView* pumpView = [PumpCustomView alloc];
heightOfPumpView = [pumpView pumpViewHeight];
[labels pumpCreateLabel:heightOfPumpView];
labelsArray = [[NSMutableArray alloc]initWithArray:[labels labelsGroup]];
[labels release];
if (labelsArray!=nil)
{
[pumpView addSubview:[labelsArray objectAtIndex:2]];
}
[labelsArray release];
[pumpView release];
}
return self;
}
-(void) dealloc
{
[super dealloc];
}
#end
PumpModel.m
#import "PumpModel.h"
#import "PumpViewController.h"
#import "PumpCustomView.h"
#implementation PumpModel
#synthesize labelsGroup;
-(id)init
{
self = [super init];
return self;
}
-(void)pumpCreateLabel:(float)pumpViewHeight
{
theNumberOfPump = 8;
PumpViewController* pumpViewControllerAlloc = [PumpViewController alloc];
labelsGroup = [[NSMutableArray alloc]init];
for (int i = 0;i < theNumberOfPump; i++)
{
int pumpViewHeight = [pumpViewControllerAlloc heightOfPumpView];
int pumpViewWidthA = 259;
int resultHeight = pumpViewHeight/theNumberOfPump;
CGFloat resultWidth = pumpViewWidthA/2;
positionChart[i] = resultHeight * i;
newLabel[i] = [[NSTextField alloc] init] ;
[newLabel[i] setIntValue:i];
newLabel[i].frame = CGRectMake(resultWidth, positionChart[i], 300, 100);
newLabel[i].font= [NSFont fontWithName:#"Arial" size:12];
newLabel[i].textColor= [NSColor blackColor];
newLabel[i].backgroundColor= [NSColor whiteColor];
[labelsGroup addObject:newLabel[i]];
[newLabel[i] release];
NSLog(#"%# %d",[[labelsGroup objectAtIndex:i] stringValue],positionChart[i]);
}
[pumpViewControllerAlloc release];
}
-(void) dealloc
{
[labelsGroup release];
[super dealloc];
}
You shouldn't send messages to the object before [super init], e.g.:
- (id)init
{
if (self = [super init])
{
[self setNumberOfPump:8];
}
return self;
}
This is also true for:
-(id)initWithNumberOfPump:(int)numberOfPump
{
if (self = [super init]) {
theNumberOfPump = numberOfPump;
[self pumpCreateLabel];
}
return self ;
}
If you have a crash, post the backtrace of the crash.
Looking at your setNumberOfPump: method, it seems quite wrong.
labels is allocated, then released, likely leaving the instance variable as a dangling reference that'll crash later
labelsArray is leaked
your dealloc doesn't release any memory
You should try running Build and Analyze on your code, fixing any errors. The above issues combined with comments regarding the init patterns indicates that you should likely review the Objective-C documentation to gain a better understanding of both initialization and memory management patterns.

Objective C - Create a multi-dimensional array with the dimensions specified at initialisation

I am trying to create a class where the width and height of a 2 dimensional array can be dynamically created at the point of initialisation with init parameters.
I have been looking through the web for hours and cannot find a way.
Using a standard C syntax [][] does not allow for a variable to be used to declare the array.
The mutable arrays within Objective C, in all examples I have seen, require the objects to be hard coded at the time of creation.
Is there a way of creating a 2 dimensional array within an object with parameters to define the sizes at the point of creation?
Hoping someone can tell me what I am missing...
You can do this quite easily by writing a category on NSMutableArray:
#interface NSMutableArray (MultidimensionalAdditions)
+ (NSMutableArray *) arrayOfWidth:(NSInteger) width andHeight:(NSInteger) height;
- (id) initWithWidth:(NSInteger) width andHeight:(NSInteger) height;
#end
#implementation NSMutableArray (MultidimensionalAdditions)
+ (NSMutableArray *) arrayOfWidth:(NSInteger) width andHeight:(NSInteger) height {
return [[[self alloc] initWithWidth:width andHeight:height] autorelease];
}
- (id) initWithWidth:(NSInteger) width andHeight:(NSInteger) height {
if((self = [self initWithCapacity:height])) {
for(int i = 0; i < height; i++) {
NSMutableArray *inner = [[NSMutableArray alloc] initWithCapacity:width];
for(int j = 0; j < width; j++)
[inner addObject:[NSNull null]];
[self addObject:inner];
[inner release];
}
}
return self;
}
#end
Usage:
NSMutableArray *dynamic_md_array = [NSMutableArray arrayOfWidth:2 andHeight:2];
Or:
NSMutableArray *dynamic_md_array = [[NSMutableArray alloc] initWithWidth:2 andHeight:2];
Here is another pure Objective C Version
#import foundation.h
#interface ZTwoDimensionalArray : NSObject{
#package
NSMutableArray* _array;
int _rows, _columns;
}
-(id) initWIthRows:(int)numberOfRows andColumns:(int) numberOfColumns;
-(id) getObjectAtRow:(int) row andColumn:(int)column;
-(void) setObject:(id) anObject atRow:(int) row andColumn:(int)column;
#end
#import "ZTwoDimensionalArray.h"
#implementation ZTwoDimensionalArray
-(id) initWIthRows:(int)numberOfRows andColumns:(int) numberOfColumns{
if (self = [super init]) {
_array = [NSMutableArray initWithCapacity:numberOfRows*numberOfColumns];
_rows = numberOfRows;
_columns = numberOfColumns;
}
return self;
}
-(id) getObjectAtRow:(int) row andColumn:(int)column{
return [_array objectAtIndex: row*_rows + column];
}
-(void) setObject:(id) anObject atRow:(int) row andColumn:(int)column{
[_array insertObject:anObject atIndex:row*_rows + column];
}
-(void) dealloc{
[_array release];
}
#end
Here's another way. Of course this is just for int but the code could easily be altered for other datatypes.
AOMatrix.h:
#import <Cocoa/Cocoa.h>
#interface AOMatrix : NSObject {
#private
int* matrix_;
uint columnCount_;
uint rowCount_;
}
- (id)initWithRows:(uint)rowCount Columns:(uint)columnCount;
- (uint)rowCount;
- (uint)columnCount;
- (int)valueAtRow:(uint)rowIndex Column:(uint)columnIndex;
- (void)setValue:(int)value atRow:(uint)rowIndex Column:(uint)columnIndex;
#end
AOMatrix.m
#import "AOMatrix.h"
#define INITIAL_MATRIX_VALUE 0
#define DEFAULT_ROW_COUNT 4
#define DEFAULT_COLUMN_COUNT 4
/****************************************************************************
* BIG NOTE:
* Access values in the matrix_ by matrix_[rowIndex*columnCount+columnIndex]
****************************************************************************/
#implementation AOMatrix
- (id)init {
return [self initWithRows:DEFAULT_ROW_COUNT Columns:DEFAULT_COLUMN_COUNT];
}
- (id)initWithRows:(uint)initRowCount Columns:(uint)initColumnCount {
self = [super init];
if(self) {
rowCount_ = initRowCount;
columnCount_ = initColumnCount;
matrix_ = malloc(sizeof(int)*rowCount_*columnCount_);
uint i;
for(i = 0; i < rowCount_*columnCount_; ++i) {
matrix_[i] = INITIAL_MATRIX_VALUE;
}
// NSLog(#"matrix_ is %ux%u", rowCount_, columnCount_);
// NSLog(#"matrix_[0] is at %p", &(matrix_[0]));
// NSLog(#"matrix_[%u] is at %p", i-1, &(matrix_[i-1]));
}
return self;
}
- (void)dealloc {
free(matrix_);
[super dealloc];
}
- (uint)rowCount {
return rowCount_;
}
- (uint)columnCount {
return columnCount_;
}
- (int)valueAtRow:(uint)rowIndex Column:(uint)columnIndex {
// NSLog(#"matrix_[%u](%u,%u) is at %p with value %d", rowIndex*columnCount_+columnIndex, rowIndex, columnIndex, &(matrix_[rowIndex*columnCount_+columnIndex]), matrix_[rowIndex*columnCount+columnIndex]);
return matrix_[rowIndex*columnCount_+columnIndex];
}
- (void)setValue:(int)value atRow:(uint)rowIndex Column:(uint)columnIndex {
matrix_[rowIndex*columnCount_+columnIndex] = value;
}
#end