Call a method on a class whose instance is owned by another - objective-c

I have two classes, both inherited from NSObject. One is called class1, the other is called class2. They both each have one instance, class1->obj1, and class2->obj2.
In class1's init method, I make the instance of class2. From obj2's init method I want to call the instance method -(void)methode from obj1
How do I do this (what are delegates, could I use one)?

- initWithThingy:(Class1 *)anObj
{
self = [super init];
if (self) {
obj1 = [anObj retain]; // or use your set method/property, if you have one
[obj1 methode];
}
return self;
}

Related

Return object of [super Init]

Well...I have read and have done a lot of research on the expression of [super init] in class inheritance of objective-c. Even some of the questions have been well explained and answered on stackoverflow. However, I still don't really understand how inheritance or the [super init] works.
In other languages, the superclass knows nothing about the subclass. There is no way for the superclass to return an object of the subclass because the superclass has no knowledge of the subclass. So my question is if expression self = [super init] return the object of the SUPERCLASS or SUBCLASS. Here I do know that the [super init] could return another object or nil, which makes sense. But assuming everything works fine and neither is it nil nor return another object. If it returns a regular object, does it return the object of the superclass or derived class, which is the class in which this self = [super init] is defined. If it returns an object of the super class, then it makes sense but then since as we know, the object of the superclass knows nothing about the subclass, how can it access the members (fields, messages or methods) of the subclass. If it returns an object of the subclass, then it does not make sense, since there is no way that the superclass can return an object of the derived class because the superclass knows nothing of it.
This is one of the aspects that is really confusing for those who transition from other languages to objective-C.
self = [super init]
will return the object from the superclass. However, note that the object itself has likely been allocated using alloc on your current class.
Consider the following:
#interface A : NSObject
- (instancetype)init;
#end
#interface B : A
- (instancetype)init;
#end
#implementation B
- (instancetype)init {
self = [super init];
if (self) {
// Do initialization for B
}
return self;
}
#end
When you create a new object of a class B you do as follows:
B *obj = [[B alloc] init];
In turn the following happens:
[B alloc]allocates the object with enough space to hold all of B.
Calls init on the newly created object of class B.
Then init on class A is called from B's init method
init on class A will* return the object allocated with B's alloc.
*) Note that the init method may return another object than the allocated one. This is allowed, and is a reason why you usually should assign the result to self.
Read more - What does it mean when you assign [super init] to self?

Class method successfully called instance method

Everything I know about programming says that instance methods can call class methods, but class methods cannot call instance methods.
This post agrees...
Call instance method from class method
Yet miraculously the class method sharedInstance manages to call instance method init. What am I missing ??
static iRpDatabase *sharedDatabase;
#implementation iRpDatabase
{
}
+(iRpDatabase*)sharedInstance
{
if(sharedDatabase == nil)
{
sharedDatabase = [[self alloc] init];
}
return sharedDatabase;
}
// this is an instance method, called from class method above.
-(id)init
{
if (self = [super init]) {
someInstanceVariable = XYZ;
[self someInstanceMethod];
}
return self;
}
The statement that a class method can't call instance methods means that the class method can't call instance methods on self since self represents the class, not an instance of the class.
In the sharedInstance method you are calling an instance method but it is being called on a specific instance of the class. That's fine.
Think of this example:
+ (void)someClassMethodOfiRpDatabase {
NSString *str = #"Hello";
NSInteger len = [str length]; // look - I called an instance method
}
This example in no different than your sharedInstance method question. It's fine to call instance methods on a specific instance of an object, even if you happen to be in some class method.

Objective-C subclass setup

