I built a custom class named game:
.h
-(void) init;
here I have a Also found '-(void) init'
.m
-(void) init {
[super init];
score = 0;
lives = 3;
elements = [[NSMutableArray alloc] initWithCapacity:1000];
}
when I try to initialize a object with:
myGame = [[Game alloc] init];
I got "Multiple methods named '-init' found
So I don't know where the error is...
init should always return (id). Change your function to the following:
.h
-(id) init;
.m
-(id) init {
if((self = [super init]))
{
score = 0;
lives = 3;
elements = [[NSMutableArray alloc] initWithCapacity:1000];
}
return self;
}
Related
I'm learning Objective-C with the Big Nerd Ranch Guide.
The author uses a store from which the controller can get some data to display :
#import "BNRItemStore.h"
#import "BNRItem.h"
#interface BNRItemStore ()
#property(nonatomic) NSMutableArray *privateItems;
#end
#implementation BNRItemStore
+(instancetype)sharedStore {
static BNRItemStore *sharedStore = nil;
if (!sharedStore){
sharedStore = [[BNRItemStore alloc] initPrivate];
}
return sharedStore;
}
-(instancetype)initPrivate {
self = [super init];
if (self) {
_privateItems = [[NSMutableArray alloc] init];
}
return self;
}
My question is about the _privateItems = [[NSMutableArray alloc] init]; line : why do we initialize _privateItems and not privateItems ?
Regards.
privateItems is the property name. Each property has a variable behind it, with a default name of _propertyName. in your case it's _privateItems.
Most times, you would use the property to set the value, like this: self.privateItems = [[NSMutableArray alloc] init]. However, you should not set properties directly in init methods, and that is why the author sets the value directly to the variable.
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.
In an NSObject subclass declaration is an array:
#interface theClass : NSObject {
NSMutableArray *myArray;
}
...
#end
In the implementation's initializer:
- (id)init
{
self = [super init];
if (self) {
[myArray initWithCapacity:50];
}
return self;
}
And in a method:
- (NSMutableArray *)theMethod:(NSArray *)someArray {
...
...
[myArray addObject:anObject];
...
return myArray;
}
Yet despite the class being instantiated in my controller, any number of messages to the method leave myArray without contents.
You haven't allocated the array yet. Replace your init code with the following:
- (id)init
{
self = [super init];
if (self) {
myArray = [[NSMutableArray alloc] initWithCapacity:50];
}
return self;
}
I'm new in objective-C and here is my problem:
I want to write a game and i want to use a GameStateManager class to manage the game states. As i've read every class in Objective-C should be inherited from NSObject or it's subclass. So here is the GameStateManager interface:
#interface GameStateManager : NSObject {
int currentState_;
}
+(id) instance;
-(void) setState:(int)state;
#end
And here is the implementation:
#implementation GameStateManager
+(id) instance
{
GameStateManager *manager = [GameStateManager init];
return manager;
}
- (id) init
{
self = [super init];
return self;
}
- (void) setState: (int) state
{
switch (state)
{
case GS_MAIN_MENU_START:
{
// MenuScene *menuScene = [MenuScene node];
// [menuScene build: false];
MenuScene *scene = [scene instance:self :false];
[[CCDirector sharedDirector] runWithScene: scene];
}
break;
case GS_PLAYING:
{
}
break;
}
}
#end
I use this class here:
gameStateManager = [GameStateManager instance];
[gameStateManager setState: GS_MAIN_MENU_START];
The second line generated an SIGABRT signal. What's the problem ?
The problem is here:
+ (id) instance
{
GameStateManager *manager = [GameStateManager init];
return manager;
}
In effect you are calling init without ever calling alloc. I’d recommend that you forget about the instance stuff and use the official init patterns until you are really comfortable with the memory management:
- (id) init
{
self = [super init];
if (self == nil)
return nil;
…
return self;
}
…and then get your instance by calling [[GameStateManager alloc] init].
GameStateManager *manager = [GameStateManager init];
-(id)init is an instance method, not a class method. That line should look like this:
GameStateManager *manager = [[GameStateManager alloc] init];
The issue is that the gameStateManager isn't being created properly. Instead of
[GameStateManager init]
use
[[[GameStateManager alloc] init] autorelease]
The autorelease is for good memory management and doesn't actually affect the initialization.
If I create a custom initWith for an object do I essentially include the code I would add should I want to override init?
-(id) init {
self = [super init];
if (self) {
NSLog(#"_init: %#", self);
}
return(self);
}
e.g.
-(id) initWithX:(int) inPosX andY:(int) inPosY {
self = [super init];
if(self) {
NSLog(#"_init: %#", self);
posX = inPosX;
posY = inPosY;
}
return(self);
}
gary
You can create one designated initializer that accepts all parameters that you want to make available in initialization.
Then you call from your other -(id)init your designated initializer with proper parameters.
Only the designated initializer will initialize super class [super init].
Example:
- (id)init
{
return [self initWithX:defaultX andY:defaultY];
}
- (id)initWithPosition:(NSPoint)position
{
return [self initWithX:position.x andY:position.y];
}
- (id)initWithX:(int)inPosX andY:(int)inPosY
{
self = [super init];
if(self) {
NSLog(#"_init: %#", self);
posX = inPosX;
posY = inPosY;
}
return self;
}
The designated initializer is -(id)initWithX:andY: and you call it from other initializers.
In case you want to extend this class you call your designated initializer from subclass.
I'd suggest creating one main initializer that handles most of the work. You can then create any number of other initializers that all call this main one. The advantage of this is if you want to change the initialization process, you'll only have to change one spot. It might look like this:
-(id) initWithX:(float)x {
if (self = [super init]) {
/* do most of initialization */
self.xVal = x;
}
return self;
}
-(id) init {
return [self initWithX:0.0f];
}
In this example initWithX: is our main initializer. The other initializer (init) simply calls initWithX: with a default value (in this case 0).
Yes, that's exactly how I do it. One slight change will cut out a line of code:
if (self = [super init]) {
As opposed to:
self = [super init];
if(self) {
For modern Objective-C ...
UDFile.h
#import <Foundation/Foundation.h>
#interface UDFile : NSObject
#property (nonatomic, strong) NSString *name;
- (instancetype)initWithName:(NSString *)name NS_DESIGNATED_INITIALIZER;
#end
UDFile.m
#import "UDFile.h"
#implementation UDFile
- (instancetype)initWithName:(NSString *)name {
self = [super init];
if (self) {
_name = [name copy];
}
return self;
}
- (instancetype)init {
return [self initWithPathname:#""];
}
Sometimes, you want to reuse some initialisation code and modify the behaviour only slightly for specific initialisers. In this case, I do the following:
- (id) init
{
self = [super init];
if (!self) return nil;
// These values are always initialised this way
ivar1 = 10;
ivar2 = #"HellO";
ivar3 = [[NSMutableArray alloc] initWithCapacity:10];
ivar4 = 22;
return self;
}
- (id) initWithIvar4:(int) aValue
{
// call -init on self, which will call -init on super for us, and set
// up ivar1, ivar2, ivar3, and ivar4.
self = [self init];
if (!self) return nil;
// Change ivar4 from the default 22 to whatever aValue is.
ivar4 = aValue;
return self;
}