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

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

Related

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

NSTableView add increasing number in row

I'm trying to make NSTable view app with adding rows with two columns x and y. I want x column to be constant string but y column I want increase the initial number by 1 every time I press button add.
Here is my TableController implementation code
#implementation TableViewController
-(id)init {
self = [super init];
if (self) {
list = [[NSMutableArray alloc]init];
}
return self;
}
-(NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {
return [list count];
}
-(id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
Number *p = [list objectAtIndex:row];
NSString *identifier = [tableColumn identifier];
return [p valueForKey:identifier];
}
-(IBAction)add:(id)sender{
[list addObject:[[Number alloc] init]];
[tableView reloadData];
}
-(void) dealloc {
[super dealloc];
}
#end
and Number implementation file:
#implementation Number
#synthesize x;
#synthesize y;
-(id) init {
self=[super init];
if (self) {
int j;
x = 5;
y=2+j;
j++;
}
return self;
}
#end
Number .h file:
#import <Foundation/Foundation.h>
int j;
#interface Number : NSObject {
#private
int x,y;
}
#property int x,y,j;
#end
But the number in y column doesn't increase by 1 when I hit the add button. It seems to be reset every time I hit add button. Any help what am I doing wrong? Many thanks.
Declare j into .h file .
.f file:
int j;
int .m file :
-(id) init {
self=[super init];
if (self) {
x = 5;
y=2+j;
j++;
}
return self;
}

Problems with array of type class