I have 3 Objective-C classes:
Animal - a subclass of NSObject
Feline - a subclass of Animal
Cat - subclass of Feline
Each of these three classes implement (what I thought was) its own private method (-private_Setup), for setup:
e.g. in Animal:
-(instancetype)init
{
self = [super init];
if (self) {
[self private_Setup];
}
return self;
}
Same thing in the Feline and Cat classes.
A list of required classes is provided at runtime, so I am creating instances of the various classes, depending on a list of class names.
e.g.
NSString *className = ... // #"Animal", #"Feline" or #"Cat".
id animal = [[NSClassFromString(className) alloc] init];
Problem:
If I create an instance of Cat, -private_Setup is being called multiple times, for each step in the inheritance chain. For example, the calling chain for a Cat:
-[Cat init]
-[Feline init]
-[Animal init]
-[Cat private_Setup] // First!
then, from:
-[Feline init]
-[Cat private_Setup] // Second!
then, from:
-[Cat init]
-[Cat private_Setup] // Third!
Thus, what I thought was a method private to each class, is being called after each -init in the hierarchy.
Could someone please advise how I could either fix this issue or redesign my setup strategies? Thankyou.
[edited, appended for clarity]
Some form of setup is required at each level of the inheritance, to supply data particular to that level. e.g. Cat specific settings.
Thus, what I need is for a Cat object to be fully set up as an Animal, as a Feline, and as a Cat.
I guess one approach is to have different setup method names at each level. e.g. setupAnimal, setupFeline, setupCat.
e.g. in Animal:
-(instancetype)init
{
self = [super init];
if (self) {
[self setupAnimal];
}
return self;
}
// in Feline:
-(instancetype)init
{
self = [super init];
if (self) {
[self setupFeline];
}
return self;
}
// in Cat:
-(instancetype)init
{
self = [super init];
if (self) {
[self setupCat];
}
return self;
}
Is there a better, more preferred design than this?
I think you should call private_Setup method just once - in Animal's init. That's all. Implement in all subclasses, call just once in supercalass
You're saying that you need a different form of setup for each subclass. Of course! That's why what you do is you implement private_Setup in every subclass. Implement just like you need it for every particular subclass. It's called overriding. Inside overridden method call [super private_Setup]. You'll get exactly what you need.
You are saying super init and super's init calls private_Setup, so why are you surprised?
I guess you're surprised because you expect each init in the chain to call its own class's private_Setup. But the thing to understand is that meaning of self changes depending on the original class of the instance that started the chain (polymorphism).
So, for example, if you call self private_Setup from Animal's init during the process of initializing a Cat, it is Cat's private_Setup that will be called. Thus, with the arrangement you've made, it is exactly true that on initialization of a Cat, Cat's private_Setup will be called three times and none of the others will be called.
The solution is simple: don't use an extra method. It is a capital mistake to have an initializer call any methods (and the problem you're having is one of the reasons why it's a mistake). Instead, simply perform the setup in init itself. That is what it's for.
If I understand correctly, you are implying that the call to private_Setup happens in all of your subclasses' init methods too.
Remove the call to private_Setup from all but the top (e.g. Animal) init method. As long as all of them call [super init], you'll get exactly one call to private_Setup.

How Class Method can access Instance Method ?

