Initializing instance object in designated initializer? - objective-c

I have a Rectangle class which has properties width and height. It also has an instance property/object called origin (-(XYPoint *) origin ). Below is the code for my designated initializer in which I pass the XYPoint object as an argument. Is there a way (or is it okay) if I take the properties of the XYPoint class as arguments in this method and then initialize the XYPoint object as well as allocate memory for it inside the method? Otherwise I have to create an XYPoint object in my main program and pass it as an argument which is a lot more code to type.
-(id) initWithWidth:(int)w andHeight:(int)h andOrigin:(XYPoint *)o
{
self = [super init];
if (self) {
[self setWidth: w andHeight: h];
self.origin = o;
}
return self;
}
P.S.- I am new to programming and Objective C so pardon me if I have stated something technically wrong in my question. Thanks!

Personally--I try to avoid initializers that take parameters. I think it leads to writing lots more code and inflexibility. I use designated initializers for just 2 things:
initializing an object with properties that must not be changed after the object is initialized
initializing an object with properties that are absolutely needed to construct it and cannot be specified later
In general, for Rectangle class, I'd make the use like this:
Rectangle * r = [ [ Rectangle alloc ] init ] ;
r.x = x ;
r.y = y ;
r.origin = o ;
// use r
and not use the designated initializer pattern at all except for the conditions outlined above. (For example, creating immutable Rectangle instances)
Finally, there's probably no need to create a Rectangle class--just use CGRect/NSRect primitive structures.

Related

Passing an integer to a class, and then creating an array with a size of that integer [duplicate]