Hey guys I am trying to build a database that maps NSStrings to int. I have on class called Movie.h where each object has a name and a number assigned:
//Movie.h
#interface Movie : NSObject
{
int m_num;
NSString *m_name;
}
#property int m_num;
#property(nonatomic, retain) NSString *m_name;
#end
//Movie.m
#implementation Movie
#synthesize m_num, m_name;
#end
I then have another class called Map where I am implementing functions to play with my "Movies". One of the function is called insert, and it inserts an object of class movie into an array where all movies should be stored. The code compiles but my "m_array" does not seem to keep a record of what I add to it. Here is the code:
//Map.h
#import "Movie.h"
#interface Map : NSObject
{
#private
int m_count;
NSMutableArray *m_array;
}
#property int m_count;
#property(nonatomic, retain) NSMutableArray *m_array;
-(bool) contain: (NSString *) name;
-(bool) insert: (NSString *) name: (int) chap;
#end
//Map.m
#implementation Map
#synthesize m_count, m_array;
//Constructor
-(id) init{
if (self = [super init]){
m_count = 0;
}
return self;
}
-(bool) contain: (NSString *) name{
bool b = false;
for (int i = 0; i < m_count; i++) {
Movie *m = [[Movie alloc]init];
m = [m_array objectAtIndex:i];
NSLog(#"%# came out in %i", m.m_name, m.m_num);
if (m.m_name == name) {
b = true;
}
}
return b;
}
-(bool) insert:(NSString *) name: (int) chap{
Movie *m1 = [[Movie alloc]init];
m1.m_name = name;
m1.m_num = chap;
[m_array addObject:m1];
NSLog(#"Here is the object %#",[m_array objectAtIndex:m_count]);
m_count++;
return true;
}
#end
-(bool) upgrade:(NSString *)name :(int)chap{
if(![self contain:name])
return false;
for (int i = 0; i < m_count; i++){
Movie *m = [[Movie alloc]init];
m = [m_array objectAtIndex:i];
if(m.m_name == name)
m.m_num = chap;
}
return true;
}
Here's my main:
//main.m
#import "Map.h"
int main (int argc, const char * argv[])
{
#autoreleasepool
{
Map *m = [[Map alloc]init];
[m insert:#"James Bond" :2001];
if (![m contain:#"James Bond"]) {
NSLog(#"It does not work");
}
}
return 0;
}
Here's the console output:
2012-02-27 14:20:04.923 myMap[3926:707] Here is the object (null)
2012-02-27 14:20:05.036 myMap[3926:707] (null) came out in 0
2012-02-27 14:20:05.037 myMap[3926:707] It does not work
It looks like you forgot to create the array:
- (id)init
{
self = [super init]
if (nil != self) {
m_count = 0;
m_array = [NSMutableArray new]; << here
}
return self;
}
Without creating it, it's just nil.

Issue initializing an object of a custom class

I'm trying to make a custom HashTable for my program. Yes, I know there is already a HashTable class in Xcode, but for this case I have a custom one. It's supposed to be simple, but when I'm trying to use it in my view controller, the debugger shows its value to be "0x0", even after calling the initialization method. Here's the code:
//header file HashTable.h
#import <Foundation/Foundation.h>
#interface HashTable : NSObject
{
}
-(void)initWithLength:(int)capacity;
-(void)add:(NSObject*)object withName:(NSString*)name;
-(id)getObjectFromIndex:(int)index;
-(id)getObjectWithName:(NSString*)name;
#end
//main file HashTable.m
#import "HashTable.h"
#implementation HashTable
NSMutableArray* values;
NSMutableArray* markers;
-(id)initWithLength:(int)capacity //Apparently, this never gets called
{
self = [super init];
if (self)
{
values = [[NSMutableArray alloc] initWithCapacity:capacity];
markers = [[NSMutableArray alloc] initWithCapacity:capacity];
}
return self;
}
-(void)add:(NSObject*)object withName:(NSString*)name
{
[values addObject:object];
[markers addObject:name];
}
-(id)getObjectFromIndex:(int)index
{
return [values objectAtIndex:index];
}
-(id)getObjectWithName:(NSString*)name
{
for (int i = 0; i < [markers count]; i++)
{
if ([[markers objectAtIndex:i] isEqualToString:name]) {return [values objectAtIndex:i];}
}
return [NSObject new];
}
-(void)removeObjectFromIndex:(int)index
{
[values removeObjectAtIndex:index];
[markers removeObjectAtIndex:index];
}
-(void)removeObjectWithName:(NSString*)name
{
for (int i = 0; i < [markers count]; i++)
{
if ([[markers objectAtIndex:i] isEqualToString:name])
{
[values removeObjectAtIndex:i];
[markers removeObjectAtIndex:i];
return;
}
}
}
-(BOOL)isEmpty
{
return [values count] == 0;
}
-(void)dealloc
{
[values release];
[markers release];
[super dealloc];
}
#end
Then I have the segments of the view controller that uses HashTable:
//header file
#import <UIKit/UIKit.h>
#import "HashTable.h"
#interface Circuitry_LabViewController : UIViewController
{
HashTable* table;
}
#property(nonatomic, retain) HashTable* table;
#end
//main file
#import "Circuitry_LabViewController.h"
#implementation Circuitry_LabViewController
#synthesize table;
- (void)viewDidLoad
{
[table initWithLength:10];
[super viewDidLoad];
}
I can't see what I'm missing here. Can anyone help?
You meant to do this in -viewDidLoad:
table = [[HashTable alloc] initWithLength:10];
Something's telling me that you're doing it wrong.

Unable to access a primitive array inside a custom class from a UIViewController instance

I have made a subclass of NSObject that is meant to be the model of my application. The class has a few methods and on instance primitive array as such:
#interface Cube : NSObject {
int cubeState[5][2][2];
}
- (void)printContent;
#end
#implementation Cube
- (id)init {
if (self = [super init]) {
for (int i=0; i<=5; i++) {
for (int j=0; j<=2; j++) {
for (int k=0; k<=2; k++) {
cubeState[i][j][k] = i;
}
}
}
}
return self;
}
- (void)printContent {
for (int i=0; i<=5; i++) {
for (int j=0; j<=2; j++) {
for (int k=0; k<=2; k++) {
NSLog(#"[%d] [%d] [%d] = %d", i, j, k, cubeState[i][j][k]);
}
}
}
}
#end
This works fine if instanciated from the delegate as such:
#include "Cube.h"
#implementation CubeAppDelegate
#synthesize window;
- (void)applicationDidFinishLaunching:(UIApplication *)application {
Cube *cube = [[Cube alloc] init];
[cube printContent];
[cube release];
[window makeKeyAndVisible];
}
However, the application crashes if I try to create a subclass of UIViewController with a Cube *cube property and later try to access the Cube instance object through the view controller's property as such:
#interface CustomController : UIViewController {
Cube *cube;
}
#property (nonatomic, retain) Cube *cube;
#end
#implementation CustomController
#synthesize cube;
- (void)dealloc {
[cube release];
[super dealloc];
}
#end
and in the delegate:
- (void)applicationDidFinishLaunching:(UIApplication *)application {
viewController = [[CustomController alloc]
initWithNibName:#"MainView" bundle:nil];
viewController.cube = [[[Cube alloc] init] autorelease];
[viewController.cube printContent]; // Application crashes here
}
Any ideas?
(1)
int cubeState[5][2][2];
...
for (int i=0; i<=5; i++) {
for (int j=0; j<=2; j++) {
for (int k=0; k<=2; k++) {
Your cube's size is just 5x2x2, so the max index is only [4, 1, 1], but you're obviously accessing stuff beyond this limit. Try to change the <= into <.
(2)
- (void)init {
An -init must return id. Since you're returning void, the statement
[[[Cube alloc] init] autorelease];
could return some messed up stuffs.
And of course
- (id)printContent;
This should return void instead.