Briefly, I have a class implementation:
#implementation ClassB: ClassA
-(id) init {
if (self = [super init]) {
...
}
return self;
}
#end
And a category, in two variants:
1:
#implementation ClassA (ClassA_Category)
+(id) alloc {
if ([self isEqual: [ClassA class]]) {
return [ClassB alloc];
} else {
return [super alloc];
}
}
#end
2:
#implementation ClassA (ClassA_Category)
+(id) alloc {
return [[ClassB superclass] superclass] alloc];
}
#end
The question is about this simple initialization:
ClassA *aObj = [[ClassA alloc] init];
For the first category variant, init of ClassB is called, but for the second case - doesn't.
Why ? Does these two alloc constructions have the same meaning ?
[[ClassB superclass] superclass] will be ClassA's superclass (probably NSObject — I'm going to assume so for the rest of this answer). So the second variant is specifically equivalent to [NSObject alloc]. This means the object that you send init to is just an NSObject, not a ClassA or a ClassB.
In the first variant, [ClassB alloc] executes ClassA's implementation (through inheritance), which calls [super alloc] in cases where the class is not ClassA (which ClassB isn't), which executes the default implementation of alloc. This allocates a ClassB, which is then sent init.
I think your confusion is caused by the assumption that [[self superclass] theCurrentMethod] is equivalent to [super theCurrentMethod]. It's not. The super keyword keeps the receiver (self) the same, but just skips over the current class when resolving that message to a particular implementation. But when you explicitly send a message to [self superclass], the superclass itself is the receiver.
Related
I am getting an issue cannot init a class object even after adding lines to the constructor such as
self = [super init];
or
self = [[super init] alloc];
And I am not sure what to do.
This is the specific error:
file:///%3Cunknown%3E: test failure: -[LinkedListTest testAdd] failed: *** +[NList<0x8e14> init]: cannot init a class object.
.m
#interface NList()
#property (weak, nonatomic, readwrite) NSObject *head;
#property (nonatomic,readwrite) NSInteger *size;
#end
#implementation NList
#synthesize size = _size;
- (id) init:(NSInteger *)size {
//is this even necessary? I don't want object methods.. or do I ?
if (self){
_head = nil;
_size = size;
}
return self;
}
.h
#interface NList : NSObject
#property (nonatomic,readonly) NSInteger *size;
#property (weak, readonly, nonatomic) NSObject *head;
- (void)add:(NSObject *)node;
#end
test class
- (void)testAdd
{
NList *testList = [[NList init] alloc];
// Card *testCardOne = [[Card init] alloc];
// [testList add:(testCardOne)];
XCTAssertNotNil(testList.head);
}
I have tried adding the line
self = [[super init] alloc];
to the constructor to no avail.
No visible interfacce for nlist declares
or self = [super init]
complains cannot init a class object!
EDIT
I realized that it is not asking me for the size! the constructor requires a size parameter...how do I do this! Ahh [looks up docs]
A few things.
You need a default constructor
- (id)init {
self = [super init];
if (self) {
self.head = nil;
}
return self;
}
Now that you have a default constructor (that calls the superclasses constructor), you need a more specific one for your purposes.
- (id)initWithSize:(int)size {
self = [self init]; // sets head, calls super constructor.
if (self) {
self.size = size;
}
return self;
}
Edit: Note, the last one had to be in your .h file so it is visible.
And also, when instantiating this class, call
NList *list = [[NList alloc] initWithSize:mySize];
You're a little backwards.
How about:
NList *testList = [[NList alloc] init:SIZE];
where size is the SIZE init you want to use.
Alloc comes before init when you're instantiating Objective-C objects.
I have seen in the BNR 3rd edition an example to do a static singleton class.
To do that, they explain how to avoid a creation cycle calling the superclass alloc:
static MyClass *myclass = [[super alloc] init];
MyClass has its own init method.
NSObject -> MyClass
My doubt is: Which init class is sent? NSOject init, or MyClass init
Nested alloc init equals:
myclass = [super alloc] and then
myclass = [myclass init] ???????????
OR
myclass = [super alloc] and then myclass = [super init]
Do not use super, but do use self. Otherwise subclassing of your singleton will not work. The correct way is something like this:
+ (MyClass *)sharedInstance {
static MyClass *instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[self alloc] init];
});
return instance;
}
dispatch_once guarantees that your code (block in this case) is called only once. And self guarantees that subclassing will work properly.
for you question, the selector is always called on the subclass's implementation, which is your first guess
the way described in the book is a valid way to implement singleton, but i do not suggest it though. Robert Vojta's solution is good.
i cannot see how necessary to override allocWithZone, then you also need to make sure init does nothing (at least not leak)
Just for add some tests:
I have created 2 MyClass classes: NSObject -> Myclass -> My2ndClass
So:
#implementation Myclass
+(id) sharedClass {
static Myclass *miclase = nil;
miclase = [[self alloc] init];
NSLog(#"%#", [super description]);
return miclase;
}
-(id)init {
self = [super init];
NSLog(#"init de Myclass");
return self;
}
-(NSString *)description {
return #"i am Myclass";
}
#end
AND:
#implementation My2ndClass
+(id) sharedClass {
static My2ndClass *miclase = nil;
miclase = [[super alloc] init];
//miclase = [super init]; CRASH
NSLog(#"%#", [super description]);
return miclase;
}
-(id)init {
self = [super init];
NSLog(#"init de My2ndClass");
NSLog(#"%#", [super description]);
return self;
}
-(NSString *)description {
return #"i am My2ndClass";
}
#end
Then in AppDelegate:
Myclass *miclase = [Myclass sharedClass];
My2ndClass *mi2ndclase = [My2ndClass sharedClass];
This is the console output:
2012-09-03 17:18:55.742 Dynamic Typing[2891:207] init de Myclass
2012-09-03 17:18:55.744 Dynamic Typing[2891:207] Myclass
2012-09-03 17:18:55.746 Dynamic Typing[2891:207] init de Myclass
2012-09-03 17:18:55.747 Dynamic Typing[2891:207] init de My2ndClass
2012-09-03 17:18:55.748 Dynamic Typing[2891:207] i am Myclass
2012-09-03 17:18:55.751 Dynamic Typing[2891:207] My2ndClass
Like xlc0212 told, the correct messages when they are nested are:
miclase = [super alloc];
miclase = [miclase init];
Besides, if i do
miclase = [super alloc]
and then
miclase = [super init]
it CRASHES.
When is sent a class method (+) [super description], it logs class name (Myclass and My2ndClass). They are de class itself and don't have super object, do they?
I have this hierarchy:
CreateAnObjectClass : NSObject
MySecondClass : MyBaseClass
MyBaseClass : NSObject
in CreateAnObjectClass I want to create an instance of MySecondClass method and i want to pass a #property (strong,nonatomic) NSDictionary* myTemplate to myBaseClass.
For example:
CreateAnObjectClass *testObj = [[MySecondClass alloc] initWithTemplate:myTemplate];
And I know that calls both initializers from MyBaseClass and MySecondClass.
(id)initWithTemplate:(NSDictionary*)myTemplate
{
self = [super init]
return self;
}
My question is how I should designe initializers to myTamplate can be a property at MyBaseClass?
Like this:
- (id)initWithTemplate:(NSDictionary*)aTemplate
{
self = [super init]
if (self){
self.myTemplate=aTemplate;
}
return self;
}
Edit 1:
Remember the following, calling this:
self = [super init];
On the MySecondClass will call the init method on the MyBaseClass
I have a class with initialization as follows:
#implementation MyClass
+(id) initializeMyClass
{
return [[[self alloc] initMyClass] autorelease];
}
-(id) initMyClass
{
if (([self = [super init]))
{
}
return self;
}
-(void) dealloc
{
NSLog(#"Deallocating");//I also used CCLOG instead.
[super dealloc];
}
#end
I initialize this class in another class without an object:
[MyClass initializeMyClass];
This works fine but the MyClass' dealloc method is not called and crashes since some resources are not freed.
This is totally puzzling and can't find anything online.
If anyone would suggest a solution or an alternative method, i'd really appreciate it.
Thank you.
if you need to initialize your MyClass into another class then you should write like
#implementation MyClass
+(id) initializeMyClass
{
return [[[self alloc] initMyClass] retain];
}
-(id) initMyClass
{
if (([self = [super init]))
{
}
return self;
}
-(void) dealloc
{
NSLog(#"Deallocating");//I also used CCLOG instead.
[super dealloc];
}
#end
I have a very simple Person class that has a ivar called name ( an NSString). When I try to release this ivar in dealloc the static analyzer gives me a weird error:
Incorrect decrement of the reference
count of an object that is not owned
at this point by the caller
What am I doing wrong?
BTW, here's my code:
#interface Person : NSObject {
}
#property (copy) NSString *name;
#property float expectedRaise;
#end
#implementation Person
#synthesize name, expectedRaise;
-(id) init {
if ([super init]) {
[self setName:#"Joe Doe"];
[self setExpectedRaise:5.0];
return self;
}else {
return nil;
}
}
-(void) dealloc{
[[self name] release]; // here is where I get the error
[super dealloc];
}
#end
You're releasing an object returned from a property getter method, which in many cases would be the indication of a possible bug. That's why the static analysis is picking it up.
Instead, use:
self.name = nil;
or:
[name release];
name = nil;