Issue initializing an object of a custom class - objective-c

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.

Related

Objective-C NSMutableArray not saving objects

I'm learning Objective-C (having come from Java) and I'm am attempting to program a small Cocoa app on OSX. I am thinking with my Java hat on and that's probably why this isn't working. Basically I am trying to get an object of type Car added to an NSMutableArray on a button click but although the rest of the code seems to work, nothing is being saved to the array. I can't figure out why - help is appreciated. Here's the code:
#import "AppDelegate.h"
#import "Car.h"
#import "PileInterface.h"
#interface AppDelegate ()
#property (weak) IBOutlet NSWindow *window;
#end
#implementation AppDelegate
PileInterface *myStack;
Car *car;
//initialise Stack
-(void)stack{
myStack = [[PileInterface alloc]init];
//initialise myStack in Pileinterface
[myStack initialise];
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
//corrected code here to call the stack method above
//initialise myStack by calling stack method
[self stack];
}
- (void)applicationWillTerminate:(NSNotification *)aNotification {
// Insert code here to tear down your application
}
- (IBAction)addBtn:(NSButton *)sender {
car = [[Car alloc]init];
NSString *licence = [_txtField1 stringValue];
NSString *model = [_txtField2 stringValue];
NSString *colour = [_txtField3 stringValue];
if ([myStack isFull] == false) {
// add Car objects to car
//set licence
[car setLicence:licence];
// set model
[car setModel:model];
//set colour
[car setColour:colour];
//add to stack
[myStack push:car];
//append to textarea
NSString *message = licence;
[_txtArea setStringValue:message];
[_txtField2 setIntegerValue:[myStack size]];
} else {
NSString *message2 = #"Rejected. There are more than 4 cars currently for recycling!";
[_txtArea insertText:message2];
}
}
#end
Effectively Car is the object I want to get into myStack (which is a stack inside PileInterface, which also contains the NSMutableArray)
PileInterface implementation code here:
#import "PileInterface.h"
#implementation PileInterface
//arraylist of objects
NSMutableArray *list;
//initialise array
-(void)initialise{
list = [[NSMutableArray alloc]init];
}
-(void) push:(id) o{
[list insertObject:o atIndex:0];
}
-(id) pop{
if ([list count] > 0) {
NSObject *temp =[list objectAtIndex:0];
[list removeObjectAtIndex:0];
return temp;
} else {
return nil;
}
}
-(BOOL) isEmpty{
if ([list count] == 0) {
return true;
} else {
return false;
}
}
-(int) size{
return (int)[list count];
}
-(BOOL) isFull{
if ([list count] > 4) {
return true;
} else {
return false;
}
}
#end
Help Appreciated!

Object loses reference