This question already has answers here:
declaring array of an object X with unknown size objective c
(2 answers)
Closed 8 years ago.
I have a class named Calculator. This class accepts a bunch of test scores, and will store each of them into an array. This array is called scoreArray.
I want to declare the array like this, but I'm having trouble with the scope:
int scoreArray[numTestScores];
If I put that code into the #implementation, it doesn't know what numTestScores is, because it hasn't been passed to the class yet.
And if I try to do this:
-(id)init:(int)numTestScores_
{
if (self = [super init])
{
int scoreArray[numTestScores_];
}
return self;
}
then the array gets created, but the rest of the class doesn't know what scoreArray is.
How can I make it so that scoreArray is created with length "numTestScores" and has the same scope as if I had put it in the implementation block?
Using a native C array is an unnecessary pain. I'd rather use a NSMutableArray, declaring it as a property.
#property (nonatomic, copy) NSMutableArray *scores;
NSMutableArray automatically manages its memory, so you don't need to declare its size in advance.
Just initialize it as
_scores = [NSMutableArray array];
and then add values to it
[self.scores addObject:#(aResult)]; //assuming that aResult is an integer expression
#(...) wraps the value in a NSNumber since NSArray can only hold objects.
To retrieve a score, you can do
int score = [self.scores[0] intValue];
VLAs (variable-length arrays) only work in contexts where... um... where they make sense. In this case, you will rather want to utilize dynamic memory allocation and an instance variable:
#interface MyClass: NSObject {
int *array;
size_t size;
}
// ... etc ...
- (id)initWithSize:(size_t)n
{
if (self = [super init]) {
size = n;
array = malloc(size * sizeof array[0]);
}
return self;
}
// free the allocated memory upon destruction
- (void)dealloc
{
// ...
free(array);
// ...
[super dealloc];
}
As to why it doesn't really make sense to use a variable-length array as an instance variable: instance variables are part of an object. If you declared a VLA inside an object, then the size of the instance would depend on its initialization. That is not something immediately easy to implement, and it is not the way the Objective-C runtime works. (I'm not saying it's impossible, but it would be very, very impractical.)
All classes have their instance size deduced at compile time (well, mostly... nowadays it's rather the initialization of the runtime system), and it can't be changed later. As a consequence, the size of an object cannot vary from initialization to initialization.
On the assumption that you're writing a properly contained object oriented class, the implementation of your set of scores is not important to the outside world. If that is indeed the case, don't create an int array, create an NSMutableArray instead (and if you want to pre-fill numTestScores_ entries to make things easier later, do that, but there shouldn't be a need for it really).
If you must have an array, you will have to allocate it dynamically by declaring scoreArray to be an int * and using malloc. Be careful here though -- you will have to create a dealloc method in your class to free() the array if it has been created.

I'm trying to get alloc init and nil to work within a method in ObjC

should hopefully be an easy question (teaching myself Objective C as I go).
I would like to send a method to an object (Cell) which returns a different object (Waste), and then deletes the reciever (Cell). Here is what I'm looking at so far:
#import "Cell.h"
#import "Waste.h"
#implementation Cell
#synthesize.......
other methods.....
// Send a method to an instance of class "Cell", causing a new object of
// class "Waste" to be made, then causing the Cell instance to "die"
- (Waste *) die {
// Create a new object, "newWaste", of class Waste
// ARC Semantic Issue: No known class method for selector 'alloc'
Waste *newWaste = [[Waste alloc] init];
// Set the energy of "newWa" to 10% what the Cell's energy is
newWaste.wasteEnergy = (0.1 * cellEnergy);
// Set the X coordinate of "r" to the Cell's X coordinate
newWaste.wasteXCoordinate = cellXCoordinate;
// Set the Y coordinate of "r" to the Cell's Y coordinate
newWaste.wasteYCoordinate = cellYCoordinate;
// Variable saying if the Waste is to be excreted set to "NO"
newWaste.wasteExcreted = NO;
// Return the new waste object
return newWaste;
// Have the Cell "die" ARC Semantic Issue:
// Cannot assign to 'self' outside of a method in the init family
self = nil;
}
I've put the two issues that come up behind the comments so you know where the problems are, but they're:
ARC Semantic Issue: No known class method for selector 'alloc'
and
ARC Semantic Issue: Cannot assign to 'self' outside of a method in the init family
Could someone tell me why this is happening and how to fix it? I had thought it was straightforward to do:
Class *newInstance = [[Class alloc] init];
and that this could be done inside a method so you can return the instance. And I had read that self = nil; was the normal way for releasing objects with ARC.

Should I assign the result of calling my class' designated initializer to self?

I was reading through the source of core-plot and ran across this code in CPTColor:
-(id)initWithCGColor:(CGColorRef)newCGColor
{
if ( (self = [super init]) ) {
CGColorRetain(newCGColor);
cgColor = newCGColor;
}
return self;
}
-(id)initWithComponentRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha
{
CGFloat colorComponents[4];
colorComponents[0] = red;
colorComponents[1] = green;
colorComponents[2] = blue;
colorComponents[3] = alpha;
CGColorRef color = CGColorCreate([CPTColorSpace genericRGBSpace].cgColorSpace, colorComponents);
[self initWithCGColor:color];
CGColorRelease(color);
return self;
}
If [self initWithCGColor:color]; results in initWithCGColor's superclass assigning a different value to self, will that new value be returned from initWithComponentRed:green:blue:alpha:?
In other words, is self in the two init methods the same variable two distinct variables?
This setup is potentially fragile, and Joe's suggestion, assigning self in initWithComponentRed:... before returning that value will fix it.
Every method gets an argument, self, that points to the instance it was called on. The argument acts just like any other variable; there's nothing special about it. That's why it's possible to assign self, and why it's necessary to have an explicit return in initializers.
When you send [super init], you're using the superclass's version of the init method, but the current instance will still be passed as self. Since initializers in Objective-C are allowed to destroy the object they receive and create and return a new one,* there is a potential for self = [super init] in initWithColor: to not be the same object as that pointed to by self back in initWithComponentRed:....
If that happens, since you don't reassign self to point to that new, correctly-initialized object, you'll be returning an uninitialized object from initWithComponentRed:....
This is only a practical concern if your superclass could possibly do the substitution I described, but there's also no reason, AFAIK, to not do that reassignment.
*Collections do this, for example, because they don't know how big they need to be at alloc time; I believe NSNumber also does this because it has cached values for instances representing small integers.
No if self were to change (ex. if you were to implementing a color cache) initWithComponentRed:green:blue:alpha: would return the wrong object unless the code was changed to:
...
self = [self initWithCGColor:color];
CGColorRelease(color);
return self;
}
self always refers to the same object. It is not a "variable", but a language key word. If one initializer is called after the other, the object is simply altered.
NB: Otherwise, your pour class would have a "split personality" ;-).

How does one know when it's safe to use a parent method in NS subclasses?

