Designated initializer and passing arguments - objective-c

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

Related

No known class method for selector 'initWith...'

I found similar questions, but I couldn't solve my error. My error is:
No known class method for selector 'initWithUrl:sub:cont:cat:dat'
I've tried
#Synthesize,
self.variableName instead of _variableName,
adding [[MyClass init] alloc],
changing - to +
How can I fix it?
MyClass.h:
#import <Foundation/Foundation.h>
#interface MyClass : NSObject
-(id)init;
-(id)initWithURL:(NSURL *)url_ sub:(NSString *)subject_ cont:(NSString *)content_ cat:(NSString *)category_ dat:(NSString *)date_;
#property NSURL *bannerImageURL;
#property NSString *subject;
#property NSString *content;
#property NSString *category;
#property NSString *date;
#end
MyClass.m:
#import "MyClass.h"
#implementation MyClass
-(id)init {
self = [super init];
if (self) {
_bannerImageURL = [NSURL URLWithString:#"url0"];
_subject = #"sub0";
_content = #"cont0";
_category = #"cat0";
_date = #"dat0";
}
return self;
}
-(id)initWithURL:(NSURL *)url_ sub:(NSString *)subject_ cont:(NSString *)content_ cat:(NSString *)category_ dat:(NSString *)date_ {
self = [super init];
if (self) {
_bannerImageURL = url_;
_subject = subject_;
_content = content_;
_category = category_;
_date = date_;
}
return self;
}
#end
myViewController.m:
#import "myViewController.h"
#import "MyClass.h"
#implementation SimpleTableViewController
MyClass *news1;
- (void)viewDidLoad {
[super viewDidLoad];
NSURL *aUrl = [NSURL URLWithString:#"aUrl"];
// Error occurs here.
news1 = [MyClass initWithURL:aUrl sub:#"aSub" cont:#"aCont" cat:#"aCat" dat:#"aDat"];
}
I think you mean:
news1 = [[MyClass alloc] initWithURL:aUrl sub:#"aSub" cont:#"aCont" cat:#"aCat" dat:#"aDat"];
This is a standard pattern in Objective-C: call [SomeClass alloc] to create a new instance, then immediately call some initializer method on it. Initializers are instance methods which must be called on an instance of a class, whereas alloc is a class method that is called on the class itself (and which returns a newly allocated instance of that class).

Objective-c : cannot init a class object

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.

Why can't I populate my controller with items?

I'm using an ItemController to provide a list of items to use in a tableview. I can't seem to populate the controller though, and I'm not sure why.
Here's the code for the controller class:
.h
#import <Foundation/Foundation.h>
#class Item;
#interface ItemController : NSObject
#property (nonatomic, copy) NSMutableArray *items;
- (NSUInteger)countOfList;
- (Item*)objectInListAtIndex:(NSUInteger)theIndex;
- (void)addItem:(Item *)item;
#end
.m
#import "ItemController.h"
#import "Item.h"
#interface ItemController ()
#end
#implementation ItemController
- (NSUInteger)countOfList {
return [self.items count];
}
- (Item *)objectInListAtIndex:(NSUInteger)theIndex {
return [self.items objectAtIndex:theIndex];
}
- (void)addItem:(Item *)item {
[self.items addObject:item];
}
#end
Item.m
#implementation Item
-(id)initWithName:(NSString *)name{
self = [super init];
if (self) {
_name = name;
return self;
}
return nil;
}
#end
I'm using the following code to populate the list:
ItemController* controller = [[ItemController alloc] init];
for (NSString* key in raw_data) {
NSLog(key); // This outputs the keys fine
[controller addItem:[[Item alloc] initWithName:key]];
}
NSLog([NSString stringWithFormat:#"%d",[controller countOfList]]); // Always 0
You need to initialize the array in the init methond.
- (id)init {
self = [super init];
if (self) {
self.items = [[NSMutableArray alloc] init];
}
return self;
}
You need to initialize your variable items. In your init method, call self.items = [NSMutableArray new]; and also change your array property from copy to retain.
I also believe your class ItemController should be of kind UIViewController and not NSObject.
#interface ItemController : UIViewController
You don't initialise the _items instance variable anywhere, so it's always nil. The result of any integer-returning method called on nil will be 0, so you see that the count is 0.

Dynamic link / Dynamic typing in objective-c

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?

superclass] construction

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.