Dedicated Initializer in Objective-C - objective-c

I am newbie to Objective-C. I have a 'XYZPerson' Class with attributes {firstName, lastName, dateOfBirth} and I want when I write "XYZPerson *person=[[XYZPerson alloc] init]" in main, it should call my overridden 'init' method which should in-turn call my designated initializer and initializes my object with the defined values.
My Code snippets. http://pastebin.com/FfxNDDhf
#import <Foundation/Foundation.h>
#import "XYZShoutingPerson.h"
int main(int argc, const char * argv[])
{
#autoreleasepool {
XYZPerson *person=[[XYZPerson alloc] init];
if(person) {
[person sayHello];
}
else {
NSLog(#"Person Object is NULL");
}
}
return 0;
}
-(id)init
{
self=[super init];
return [self initWithFirstName:#"Ankit" LastName:#"Sehra" DOB:01/01/2000];
}
-(id)initWithFirstName:(NSString *)aFirstName LastName:(NSString *)aLastName DOB:(NSDate *)aDateOfBirth
{
_firstName=aFirstName;
_lastName=aLastName;
_dateOfBirth=aDateOfBirth;
}
-(void)sayHello;
{
NSLog(#"%# %# %#",self.firstName,self.lastName,self.dateOfBirth);
}
Write now the output of the program is "Person Object is NULL", I want it to print the firstName, lastName and DOB.

If a class has several init methods, one of them is the "designated initializer".
This is the one that calls [super initXXX]. In your example, initWithFirstName:LastName:DOB: would be the designated initializer and should look like
this:
-(id)initWithFirstName:(NSString *)aFirstName LastName:(NSString *)aLastName DOB:(NSString *)aDateOfBirth
{
self = [super init];
if (self) {
_firstName=aFirstName;
_lastName=aLastName;
_dateOfBirth=aDateOfBirth;
}
return self;
}
(I have changed the type of the dateOfBirth property and the DOB argument to NSString and will explain that later.)
All other init methods just call the designated initializer (and not [super initXXX]), in your example init:
-(id)init
{
return [self initWithFirstName:#"Ankit" LastName:#"Sehra" DOB:#"01/01/2000"];
}
Note that (among several other errors), "01/01/2000" is not a NSDate, so
return [self initWithFirstName:#"Ankit" LastName:#"Sehra" DOB:01/01/2000];
does not make any sense. Therefore, to get a first working example for you, I have
changed the argument type to NSString.

I'd bet the compiler is giving you plenty of warnings on that code. You should fix them. If it isn't, your compiler isn't tuned correctly.
First, your designated initializer doesn't return anything.
Secondly, there is no reason to override init and call your designated initializer. Simply do:
foo = [[Person alloc] initWithFirstName:#"bob" lastName:#"dobbs"];

Related

Obj-C Variable Stack Type

As a foray into new programming languages, I build well known data structures to familiarize myself with the syntax and the basic ins & outs of the language. In this case, I examine the stack in Objective-C. From Apple's Working with Objects we read about the keyword 'id'
...This is a special keyword used in Objective-C to mean “some kind of object.” It is a pointer to an object, like (NSObject *), but is special in that it doesn’t use an asterisk.
By using the keyword 'id', it seems possible to create a stack data structure that holds differing types of Obj-C objects; however, I am not sure if this as intended. Is it better to create the various class methods for each potential data type rather than attempting a generic method and make sure each stack adheres to a single Object type?. Here is what I have so far
XYZNode.h
#import <Foundation/Foundation.h>
#interface XYZNode : NSObject
#property id value;
#property XYZNode *next;
-(instancetype)initWithValue:(id)aValue next:(XYZNode *)aNext;
-(instancetype)init;
// Class factory methods should always start with the name of
// the class (without the prefix) that they create, with the
// exception of subclasses of classes with existing factory methods.
+(XYZNode *)nodeWithValue:(id)aValue nextNode:(XYZNode *)aNext;
#end
XYZNode.m
#import "XYZNode.h"
#implementation XYZNode
-(instancetype)initWithValue:(id)aValue next:(XYZNode *)aNext {
if (self = [super init]) {
_value = aValue;
_next = aNext;
} return self;
}
-(instancetype)init {
return [self initWithValue:nil next:nil];
}
+(XYZNode *)nodeWithValue:(id)aValue nextNode:(XYZNode *)aNext {
return [[self alloc] initWithValue:aValue next:aNext];
}
#end
XYZStack.h
#import <Foundation/Foundation.h>
#interface XYZStack : NSObject
-(void)pushValue:(id)aValue;
-(id)popValue;
-(BOOL)isEmpty;
-(instancetype)init;
-(instancetype)initWithValue:(id)aValue;
+(XYZStack *)stackWithValue:(id)aValue;
#end
XYZStack.m
#import "XYZStack.h"
#import "XYZNode.h"
// The extension hides how the values are stored
#interface XYZStack ()
#property XYZNode *lastNodeAdded;
#end
#implementation XYZStack
// Default initializer
-(instancetype)initWithValue:(id)aValue {
if (self = [super init]) {
_lastNodeAdded = nil;
}
if (aValue) {
[self pushValue:aValue];
}
return self;
}
// Call default initializer
-(instancetype)init{
return [self initWithValue:nil];
}
-(BOOL)isEmpty{
return ([self lastNodeAdded] == nil);
}
-(void)pushValue:(id)aValue {
[self setLastNodeAdded:[XYZNode nodeWithValue:aValue nextNode:[self lastNodeAdded]]];
}
-(id)popValue {
id temp = [[self lastNodeAdded] value];
[self setLastNodeAdded:[[self lastNodeAdded] next]];
return temp;
}
+(XYZStack *)stackWithValue:(id)aValue {
return [[self alloc] initWithValue:aValue];
}
#end
Any comments would be appreciated.

NSObject can not access property and method

I have a very strange problem, I have two classes the first one is a sub class of NSObject class it contains a method that add an object to its array. See the code below:
#import "portfolio.h"
#implementation portfolio
-(void) addStockObject:(stockHolding *)stock
{
[self.stocks addObject:stock ];
}
+(portfolio *) alloc
{
return [self.superclass alloc];
}
-(portfolio *) init
{
self.stocks=[[NSMutableArray alloc]init];
return self;
}
-(NSString *)getCurrentValue
{
stockHolding *stockInArray;
float currentValue=0.0;
for (NSInteger *i=0; i<[self.stocks count]; i++) {
stockInArray = [self.stocks objectAtIndex:i];
currentValue+=stockInArray.currentValue;
}
return [NSString stringWithFormat:#"Current Value: %f",currentValue];
}
#end
so when i call the method -(void) addStockObject:(stockHolding *)stock, i get the following error(during runtime):
Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: '-[NSObject addStockObject:]: unrecognized selector
sent to instance 0x8b48d90'
The calling code is:
p=[[portfolio alloc]init];
[p addStockObject:s];
portfolio *p;
anyone can tell me what is wrong?
the other class has a property and it seems that it can not access it during compile time.
I'm really confused.
Thank you,
missa
First, never override +(portfolio *) alloc.
Second, init methods must call another init method and you must always check self for nil before setting ivars. Apple recommends against using properties to set ivars in init methods and init methods should always return instancetype in compilers that support it or id in those that don't.
-(instancetype) init
{
self = [super init];
if (self)
{
_stocks = [[NSMutableArray alloc] init];
}
return self;
}

Why my own Object not populate NSMutableArray property?

Hi i want to implement my own Objects to manage my data, i was trying to make a two classes.
Class Continents that contains a Continent Objects
Here is my implementation:
#implementation OsContinents
#synthesize continentes;
-(id)init{
return [super init];
}
-(NSUInteger)count{
NSLog(#"%u",[continentes count]);
return [continentes count];
}
-(void)add:(OsContinent *)continente{
[continentes addObject:continente];
}
-(OsContinent *)getElementByIndex:(NSUInteger)index{
return [continentes objectAtIndex:index];
}
-(void)deleteContinentByIndex:(NSUInteger)index{
return [continentes removeObjectAtIndex:index];
}
-(void)deleteContinent:(OsContinent *)objContinent{
return [continentes removeObject:objContinent];
}
-(NSMutableArray *)getAll{
return continentes;
}
#end
Next i want to populate *continents Property with "Continent" Objects like this.
OsContinents *continentesCollection = [[OsContinents alloc] init];
for (NSString *strContinente in [data allKeys]) {
OsContinent *con = [[OsContinent alloc] init];
[con setContinente:strContinente];
NSLog(#"%#",[con getContinente]);
[continentesCollection add:con];
}
NSLog(#"%u",[continentesCollection count]);
But allways got ZERO in de count Method.
Note: NSLog(#"%#",[con getContinente]) print de data OK, the Continent Object is OK, the problem is in the "*continentes" inside the Continents Object-
Any Clue?
Your initializer does nothing but initialize the superclass. Use it to set up your own class:
- (id)init
{
self = [super init];
if (self)
{
_continentes = [[NSMutableArray alloc] init];
}
return self;
}
Otherwise, continentes will remain nil. Messaging nil is valid: methods simply don't do anything, and return 0.
If you want to completely hide the underlying mutable array (which is perfectly fine) then don't advertise it in your .h file as a property. Instead, at the beginning of your #implementation, declare a semi-private instance variable:
#implementation OsContinents
{
NSMutableArray *_continentes;
}
I say "semi-private" because you can always use the runtime engine to introspect objects. But it'll be hidden from normal use. If you ever subclass your object, you can always move the instance variable declaration from your #implementation to your #interface so that subclasses can get at it.

How to write an Objective-C convenience constructor

I'm trying to add a convenience constructor to my custom object.
Similar to [NSArray arrayWithArray:]
I know it involves a class method that returns an auto released object. I've been googling around but all I can seem to find is the definition of a convenience constructor but not how to write one.
Let's say you have the following:
#class PotatoPeeler : NSObject
- (instancetype)initWithWidget: (Widget *)w;
#end
Then to add a factory method, you'd change it to this:
#class PotatoPeeler : NSObject
+ (instancetype)potatoPeelerWithWidget: (Widget *)w;
- (instancetype)initWithWidget: (Widget *)w;
#end
And your implementation would simply be:
+ (instancetype)potatoPeelerWithWidget: (Widget *)w {
return [[[self alloc] initWithWidget: w] autorelease];
}
Edit: replaced id with instancetype. They are functionally identical, but the latter provides better hints to the compiler about the method's return type.
Generally my approach is the following: first I create a normal initializer method (instance method), then I create a class method that calls the normal initializer. It seems to me Apple uses the same approach most of the time. An example:
#implementation SomeObject
#synthesize string = _string; // assuming there's an 'string' property in the header
- (id)initWithString:(NSString *)string
{
self = [super init];
if (self)
{
self.string = string;
}
return self;
}
+ (SomeObject *)someObjectWithString:(NSString *)string
{
return [[[SomeObject alloc] initWithString:string] autorelease];
}
- (void)dealloc
{
self.string = nil;
[super dealloc];
}
#end

Singleton not initializing correctly

I have the following code that I am calling using this statement: SQLiteDB *db = [[[SQLiteDB alloc] init] autorelease];
The problem is "sharedSQLiteDB" is not being called, but rather "allocWithZone" is, and therefore "checkIfDatabaseExists" is not being called, which is where the database is created.
I don't understand why... (i.e. what am I doing wrong?)
#import "SQLiteDB.h"
static SQLiteDB *sharedSQLiteDB = nil; // makes this a singleton class
#implementation SQLiteDB
#synthesize searchPaths, documentPath, databasePath, cDatabasePath;
#pragma mark Singleton Methods
+ (SQLiteDB *) sharedSQLiteDB {
if(!sharedSQLiteDB) {
sharedSQLiteDB = [[SQLiteDB alloc] init];
[sharedSQLiteDB checkIfDatabaseExists]; // check to see if d/b exists
}
return sharedSQLiteDB;
}
+(id)allocWithZone:(NSZone *)zone { // makes sure another instance is not allocated
if(!sharedSQLiteDB) {
sharedSQLiteDB = [super allocWithZone:zone];
return sharedSQLiteDB;
}
else {
return nil;
}
}
-(id)copyWithZone:(NSZone *)zone {
return self;
}
-(void) release {
// no-op
}
In the singleton pattern your use pattern should be:
SQLiteDB* db = [SQLiteDB sharedSQLiteDB];
They way you are calling it doesn't fit the singelton pattern. All access should be through your sharedSQLiteDB message.
In other words you shouldn't be initializing via typical Cocoa patterns (SQLiteDB *db = [[[SQLiteDB alloc] init] autorelease]; is incorrect and full of problems) outside the scope of the class.
In a singleton using the default initialization pattern for the language (alloc/init for ObjC or the default constructor for C++) should generate a compile time error message since the constructor/init method should be protected.
See the Wikipedia entry. consult the Design Pattern C++ bible. There is even a version for Cocoa
Good luck.
It isn't executing your + (SQLiteDB *) sharedSQLiteDB method because you're not actually calling that method anywhere.
As you've seen, when you call [[SQLiteDB alloc] init], the allocWithZone method is called.
Change your call to be SQLiteDB *db = [SQLiteDB sharedSQLiteDB], which will call your checkIfDatabaseExists method in this case. However, if [[SQLiteDB alloc] init] is called somewhere else, then the checkIfDatabaseExists method call will still be skipped.
Maybe consider moving the checkIfDatabaseExists method into an init method so that it will be called for both your singleton method and your allocWithZone.
Honestly I don't see any error...
However I post the code I used to create a Singleton. It's from a source that now I don't remember the link... it's not my code.
static DataManager *_instance;
#implementation DataManager
+ (DataManager*)sharedInstance
{
#synchronized(self) {
if (_instance == nil) {
_instance = [[super allocWithZone:NULL] init];
// Allocate/initialize any member variables of the singleton class her
// example
//_instance.member = #"";
}
}
return _instance;
}
#pragma mark Singleton Methods
+ (id)allocWithZone:(NSZone *)zone
{
return [[self sharedInstance]retain];
}
- (id)copyWithZone:(NSZone *)zone
{
return self;
}
- (id)retain
{
return self;
}
- (unsigned)retainCount
{
return NSUIntegerMax; //denotes an object that cannot be released
}
- (void)release
{
//do nothing
}
- (id)autorelease
{
return self;
}
I hope it helps
I highly recommend using the SyntesizeSingleton header file first created by Matt Gallagher.
Find the latest version (that I know about) here:
https://github.com/cjhanson/Objective-C-Optimized-Singleton
It makes creating a singleton dead simple.
Here's an example header:
#import <Foundation/Foundation.h>
#interface Example : NSObject {}
+(Example*)sharedExample;
#end
And the corresponding .m:
#import "FMUser.h"
#import "SynthesizeSingleton.h"
#implementation Example
SYNTHESIZE_SINGLETON_FOR_CLASS(Example);
#end
[Example sharedExample] is created for you. It's pretty sweet.