Init and init with parameters - objective-c

Here is the code :
#implementation Accumulateur
// Constructor
- (id) init
{
return ([self initWithTotal:0]);
}
- (id) initWithTotal:(int)aTotal
{
AccumulateurMoyen *ac;
if ((ac = [[AccumulateurMoyen alloc] init]) == nil)
{
[self release];
return (nil);
}
return ([self initWithTotal:aTotal andAccumulateurMoyen:ac]);
}
- (id) initWithTotal:(int)aTotal
andAccumulateurMoyen:(AccumulateurMoyen *)aAcMoyen
{
if (self = [super init])
{
[aAcMoyen retain];
[acMoyen release];
acMoyen = aAcMoyen;
total = aTotal;
}
return (self);
}
#end
The problem is here : if ((ac = [[AccumulateurMoyen alloc] init]) == nil)
As I redefined init, the init called is mine and not that of NSObject...
I dont have idea, how i can do that correctly (AccumulateurMoyen is subclass of Accumulateur)
Thx you

You have probably undesired recursion there: [[AccumulateurMoyen alloc] init] tries to create new AccumulateurMoyen but that results in nested initWithTotal: which again tries to create another AccumulateurMoyen instance etc.
I.e. your code tries to create Accumulateur which has member acMoyen set to new instance of AccumulateurMoyen, which again has its acMoyen set to another new instance of AccumulateurMoyen etc.
You must to break the endless recursion. E.g. in initWithTotal:, replace the line
if ((ac = [[AccumulateurMoyen alloc] init]) == nil)
with
if ((ac = [[AccumulateurMoyen alloc] initWithTotal:0 andAccumulateurMoyen:nil]) == nil)
I.e. the nested AccumulateurMoyen will have its member set to nil.

Sorry but I think you have a structural problem here. Why your super class need to have an reference to a class that extend it? I think your best option to it is think again how your class structure will be.
But in your subClass you can change the init method to so your problem will disappear.
(id)init {
return ([NSObject init]);
}

Related

Can I use assert() to catch failure of [super init]?