As an example, when I'm using an NSMutableDictionary, I know it inherits all the methods of NSDictionary, but how can I know/trust that it has overridden the behavior of those methods if I want to use NSDictionary methods (such as +dictionaryWithObjectsAndKeys) to create my mutable dictionary instance?
More generally, is it the Framework's responsibility to make sure subclasses don't blindly inherit methods that can potentially break instances of the subclass if used? Or is it the coder's responsibility to know not to use them? If Square inherits from Rectangle, and via inheritance I can call
Square *newSquare = [[Square alloc] init];
[newSquare setWidth:3 andHeight:6]; //instead of -(void)setSide:(int)side
I've "broken" the square and other methods which depend on width being equal to height will not work now. What are the rules of the game?
The rule would be only expose what you would allow to be override it means, put on your interface what is really public. When necessary explicitly state that when overriding an specific method call at some point [super methodName].
On your example you would override the method - (void)setWidth:(int)width andHeight:(int)height, and you would like to throw an error if width != height. Or you could also throw an error and force the user to only use - (void)setSide:(int)side.
For example you could do:
// If you want to test and accept cases when width == height
- (void)setWidth:(int)width andHeight:(int)height {
NSAssert(width == height, NSLocalizedString(#"This is a Square. Width has to be height.", nil));
[super setWidth:width andHeight:height];
// Or
[self setSide:width];
}
// Or if you want to completely prohibit the usage of the method
- (void)setWidth:(int)width andHeight:(int)height {
NSAssert(NO, NSLocalizedString(#"This is a Square! Please use - (void)setSide:(int)side method.", nil));
}
If you would like to throw some errors and warnings at compilation time, you could use on the declaration of your methods, some of the macros defined on NSObjCRuntime.h.
I wouldn't trust the parent convenience method to call your inheriting init method. For example, that dictionary method could be defined as:
+ (id)dictionaryWithObjectsAndKeys:...
{
return [[[NSDictionary alloc] initWithObjectsAndKeys:...] autorelease];
}
If that method is defined that way then it won't be even be aware of your implementation.
You'd have to create your own convenience method. Something like would be in your MyDictionary implementation:
+ (id)myDictionaryWithObjectsAndKeys:...
{
return [[[MyDictionary alloc] initWithObjectsAndKeys:...] autorelease];
}
--
Also...
You probably should inherit Rectangle from Square. Inheritance is additive. You can describe Square with one size (width), but for Rectangle you have two sizes (width, height).

self in Objective-C

is self not completely interchangeable with this in C++?
It seems to work with message passing ([ self sayHi ] would work within any method there).
I don't quite understand why I can't use self to access private members of an object (in the example below, I show I can't use self.width)
#import <Foundation/Foundation.h>
// Write an Objective-C class
#interface Rectangle : NSObject
{
int width ;
}
-(int)getWidth;
-(void)setWidth:(int)w;
-(void)sayHi;
-(void)sayHi:(NSString*)msg ;
#end
#implementation Rectangle
-(int)getWidth
{
// <b>return self.width ; // ILLEGAL, but why?</b>
// why can't I return self.width here?
// why does it think that's a "method"?
return width ;
}
-(void)setWidth:(int)w
{
// <b>self.width = w ; // ILLEGAL</b>
// again here, I CAN'T do self.width = w ;
width = w ;
}
-(void)sayHi
{
puts("hi");
}
-(void)sayHi:(NSString*)msg
{
printf( "Hi, and %s\n", [ msg UTF8String ] ) ;
}
#end
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
Rectangle* r = [ Rectangle alloc ] ;
[ r sayHi ] ;
[ r setWidth:5 ] ;
printf( "width is %d\n", [ r getWidth ] ) ;
[pool drain];
return 0;
}
The other answers are almost correct, but not quite.
In Objective-C, no object [save for Blocks, but that is a very very special case] are ever on the stack. Thus, self.width doesn't make sense.
However, self->width does work. Since self is a reference to what is effectively a structure allocated on the heap, using the -> operator to get at the member variables makes sense.
But, in the context of Objective-C, it generally doesn't make sense, either. That is, Objective-C generally assumes a philosophy of preserving encapsulation. That is, you don't generally reach into an object and muck with the instance variables -- the internal state -- directly. Instead, you use the accessors to get/set the state. By doing so, the object (and subclasses) can customize getter/setter behavior, as needed. (This includes such mechanisms as Key-Value Observing and Key-Value Coding).
That self.width happens to equate to [self width] or [self setWidth: ...something...] is fallout from the above. That is, the . operator for accessing members of Objective-C class instances was not otherwise used and could be overloaded as a short hand for property access.
However, there is little difference between property access and invoke the getter/setter method. Thus, dot notation is synonymous with method invocation.
Within the context of your code, instance variables are transparently accessible within your classes implementation and without prefix.
Thus, you would use width = 5.0; instead of self.width = 5.0;, typically. Of course, the latter does equate to a method call with Objective-C 2.0 for reasons stated above.
You can't use self.width because it's not a property. self.width = w is shorthand for [self setWidth:w]; which was introduced in Objective-C 2.0. Try adding #property int width; above your method prototypes in the interface file, and at the top of your implementation file under the #implementation line, add #synthesize width;. That should allow you to use self.width, but it would no longer be a private variable.
You could also use #property (readonly) int width; to only generate a 'getter' method for width, but I doubt that's what you want. For more options you can pass to #property, check this documentation page.
Also, like Cliff said, getVar isn't convention in Objective-C. Instead, you just use the name of the variable you want to expose. The get prefix is usually used for when you're returning some form of raw data, as far as I know.
self.width is shorthand for [self width] and since you have not defined a width method it will be illegal. The getters in ObjC do not start with "get" by convention as they would in other languages like Java. Also I've heard from other experts (though I don't understand why) that it's not a good idea to use the property syntax from within the object that owns the proerty. From what I heard it causes some kind of a gotcha with Key Value Coding. In your example if you want to define a custom getter/setter then just reference the value directly without the self qualifier. It probably makes sense to use the getter/setter or dot notation everywhere else for good encapsulation.
self in Objective-C, like this in C++, is a pointer to the current object. So to access a field through self, you would do self->width (just as you would do this->width in C++)