I have a IKImageBrowserView which has its own controller - BrowserController.h + .m
#interface BrowserController : NSWindowController{
NSMutableArray *_images;
}
#property (strong,nonatomic) IBOutlet IKImageBrowserView *imageBrowser;
-(void)addMultipleImages;
When I run the app for the first time, the staring image loads, but when I click a button to add other images and call a method from another class I don't get any results. I have noticed that my _imageBrowser loses the reference and becomes nil.
How could I solve this issue?
AppDelegate.m
#import "AppDelegate.h"
#import "BrowserController.h"
#implementation AppDelegate{
BrowserController *imageBrowserController;
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Insert code here to initialize your application
imageBrowserController = [BrowserController sharedManager];
}
- (IBAction)doSomething:(id)sender {
[imageBrowserController addMultipleImages];
}
#end
BrowserController.m
#import "BrowserController.h"
#interface myImageObject : NSObject
{
NSString *_path;
}
#end
#implementation myImageObject
/* our datasource object is just a filepath representation */
- (void)setPath:(NSString *)path
{
if(_path != path)
{
_path = path;
}
}
/* required methods of the IKImageBrowserItem protocol */
#pragma mark -
#pragma mark item data source protocol
/* let the image browser knows we use a path representation */
- (NSString *)imageRepresentationType
{
return IKImageBrowserPathRepresentationType;
}
/* give our representation to the image browser */
- (id)imageRepresentation
{
return _path;
}
/* use the absolute filepath as identifier */
- (NSString *)imageUID
{
return _path;
}
#end
#interface BrowserController ()
#end
#implementation BrowserController
- (id)initWithFrame:(NSRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code here.
}
return self;
}
- (void)drawRect:(NSRect)dirtyRect
{
[super drawRect:dirtyRect];
// Drawing code here.
}
- (void)awakeFromNib{
myImageObject *p;
p = [[myImageObject alloc]init];
[p setPath:[[NSBundle mainBundle]pathForResource:#"Unknown" ofType:#"jpg"]];
_images = [[NSMutableArray alloc]init];
[_images addObject:p];
[self updateDataSource];
}
- (void)updateDataSource{
[_imageBrowser reloadData];
}
-(NSUInteger) numberOfItemsInImageBrowser:(IKImageBrowserView *)aBrowser{
return [_images count];
};
-(id)imageBrowser:(IKImageBrowserView *)aBrowser itemAtIndex:(NSUInteger)index{
return [_images objectAtIndex:index];
};
- (void)updateDatasource
{
[_imageBrowser reloadData];
}
- (void)addMultipleImages{
myImageObject *p;
p = [[myImageObject alloc]init];
[p setPath:[[NSBundle mainBundle]pathForResource:#"Unknown" ofType:#"jpg"]];
_images = [[NSMutableArray alloc]init];
[_images addObject:p];
[_images addObject:p];
[_images addObject:p];
[_imageBrowser reloadData];
}
+ (id)sharedManager {
static BrowserController *sharedMyManager = nil;
#synchronized(self) {
if (sharedMyManager == nil)
sharedMyManager = [[self alloc] init];
}
return sharedMyManager;
}
#end
There is some confusion as to the name of the class where you mention it's called ImageBrowserController at the start of your question and it looks like it's called BrowserController at the end of your question.
The issue is that you allocate _images in awakeFromNib which is never called given the class is created via the singleton pattern (sharedInstance) and not loaded from a .nib file.
Therefore move the code from awakeFromNib into init and dump awakeFromNib:
BrowserController.m:
- (id)init
{
self = [super init];
if (self) {
myImageObject *p = [[myImageObject alloc]init];
[p setPath:[[NSBundle mainBundle]pathForResource:#"Unknown" ofType:#"jpg"]];
_images = [[NSMutableArray alloc]init];
[_images addObject:p];
[self updateDataSource];
}
return self;
}
Further confusion: you have implemented an initWithFrame method. Why?

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

Leak on iPad that I don't understand

I've got a leak in my application and I do not know why. Maybe I've got all memory managment thing wrong. In my code I've got UIViewController object which have ivar TelephoneValidator *validator
TelephoneValidator is TelephoneValidator : NSObject
So in my initialization function of UIViewController object (initWithFieldData) I've got:
-(id) initWithFieldData: (NSMutableDictionary*) fieldData
{
...
validatorOptions = [fieldData objectForKey:#"fieldValidator"];
...
}
Now in my viewDidLoad I've got:
- (void)viewDidLoad {
...
if (![validatorOptions respondsToSelector:#selector(isEqualToString:)]) {
validator = [[TelephoneValidator alloc] initWithOptions: validatorOptions];
}
else {
validator = nil;
}
...
}
Basicly if my validatorOptions isn't NSString the validator ivar became TelephoneValidator instance.
In my dealloc:
- (void)dealloc {
if(validator != nil)
{
[validator release];
validator = nil;
}
...
[super dealloc];
}
I've checked a couple of times if dealloc works, and it is. After calling dealloc the validator is released (calling any method on validator after [validator release] gets me exception).
And yet in Instruments it is telling me that TelephoneValidator is leaked. And after double clicking in Instruments the line of code that is highlited is:
validator = [[TelephoneValidator alloc] initWithOptions: validatorOptions];
What am I doing wrong?
UPDATE:
Here is my header information of UIViewController:
#interface GenericViewController : UIViewController <UITextFieldDelegate>{
UIImage *backgroundImage;
NSString *step; // na ktorym kroku jestesmy
id <GenericControllerDelegate> delegate; //delegata z ktorej bedziemy pobierali dane
UITextField *textField;
NSString *fieldName; //nazwa pola (potrzebujemy zeby zapisac do modelu odpowiedni tekst
UILabel *textLabel;
UILabel *stepsLabel;
UILabel *prefixTextLabel;
NSString *fieldPlaceholder;
NSString *textLabelText;
NSString *textLabelTextPl; //w jezyku polskim
NSString *prefixTextLabelText; //w jezyku eng
NSString *prefixTextLabelTextPl; //w jezyku polskim prefix
NSString *fieldRequired;
NSString *keyboardType;
NSString *capitalizeType;
UIButton *button; //forward button
UIButton *button2; //backward button
//to bedzie do przerobienia bo bedziemy mieli tablicje walidatorow a nie jeden walidator
NSString *validatorType;
//maksymalna dlugosc pola
int maxLengthOfTextField;
NSArray* validatorOptions;
TelephoneValidator *validator;
//patientModel
PatientData *patientModel;
}
TelephoneValidator header:
#import <Foundation/Foundation.h>
#import "MAOTranslate.h"
#interface TelephoneValidator : NSObject {
//opcje walidacyjne
NSString *phonePrefix;
NSString *phonePostfix;
int phoneLength;
NSString *message;
NSString *messagePl;
UIAlertView *alertView;
}
-(id) initWithOptions:(NSArray *) optionsArray;
-(void) displayMessage;
-(BOOL) validate: (NSString *) phoneNumber;
#end
TelephoneValidator class:
#import "TelephoneValidator.h"
#implementation TelephoneValidator
//#synthesize phoneNumber;
-(id) initWithOptions:(NSArray *) optionsArray;
{
if(self = [[TelephoneValidator alloc] init])
{
phonePrefix = [optionsArray objectAtIndex:0];
phonePostfix = [optionsArray objectAtIndex:1];
phoneLength = [[optionsArray objectAtIndex:2] intValue];
message = [optionsArray objectAtIndex:3];
messagePl = [optionsArray objectAtIndex:4];
}
else {
self = nil;
}
return self;
}
//wyswietlamy wiadomosc
-(void) displayMessage
{
NSString *displayMsg;
if ([[MAOTranslate getLanguage] isEqualToString:#"pl"]) {
displayMsg = messagePl;
}
else {
displayMsg = message;
}
alertView = [[UIAlertView alloc] initWithTitle:#"Alert" message:displayMsg delegate:self cancelButtonTitle:#"ok" otherButtonTitles:nil];
[alertView show];
}
-(BOOL) validate: (NSString *) phoneNumber
{
//dlugosc
if ([phoneNumber length] != phoneLength) {
NSLog(#"zla dlugosc");
return NO;
}
NSLog(#"tutaj");
//sprawdzamy prefix
if ([phonePrefix length]!= 0) {
NSLog(#"w srodku ifa");
if ([phoneNumber compare:phonePrefix options:NSLiteralSearch range:NSMakeRange(0, [phonePrefix length])] != 0) {
NSLog(#"zly prefix");
[self displayMessage];
return NO;
}
}
//sprawdzamy postfix
if([phonePostfix length] != 0)
{
if ([phoneNumber compare:phonePostfix options:NSLiteralSearch range:NSMakeRange([phoneNumber length]-[phonePostfix length], [phonePostfix length])] != 0) {
NSLog(#"zly postfix");
[self displayMessage];
return NO;
}
}
//sprawdzamy czy string jest numeryczny
NSCharacterSet *alphaNums = [NSCharacterSet decimalDigitCharacterSet];
NSCharacterSet *inStringSet = [NSCharacterSet characterSetWithCharactersInString:phoneNumber];
if (![alphaNums isSupersetOfSet:inStringSet])
{
NSLog(#"zly format ");
[self displayMessage];
return NO;
}
return YES; //zwalidowany poprawnie
}
-(void) dealloc
{
[alertView release];
alertView = nil;
[super dealloc];
}
You need to call [super dealloc] at the end of the dealloc method.
See These both lines
validator = [[TelephoneValidator alloc] initWithOptions: validatorOptions];
and inside initWithOptions
if(self = [[TelephoneValidator alloc] init])
You are allocing twice the validator, so there is a leak.
Could it be that instruments is pointing to validatorOptions as the source of the leak? Is it a retained property being released at dealloc or not? I can't say for sure, the code you posted is not enough to arrive to a conclusion.
Also, as willcodejavaforfood says, you must always call [super dealloc]; at the end of your dealloc method. No code must come after it.
Edit:
I'm back. But Bruno Domingues got it right already, you are allocating twice, in which case, the first one leaks. You should change your -initWithOptions: code to:
-(id) initWithOptions:(NSArray *) optionsArray;
{
if((self = [super init])){
// ... rest of code is fine
}
return self;
}

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.