A typical init method in Objective C returns nil if initialisation fails:
- (id) init {
self = [super init];
if (self) {
// more initialisation
}
return self;
}
Would it make sense to use assertions to catch initialisations which should
always succeed? i.e:
- (id) init {
self = [super init];
assert(self); // unrecoverable?
// more initialisation
array = [[NSArray alloc] init];
assert(array); // unrecoverable?
return self;
}
In this case, failure of [super init] is defined (assumed?) to be an unrecoverable error, so crashing with an assertion failure is warranted.
It seems that the convention of returning nil is intended to be used to allow for error recovery, but in situations where error recovery isn't possible, is it reasonable to just throw an assertion?
Thanks...
Edit:
And see also this question
No returning nil, as per the normal pattern, is sufficient. It's up to the caller to decide what to do about it:
id obj = [[SomeObject alloc] init];
if (!obj)
[NSException raise:#"Oops"];

Objective-C Class definitions

Is it possible to alter the definition of a class in Objective-C?
For example, I have a function that creates objects (bullets), and those bullets are all the same. However, if given an event, say a power-up, I want to alter those bullets. In either size, or color, or what-have-you.
In my code, I have
playerBullet = [[PlayerBullet alloc] init];
But that always initializes the new bullet, regardless of 'power-up', as the standard, template bullet.
Is there a way that I adjust the class definition such that all new allocations of the PlayerBullet class come with the new value?
PlayerBullet.setProjectileColor:#"red";
Or is this approach a bad one?
The answer to your question as asked is No. However, what you are trying to do is very easily achievable with the proper design.
You should create a customer initialization method in your PlayerBullet class that takes an argument.
- (id) initWithProjectileColor:(NSString*)color
{
self = [self init];
if (self)
{
self.projectileColor = color;
}
return self;
}
So you could make a method and then call something like:
[[PlayerBullet alloc] initWithProjectileColor:#"red"];
Alternatively, you could create public properties and set them after creating a "blank" projectile.
call [[PlayerBullet alloc] initWithColor:#"red"] where you need it:
-(id) initWithColor:(NSString*) color{
self = [self init];
[self setProjecticeColor:colour];
return self;
}
There's no way to do this automatically. You could do it yourself with something like this. (Memory management not included.)
static NSString *DefaultProjectileColor = #"black";
+(void) setDefaultProjectileColor:(NSString *)color {
DefaultProjectileColor = color;
}
+(NSString *) defaultProjectileColor {
return DefaultProjectileColor;
}
-(id) init {
...
self.projectileColor = [PlayerBullet defaultProjectileColor];
...
}
-(void) gotPowerUp {
...
[PlayerBullet setDefaultProjectileColor:#"red"];
...
}

Objective C Singleton - Prevent Allocating Memeory More than Once

I use a sinlgeton in my application for managing data that is available to the whole application, which accessed via:
static MMProductManager *sharedInstance = nil;
+(MMProductManager*)SharedInstance {
dispatch_once( &resultsToken, ^(void) {
if ( ! sharedInstance ) {
sharedInstance = [[MMProductManager alloc] init];
}
});
return sharedInstance;
}
Everything is working as expected.
In Objective C, there does not seem to be a way to hide any object's init method, and in my case having more than instance of MMProductManager would lead to data being duplicated (in the best case scenario).
What I would like to do is guard against instantiating more than one instance. Other languages seem to have this feature; i.e. marking certain methods/classes as private. I am thinking of implementing something along like:
-(id)init {
// guard against instantiating a more than one instance
if ( sharedInstance )
return sharedInstance;
if ( (self = [super init]) ) {
self->_resultsQueue = dispatch_queue_create( kMMResultQLAbel, NULL );
self->_initialized = FALSE;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(handleNotification:)
name:UIApplicationDidReceiveMemoryWarningNotification
object:0];
[self initialize];
}
return self;
}
Does this approach seem reasonable?
What would happen in the case of someone allocating this class, then calling the init described above? Would it be reasonable to override +(id)alloc? If so How would I go about doing that?
I know the convention of exposing a SharedInstance method is an implicit message to other developers to go through this method, but I would like a bit more control if possible.
You don't want to override - init (if not for some other reason) - - init is not the method that creates the instance. You want to override + alloc for this:
#implementation SingletonClass
+ (id)alloc
{
static id instance = nil;
if (instance == nil) {
instance = [super alloc];
}
return instance;
}
#end
This way you can actually prevent (almost) completely creating multiple instances of SingletonClass.
(Unless somebody falls back to calling
id trickyDifferentInstance = class_createInstance(objc_getClass("SingletonClass"), 0));
but that's very unlikely.)

Obj-C: NSError in initialiser

Fairly simple question:
I have an init method on my class that has the potential to go wrong. If it does, I plan to "return nil", but I would also like to return an error. Is it bad practice to have an NSError** parameter to an init method? My method declaration would look like this:
- (id) initWithArgs:(NSString*) args andError:(NSError**)error;
Many thanks,
Nick
It's unusual, but I don't think it's necessarily a bad practice. I'd name the second part of the method just "error" instead of "andError:", though. You don't need to connect the parts of a method name with 'and', and in this case it also gives the impression that the error is being used to initialize the object. Just make it:
- (id) initWithArgs:(NSString*) args error:(NSError**)error;
Also, don't forget to release the allocated object if you plan to return something else (like nil):
- (id) initWithArgs:(NSString*) args error:(NSError**)error
{
if ((self = [super init])) {
if (canInitThisObject) {
// init this object
}
else {
[self release];
self = nil;
if (error != nil) {
*error = [NSError errorWithDomain:someDomain code:someCode: userInfo:nil];
}
}
}
return self;
}

Obj-C, Returning 'self' while it is not set to the result of '[(super or self) init...]'?

I'm getting an analyzer warning, since upgrading...
Returning 'self' while it is not set to the result of '[(super or self) init...]'
Dunno whats wrong with it ?
- (id)initWithFrame:(CGRect)frame {
if (self == [super initWithFrame:frame]) {
[self initLayers];
}
return self;
}
Get rid of the second equals sign. The proper if statement is:
if(self = [super initWithFrame:frame])
The point of this is that the super implementation could return a different, but still valid, object than the current value of self. In this case, your if statement will be false, since the objects are different, and so your initialization won't occur. However, since it returned a different object, the super implementation should have released the old self, which is what you are returning. This means you are probably returning an invalid pointer.
By using only one equals sign, you set the variable instead of comparing it. Since if(object) is true if object is not nil, it is equivalent to this:
if((self = [super initWithFrame:frame]) != nil)
Or, the easier to understand version:
self = [super initWithFrame:frame];
if(self != nil)
This code reassigns self to be the value returned by the super initializer, instead of just assuming the value returned is the same. This is the same reason why it is important to set a variable to the result of the init... method and not alloc.
// good
id object = [[MyClass alloc] init];
// bad
id object = [MyClass alloc];
[object init];
If I recall correctly the syntax is self = ... not self == .... The syntax uses the returned value from assignment.
your returning self not initialized
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self initLayers];
}
return self;
}