I am from Actionscript Background. In Actionscript Class Method can access only Class Methods and Class properties.
But In Objective C,
How Class method gameResultAll can access Instance Method initFromPlist
+(NSMutableArray *)gameResultAll://Class Method
-(id)initFromPlist:(id)plist;//Instance Method
NSMutableArray *gameResults = [GameResult gameResultAll]; // (returns GameResult array)
Why [self init] method is called instead of [super init] to create an instance from class method.
Thanks in advance.
#import "GameResult.h"
#implementation GameResult
#define GAME_RESULT_KEY #"gameresult_key"
#define SCORE_KEY #"score"
+(NSMutableArray *)gameResultAll
{
NSMutableArray *resultArray = [[NSMutableArray alloc] init];
for (id plist in [[[[NSUserDefaults standardUserDefaults] dictionaryForKey:GAME_RESULT_KEY] mutableCopy] allValues])
{
GameResult *gameResult = [[GameResult alloc] initFromPlist:plist];
[resultArray addObject:gameResult];
}
return resultArray;
}
//Designated initialiser
-(id)initFromPlist:(id)plist
{
self = [self init];
if(self)
{
if([plist isKindOfClass:[NSDictionary class]])
{
NSDictionary *resultDictionary = (NSDictionary*)plist;
_score = (int)resultDictionary[SCORE_KEY];
}
}
return self;
}
You asked:
How Class method gameResultAll can access Instance Method initFromPlist
It can access that method because you used the alloc method, which creates an instance of GameResult. Now that you have an instance, you can use instance methods in conjunction with this instance.
By the way, this is a very common pattern, a "convenience" class method that allocates an instance of an object (with alloc) and initializes the object (with init or some permutation of that). Or, as in this case, it can create an array of these objects.
You then go on to ask:
Why [self init] method is called instead of [super init] to create an instance from class method.
I can understand the confusion, but there is an important, yet subtle distinction in the behavior of these two.
Imagine this scenario:
At some future date, you subclass GameResult, e.g. ArcadeGameResult;
You implemented an init method for ArcadeGameResult that initializes some properties unique to this subclass; and
You happen to initialize a ArcadeGameResult instance like so:
ArcadeGameResult *agr = [[ArcadeGameResult alloc] initFromPlist:plist];
Because the initFromPlist uses [self init], it means that the the initFromPlist method of GameResult will end up calling the init method of the object (which in this example, is actually a ArcadeGameResult object). But if initFromPlist in GameResult called [super init] instead, it would not have called ArcadeGameResult's init method and thus initFromPlist would be problematic if ever used in conjunction with a subclass.
Bottom line, unless the method you're calling is the exact same method signature, it's safer to call the self rendition rather than the super rendition. It's a little more flexible in case you ever decide to subclass in the future.
There is a corollary to the counsel. When calling class methods from an instance method, you should refer to [self class] rather than the class name. So, imagine your GameResult class had a class method:
+ (void)someClassMethod
{
// do something
}
If you had some GameResult instance method that was going to avail itself of this method, you might be tempted to write:
- (void)someInstanceMethod
{
// do some stuff
[GameResult someClassMethod];
}
But that's not a good idea. You would instead use the following:
- (void)someInstanceMethod
{
// do some stuff
[[self class] someClassMethod];
}
They look very similar, but the latter lets you implement a someClassMethod in a subclass, and this instance method will still work. If you use the former construct, the subclassed class method wouldn't be called by someInstanceMethod.
These are subtle issues, and probably not critical for your current code sample. But hopefully it illuminates the choice of [self init] versus [super init] in this situation.
In Actionscript Class Method can access only Class Methods and Class properties.
That's not different in Objective-C either (because nothing else would make sense), so:
How Class method GameResultAll can access Instance Method initFromPlist
Only through a valid instance.
Why [self init] method is called instead of [self super] to create an instance from class method.
Because the latter is a syntax error, perhaps? Read a basic Objective-C tutorial.

Objective-c - what does [super init] return?

New to objective-c. Wrote a code-snippet to better understand the init mechanism, and ended up with a few questions.
#implementation MyClass
-(id) init
{
if (self) {
i = 5;
NSLog(#"self before init - %# %p i=%d",[self className], &self, i);
} else {
NSLog(#"self is null???");
}
id someClass = [super init];
NSLog(#"the result of super-init - %# %p",[someClass className], &someClass);
self = [super init];
if (self) {
NSLog(#"self after init - %# %p %d",[self className], &self, i);
} else {
NSLog(#"self is null???");
}
return self;
}
i is a private instance variable int.
Here is the result:
2012-12-14 18:01:26.403 Init[1621:303] self before init - MyClass 0x7fff5fbff848 i=5
2012-12-14 18:01:26.405 Init[1621:303] the result of super-init - MyClass 0x7fff5fbff838
2012-12-14 18:01:26.405 Init[1621:303] self after init - MyClass 0x7fff5fbff848 5
What really surprised me is that that someClass's class Name is MyClass.
How does NSObject know to return the sub-classes instance (not just the type match, it is the exact same object)?
I'm aware that it is not good form to call init many times, and initialize instance variables before calling init but I was just experimenting.
Thanks.
You do need to use the standard schemen (more or less):
-(id)init {
self = [super init];
if (self) {
// Do initialization stuff
}
}
Your class subclasses some other class. The call to super init runs the init routine of your superclass. Without it your class is not properly initialized and may malfunction strangely. (However, it's probably not wise to call super init twice, as this could have bad side-effects.)
There are cases where you would not call super init, but would instead call a version of init in your own class. Basically, if you have initWithJunk: and init, you can have initWithJunk: call [self init] instead of [super init] so that the stuff that self init would do gets done and doesn't have to be reproduced in initWithJunk:.
This is especially critical if you write a "category" that adds an init... method to an existing class -- you must call some version of [self init] to assure that the base class's initializer runs.
Understand that the super init method is not (usually) replacing the existing instance with a new one, but rather is initializing instance fields in it that belong to the superclass. The reason for receiving the "self" value back from the super init call is two-fold:
The init routine can return a nil in the event that some sort of error occurs.
In some (rare) special cases the init routine may replace the supplied instance with a different one (eg, a cached version).