I'm new with objective c for the iphone.
I'm writing a custom class, then, should I write my own +alloc, +init methods?
I believe that: the +alloc will just call [thing alloc]; and the +init will perform something like: [thing setValue:X];
is there a "default" +alloc and +init methods?
if yes, what should I wait for the default +alloc and +init?, let's say i have a NSMutableDictionary*
i.e.
#interface class1 : NSObject {
NSString *test;
NSMutableDictionary *map;
}
thanks
You generally don't need to write your own +alloc method.
For your example, you might have an -init that looks like:
- (id)init {
self = [super init];
if (self) {
map = [[NSMutableDictionary dictionary] retain];
}
return self;
}
Note that you first call the superclass -init, and check that it worked, before initializing your own variables.
You should NEVER override alloc.
As for init, which is an instance method, by the way, yes that would be the place where you'd probably want to set up your variables.
Related
If I have an NSObject subclass which either has no -init method or simply does nothing in -init, is there any difference between an instance created these two ways:
MyClass *instance = [MyClass alloc];
MyClass *instance = [[MyClass alloc] init];
By "does nothing in -init" I mean
- (id)init {
self = [super init];
if (self) {
}
return self;
}
Since NSObject's -init method itself does nothing, I can't see there being any difference, but of course the advice is that you must call -init to properly prepare an object.
Here's the snippet from NSObject's -init method which got me wondering about this:
The init method defined in the NSObject class does no initialization; it simply returns self.
If I have an NSObject subclass which either has no -init method or
simply does nothing in -init, is there any difference between an
instance created these two ways:
MyClass *instance = [MyClass alloc];
MyClass *instance = [[MyClass alloc] init];
Technically, there is no difference.
But that doesn't mean you should use a bare +alloc to ever create an instance for a variety of reasons.
First, it is the principal of the thing. Objective-C coding standards say +alloc should always be followed by -init.
Secondly, it is all about consistency and code maintenance. What happens when you refactor MyClass to be a subclass of some class where the designated initializer is actually critical? A nasty, hard to figure out, bug is what happens.
Of relevance, note that the use of +new has been all but deprecated for a similar reason. It makes refactoring tedious (dammit! gotta break apart THIS call site, too!) and the convenience factor is exceedingly minimal.
No, it's not and you're not doing nothing, you're calling [super init] and that does a lot to initialize your superclasses up until NSObject.
You can do it in theory.
When you want to create an instance, you can do it simply using the alloc method, so this code is perfectly accepted:
NSObject *someObject = [NSObject alloc];
What creates the instance is the alloc method, so you have created an instance of NSObject.
But if you want to use it you have to initialize it, since the NSObject init method is used by a class to make sure its properties have suitable initial values at creation (Apple documentation).
The most important thing done by the init method is to create the self variable, so if you want to use the instance created with the alloc method, you have to init it.
- (id)init {
self = [super init];
if (self) {
// initialize instance variables here
}
return self;
}
Without the initialization method you have only an unusable instance.
alloc allocates a place in memory for the instance of the object to be stored. If you’re using a local variable it is allocated on the stack, while objects (ivars etc) are allocated on the heap.
init initialises the instance of the object and points it to the allocated memory space - this is why you must always call init after alloc.
e.g.
MyClass *instance = [[MyClass alloc] init];
In your instance your init implementation is empty so it can be removed and you can let the superclass handle it. You would override init to set some state on the object itself.
You might want to take some time to read the Apple Documentation on this if you want to brush up.
Calling MyClass *instance = [MyClass alloc]; - will leave you with an invalid object. You need to allocate and initialize every object you create.
If you do it this way, all objects until MYClass will be initialised. MyClass won't though.
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.
I want to know some features about self.
Which context have self variable in class method?
Why self.self allowed in init method?
First:
We have a class ExampleClass
#interface ExampleClass:NSObject
#property (nonatomic,strong) NSString* a;
+(ExampleClass*)createExampleClass;
#end
#implementation ExampleClass
-(id)init{
self = [super init];
if(self){
[self.self init]; #Allowed
[self init]; #Not Allowed ?
}
}
+(ExampleClass*)createExampleClass{
/*do work here*/
NSLog(#"Self: %# \n Class: %#",self,[self class]);
}
#end
In this example we will see something like this:
Self: ExampleClass
Class: ExampleClass
But why?!
And in init method [self.self init] allowed, but not allowed '[self init]'.
Why does this happen?
In a class method, self is the class. For classes [self class] simply returns self, so self and [self class] are basically the same thing there.
Calling [self init] in the init method doesn't make any sense, it would cause an infinite recursion. However, the compiler error you get is a restriction of ARC, if you'd use self = [self init], the error would go away, but it would still make no sense. You might do this in a different initializer method though, to call the designated initializer.
self.self is short for [self self] which does nothing but return self.
self in class method is the class object itself.
NSObject has self method which returns itself.
See here: https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Protocols/NSObject_Protocol/Reference/NSObject.html#//apple_ref/occ/intfm/NSObject/self
Self: ExampleClass // Name of the class.
Class: ExampleClass // Name of the meta-class object which is same with class object.
If you print pointer address, you will see two objects are different.
Here's nice illustration and description.
http://www.sealiesoftware.com/blog/archive/2009/04/14/objc_explain_Classes_and_metaclasses.html
self.self.self.self.self.self is also valid :) or [[self self].self self].self.self
I'm quite a newbie in Objective C, though I have some background in Java reflection.
Here, I have a classic class method findAll that find all the domain objects from the database. The class Univers directly inherits from DomainObject
#interface DomainObject : NSObject
- (NSString *) execute : (NSString*) method withJson:(NSString*)json;
+ (NSString*)findAll: (NSString*)json;
#end
#implementation DomainObject
- (NSString *) execute: (NSString*) method withJson:(NSString*)json{
method = [NSString stringWithFormat:#"%#%#", method, #":"];
//method is 'findAll:'
NSString* result = [ self performSelector:
NSSelectorFromString(method) withObject:json];// Error here
return result;
}
#end
The code was working when findAll was NOT a class method (ie -findAll declaration), but now I have the error : NSInvalidArgumentException -[Univers findAll:]
It clearly seems that the runtime is looking for an instance method.
Any idea to find my class method ?
Instead of calling
NSString* result = [self performSelector:NSSelectorFromString(method) withObject:json];
you need to call
NSString* result = [[self class] performSelector:NSSelectorFromString(method) withObject:json];
for class methods.
After all it's the object instance's class that supposed to be calling the method, not the instance itself.
Short explanation: NSObject implements - (Class)class; (not to be mistaken with + (Class)class of similar effect, which NSObject implements, too!) which returns the Class object of your instance object. Keep in mind that in Objective-C in addition to plain instance objects, Classes are actual objects, too: objects of type Class, that is (vs. id, NSObject, …).
See the documentation for the -class method here.
Btw, you should probably wrap your method call into an conditional block to prevent exceptions caused by calls to missing methods.
SEL selector = NSSelectorFromString(method);
if ([[self class] respondsToSelector:selector]) {
NSString* result = [[self class] performSelector:selector withObject:json];
}
In general it's a common pattern in Objective-C to call an object's class method by receiving the class object via [object class].
Consider this case of a class called Foo implementing a convenience method for returning an autporeleased instance of itself (to be called via: Foo *newFoo = [Foo foo];):
While it would certainly be possible to implement said method like this (after all we know the object's class name, right?):
+ (id)foo {
return [[[Foo alloc] init] autorelease];
}
the correct way is this:
+ (id)foo {
return [[[self alloc] init] autorelease];
}
As the first one would cause problems with polymorphism in subclasses (Such as a subclass called FooBar, for which it should clearly be [FooBar alloc] …, not [Foo alloc] …. Luckily [[self class] alloc] solves this dynamically).
While this is clearly not the right place for a thorough explanation of this (rather offtopic one might say) it's certainly worth noting/warning about, imho.
if header file declares
#interface SomeClass: NSObject {
Data* d;
}
#property (nonatomic, retain) Data* d;
Why is the following line in the implementation file giving me a warning (and init method does not get called?)
[[[self d] alloc] init];
The warning i get is
Instance method '-alloc' not found (return type defaults to 'id')
Meanwhile, Data has
- (id) init method, that is not being called.
Please help me understand why.
alloc should be invoked on a class, not on an instance.
interface SomeClass : NSObject
{
Data *d;
}
Declare an init method on SomeClass and make it look like:
- (id) init
{
self = [super init];
if (self)
{
d = [[Data alloc] init];
}
return self;
}
- (void) dealloc
{
[d release];
[super dealloc];
}
Now you do:
SomeClass *c = [[SomeClass init] alloc];
And you can use the class. Note that you should probably read a little more on classes and objects and about memory management too (when you should release c, etc.).
If, by any chance, you have the possibility to use ARC (automatic reference counting), you won't need to take care of releasing stuff. But that doesn't come with Xcode 4.1, only with 4.2 which is not publicly accessible, apparently.
The problem isn't -(id)init, it's -(id)alloc. alloc is a class method of NSObject, which means you send it to the class itself and not to an instance of that class, i.e.:
[Data alloc]; // Correct
[someDataInstance alloc]; // Method not found
When you call [self d], you're given an instance of a Data, which you're then sending a -(id)alloc message to. Since NSObject doesn't have a -(id)alloc (only a +(id)alloc), you get the warning.
You should be doing
self.d = [[Data alloc] init];
As Matt says, alloc is a class method, and must be called on the class itself.