Constructor in Objective-C - iphone

I have created my iPhone apps but I have a problem.
I have a classViewController where I have implemented my program.
I must alloc 3 NSMutableArray but I don't want do it in grapich methods.
There isn't a constructor like Java for my class?
// I want put it in a method like constructor java
arrayPosition = [[NSMutableArray alloc] init];
currentPositionName = [NSString stringWithFormat:#"noPosition"];

Yes, there is an initializer. It's called -init, and it goes a little something like this:
- (id) init {
self = [super init];
if (self != nil) {
// initializations go here.
}
return self;
}
Edit: Don't forget -dealloc, tho'.
- (void)dealloc {
// release owned objects here
[super dealloc]; // pretty important.
}
As a side note, using native language in code is generally a bad move, you usually want to stick to English, particularly when asking for help online and the like.

/****************************************************************/
- (id) init
{
self = [super init];
if (self) {
// All initializations you need
}
return self;
}
/******************** Another Constructor ********************************************/
- (id) initWithName: (NSString*) Name
{
self = [super init];
if (self) {
// All initializations, for example:
_Name = Name;
}
return self;
}
/*************************** Another Constructor *************************************/
- (id) initWithName:(NSString*) Name AndAge: (int) Age
{
self = [super init];
if (self) {
// All initializations, for example:
_Name = Name;
_Age = Age;
}
return self;
}

Related

How to correctly implement subclass constructor in Objective-C

I have a base class who's constructor sets the objects state given some external data:
#implementation XMlContent
- (id)initWithParser:(NSXMLParser *)xmlParser {
self = [super init];
if (self) {
if(xmlParser != nil){
_documentFormat = #"xml";
_xmlParser = xmlParser;
xmlParser.delegate = self;
} else{
return nil;
}
}
return self; }
I have a subclass of this object and I have overridden this constructor like so (probably wrong):
#implementation AtomContent
- (id)initWithParser:(NSXMLParser *)xmlParser
{
self = [super init];
if (self) {
if(xmlParser != nil){
self.xmlParser = xmlParser;
self.xmlParser.delegate = self;
self.documentFormat = #"atom";
} else{
return nil;
}
}
return self;
}
The issue I have is that when creating an instance of the subclass (AtomContent in this case) I get back an instance of the superclass and thus superclass methods are called rather than those in the subclass. Looking at my subclass constructor its obvious why. My question is how do I property implement the subclass constructor so the super class is init'd but references to 'self' are to the subclass? Should I not override the constructor but rather use setters to set object state?
Corrections
I get back an instance of the superclass and thus superclass
-No. Specifically my issue is that base class implementation is used (the NSXMLParser delegate methods) rather than the subclass'. I am, indeed, returned an instance of the subclass.
constructor
-Yeah ok.. "Initializer"
Thanks!
You're not calling the designated initializer from your subclass initializer, which causes you to need to repeat a lot of work in the subclass's initWithXMLParser: implementation. Here's how I'd do it:
// Superclass
- (id)initWithParser:(NSXMLParser *)xmlParser {
self = [super init];
if (self) {
if(xmlParser != nil) {
_documentFormat = #"xml";
_xmlParser = xmlParser;
xmlParser.delegate = self;
}
else {
return nil;
}
}
return self;
}
// Subclass
- (id)initWithParser:(NSXMLParser *)xmlParser
{
self = [super initWithParser:xmlParser];
if (self) {
self.documentFormat = #"atom";
}
return self;
}
I should add that if you are truly getting an instance of the superclass returned, then your problem would be in allocation, not initialization, as the isa pointer and hence the method lookup tables are set inside alloc and thus are set at the time init is called. I would rate the chance of that being your problem in actuality as being low.

How to copy superclass properties to a subclass?

Let's say I have two Classes like so:
Car
{
NSInteger wheels;
NSInteger bumpers;
}
+ (Car *)carWithData:(NSDictionary *)carData;
Lexus : Car
{
GPS *navigation;
}
+ (Lexus *)carWithData:(NSDictionary *)carData;
carWithData: is a simple helper method that creates an instance of Car populated with variables from carData. Lexus' version would also set the navigation data.
How would Lexus' carWithData look like without duplicating code from Car?
This is accomplished by calling super's implementation of init… in the init method:
//Car.m:
- (id)initWithData:(NSDictionary *)carData {
self = [super init];
if (self) {
//setup generic car properties:
self.wheels = [carData objectForKey:#"wheels"]; //example
self.bumpers = [carData objectForKey:#"bumpers"]; //example
}
return self;
}
+ (id)carWithData:(NSDictionary *)carData {
return [[[self alloc] initWithData:carData] autorelease];
}
//Lexus.m:
- (id)initWithData:(NSDictionary *)carData {
//this call to super is where the car's generic properties get initialized:
self = [super initWithWithData:carData];
if (self) {
//setup lexus car properties:
self.navigation = [carData objectForKey:#"navigation"]; //example
}
return self;
}
//there is no need to override super's [carWithData:] method as it's only a wrapper anyway.
Also note that both the initWith… and carWith… methods return id, not Car or Lexus.
The way your code is set up you end up with casting problems, where [Lexus carWithData:dataDict] does return an object of class Lexus, but the compiler doesn't know about it, as it expects a Car.
You would not define the methods with different signatures like:
+ (Car *)carWithData:(NSDictionary *)carData;
+ (Lexus *)carWithData:(NSDictionary *)carData;
you should instead use
+ (id)carWithData:(NSDictionary *)carData;
The implementation of the subclass would then look like
- (id)initWithData:(NSDictionary *)carData;
{
self = [super initWithData:carData];
if (self) {
_navigation = [carData valueForKey:#"navigation"];
}
return self;
}
+ (id)carWithData:(NSDictionary *)carData;
{
return [[[self alloc] initWithCarData:carData] autorelease];
}
Here would be my solution:
// interface
-(id) initWithCarData:(NSDictionary *) carData;
+(Car *) carWithCarData:(NSDictionary *) carData;
// car implementation
-(id) initWithCarData:(NSDictionary *) carData
{
if (self = [super init])
{
// initialize car data
}
return self;
}
+(Car *) carWithCarData:(NSDictionary *) carData
{
// note that 'self' here is the current class,
// there is no need to overwrite this method in the subclass
return [[self alloc] initWithCarData:carData];
}
// lexus implementation
-(id) initWithCarData:(NSDictionary *) carData
{
// initialize the variables that the superclass recognizes
if (self = [super initWithCarData:carData])
{
// initialize the lexus data
}
return self;
}
So, when you call [Lexus carWithCarData:myData] it ends up calling the Lexus's init method, not the Car's.
There's another way, which is more generic, by using the NSCoding protocol and NSKeyedArchiver.
If the object you want to copy into a subclass of yours implements the NSCoding protocol, which is the case for many NS... based classes, the following totally legal and safe trick can be used:
// Assumptions:
// copyFrom is an object of ClassA
// We have a ClassB that is a subclass of ClassA
NSMutableData *data = [NSMutableData data];
NSKeyedArchiver *arch = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
[copyFrom encodeWithCoder:arch]; // this archives its properties
[arch finishEncoding];
NSKeyedUnarchiver *ua = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
ClassB *ourCopy = [[ClassB alloc] initWithCoder:ua]; // this restores the properties into our new object

Overriding the init method in a subclass and calling [super initWith:bla], correct way?

I'm subclassing a class.
I'm overriding a init method. This one: -(id)initWithSomething:(Something*)somet;
this would look like this (in the subclass)
-(id)initWithSomething:(Something *)somet with:(int)i{
if (self = [super init]) {
//do something
}
return self;
}
But now I want to call the init in the superclass too.
How would I now do this? Mayby this way?
-(id)initWithSomething:(Something *)somet with:(int)i{
if (self = [super init]) {
}
[super initWithSomething:somet];
return self;
}
Typically like this:
-(id)initWithTarget:(CCNode *)someTarget
{
self = [super initWithTarget:someTarget];
if (self)
{
}
return self;
}
It's the responsibility of super to call the vanilla init selector if it needs to.
-(id)initWithSomething:(Something *)somet {
if ((self = [super initWithSomething:somet])) {
// ...
}
return self;
}
One-and-only-one method should be your "designated initializer" for a class. All other initializers should call that one, and the designated initializer should call super's designated initializer. (This is a general rule; there are a few exceptions such as in initWithCoder:, but it is the normal approach.)

Memory Leak in initWithFrame

i use a UIView subclass with an NSMutableArray of other Views to indicate values as bars.
I init it in my initWithFrame. The Instruments tells after a few create and remove of my UIView subclass that there is a leak on the alloc of the NSMutableArray.
Thats why i framed it with the if to avoid multiple objects. But doesn't help
- (id) initWithFrame :(CGRect)frame
{
self = [super initWithFrame:frame];
if (self.uiValueSubviews == nil){
self.uiValueSubviews = [[NSMutableArray alloc]init];
}
return self;
}
- (void)dealloc {
[self.uiValueSubviews release];
[super dealloc];
}
Am i doing something wrong with the dealloc?
Thanks for your Help
Two problems I see with memory management involving your property.
Properties should always be set to
an autoreleased object or an
object you will be releasing on your
own.
Never send release directly to a property. I prefer to release underlying variable if possible (ex. [_uiValueSubviews release];)
Change the code to the following.
- (id) initWithFrame :(CGRect)frame
{
self = [super initWithFrame:frame];
if (self.uiValueSubviews == nil){
//Set to autoreleased array
self.uiValueSubviews = [NSMutableArray array];
}
return self;
}
- (void)dealloc {
//nil the value
self.uiValueSubviews = nil;
[super dealloc];
}
You should do like this :
- (id) initWithFrame :(CGRect)frame
{
if ((self = [super initWithFrame:frame]))
{
if (self.uiValueSubviews == nil){
uiValueSubviews = [[NSMutableArray alloc]init];
}
return self;
}
- (void)dealloc
{
self.uiValueSubviews = nil;
[super dealloc];
}
You uiValueSubviews is probably a retain property so when you alloc, your retainCount is +1 and self. +1 too.
An other way, avoiding autoreleased objects, would be:
// ...
if (self.uiValueSubviews == nil)
{
NSMutableArray *uiValueSubviews_tmp = [[NSMutableArray alloc] init];
// maybe do something with uiValueSubviews_tmp
self.uiValueSubviews = uiValueSubviews_tmp;
[uiValueSubviews_tmp release];
}
// ....
As far as I know, that's how Apple does it in their examples.

When to release a class with delegates

A quick question to delegates. Lets say, CLASSA has a delegate defined:
#protocol MyDelegate
-(void) didFinishUploading;
#end
In CLASSB I create an instance of CLASS A
-(void) doPost {
CLASSA *uploader = [[CLASSA alloc] init];
uploader.delegate = self; // this means CLASSB has to implement the delegate
uploader.post;
}
and also in CLASSB:
-(void)didFinishUploding {
}
So when do I have to release the uploader? Because when I release it in doPost, it is not valid anymore in didFinishUploading.
Thanks
Release it in didFinishUploding. Put CLASSA * uploader in the instance variables of CLASSB to allow for that.
Instead of creating CLASSA instance in doPost method.
It is better to create CLASSA *uploader = [[CLASSA alloc] init]; in the init method and release uploader in dealloc.
make uploader as member variable.
-(id) init
{
self = [super init];
if(self)
{
uploader = [[CLASSA alloc] init];
uploader.delegate = self;
}
retrurn self;
}
-(void) doPost
{
uploader.post;
}
-(void)didFinishUploding
{
uploader.delegate = nil;
//your code
}
-(void) dealloc
{
[uploader release];
[super dealloc];
}