I want to write some methods in a class so that other classes can call these methods using [instance methodName:Parameter].
If the class is a subclass of UIViewController, I can use initWithNibName to initialize it. But I want to write the methods in an NSObject's subclass, how can I initialize it?
iphony is correct, but he or she doesn't say that you need to write the init method yourself. Your init method should generally look something like this:
- (id) init
{
if (self = [super init])
{
myMember1 = 0; // do your own initialisation here
myMember2 = 0;
}
return self;
}
Although the apple documentation says
The init method defined in the NSObject class does no initialization; it simply returns self.
and one can just be tempted to write
- (id) init
{
myMember1 = 0; // do your own initialisation here
myMember2 = 0;
return self;
}
this is WRONG and not following what is explicitly stated in documentation:
In a custom implementation of this (init) method, you must invoke super’s
designated initializer then initialize and return the new object.
MUST. Not should, could, ought to, etc.
You should not assume NSObject's init does not change in future; nor the superclass from which your custom class derives.
I find this may work:
TheClass *newObject = [[TheClass alloc] init];
//do something here
[newObject release];
Related
In Swift, super's initializer should be called after all properties of the current class have been initialized. This is however not done for Objective-C init, where super init is called first before initializing properties in the current class.
What issues is Swift trying to prevent by enforcing this? Why is Objective-C able to avoid the issues Swift is trying to prevent?
What issues is Swift trying to prevent by enforcing this?
This is a great question, and Objective-C did not avoid it.
The problem is that while you're inside an initializer method, the object is technically in a partially constructed state. Bryan's post is a great (albeit contrived) example of why. The general issue is that if a super class's initializer invokes a method, a subclass may have overridden this method. That, in and of itself, is not a bad thing. The problem arises if the overridden method assumes that the object is totally constructed.
However, since the object is still in the midst of invoking the initializers, that is not the case. The object is not wholly constructed until the call to [super init] returns and the class of the object executes any of its initialization code.
There's a related problem with dealloc methods: if you invoke methods inside your -dealloc method, those methods may assume that the object is wholly constructed, when in fact it may be partially deconstructed. This isn't as big of a deal under ARC, but it can still lead to some very subtle bugs.
With Swift, the decision was made to avoid these class of problems by enforcing this rule:
By the time you decide to call super, the calling class must have finished any class-specific initialization.
A variant of this rule is:
You may not invoke methods until after you have called super's initializer.
With this rule, you will never run into the problem described above.
ObjC does not avoid anything.
For this ObjC code, it crashed because parent class is trying to access ivar from child class. It can be detected/avoid if the Swift rule is used. i.e. initialize all members before [super init]
#interface Parent : NSObject
#property (readonly) int value;
#end
#implementation Parent
- (id)init {
self = [super init];
if (self) {
NSLog(#"%d", self.value); // call a method, which can be overrided by child class
}
return self;
}
- (int)value {
return 42;
}
#end
#interface Child : Parent
#end
#implementation Child {
int *_valuePtr;
}
- (id)init {
self = [super init]; // call self.value
if (self) {
// to avoid crash, move this line before [super init], but it may have other undesired effect. e.g. when [super init] return another instance
_valuePtr = calloc(sizeof(int), 1);
}
return self;
}
- (void)dealloc {
free(_valuePtr);
}
- (int)value {
return *_valuePtr;
}
- (void)setValue:(int)value {
*_valuePtr = value;
}
#end
I have a singleton class which is allocation object only one time in whole project. Few code line is below..
declaration...
....
MyClassName *classObject = nil
In the init method, the code is like below..
-(id) init(){
self = [super init];
if(classObject == nil){
1. Allocate object code here
2. classObject = self;
3. return classObject
} else {
return classObject;
}
}
But my problem is that how will I dealloc this object. I am calling this init method from all the class and it is returning classObject reference every time.
My approach....
From the dealloc method in appdelegate.m, I am calling a function (releaseObject)which is defined in MyClassName . Here is the definition of function body...
-(void) releaseObject {
[self release]; // Confusion: Will it dealloc classObject reference?
[super release];
}
Is this good idea dealloc this object? My problem is that I don't have to dealloc object until application is not being closed.
The answer is don't bother ever to release the singleton. It is supposed to last the lifetime of the application anyway and will go away automatically along with everything else when the process terminates. You may find that the dealloc method on your app delegate never gets called for the same reason.
If you have clean up to do on application close, it's probably better to move that into a separate method and just call that when the application is about to terminate.
a simpler pattern for a singleton IMO is to have a class method to return the singleton instance and not mess about with releasing stuff in init.
+(MyClass*) sharedInstance
{
static MyClass* theInstance = nil;
static dispatch_once_t pred;
dispatch_once(&pred, ^{ theInstance = [[MyClass alloc] init]});
return theInstance;
}
The above uses dispatch_once to ensure the initialising block only happens once in the lifetime of the application. You can still create other instances by calling init directly but that is advantageous IMO.
I'd recommend to make an extra class method in your singleton:
static MyClassName *classObject = nil;
...
+ (MyClassName *)sharedInstance {
...
}
+ (void)releaseSharedInstance {
[classObject release];
classObject = nil;
}
If your class is a singleton, in AppDelegete dealloc just call
[[YourClass instance] release];
Here is workaround via Objective C++:
class StaticOwner {
private:
id<NSObject> object;
public:
StaticOwner(id<NSObject> obj) { object = [obj retain]; }
~StaticOwner() { [object release]; }
id<NSObject> instance() {return object;}
};
Usage example:
+ (MySingleton*) sharedInstance {
static StaticOwner owner = StaticOwner([[[MySingleton alloc] init] autorelease]);
return owner.instance();
}
I want to save the "dataFilePath" as a static variable so that it can be initialized when first time use "Constants" and no need to instantiate the Class , for example [Constants SDataFilePath]. But the trues is that the init method is not called. How can I do to meet my request? (In Java the construct method will be called the fist time to access the Class).
#implementation Constants
static NSString *dataFilePath;
-(id)init
{
NSLog(#"init!");
if(self = [super init]) {
dataFilePath = [self getDataFilePathWithArg:dbfile];
}
return self;
}
+(NSString *)SDataFilePath {
return dataFilePath;
}
....
#end
Well you could make Constants a singleton. Leave your code how it is and add this method to the .m:
+ (Constants *)sharedConstants
{
static Constants *_sharedConstants = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
_sharedConstants = [[self alloc] init];
});
return _sharedConstants;
}
And the method declaration to the .h:
+ (Constants *)sharedConstants;
Then access your variable like this:
[[Constants sharedConstants] SDataFilePath]
That will force an init the first time you access [Constants sharedConstants] (and only the first time). Also, you'll need to change +(NSString *)SDataFilePath to an instance method, not class method:
-(NSString *)SDataFilePath
This cannot be done this way. Any reason why you want this path to be static? You might want to look into setting dataFilePath with a getter, but no setter and instantiating the class as a singleton. That way you can set the path by some internal method and share the instance as a singleton. See here
I have a class, in that class I have set up a singleton patter and have a method, here is a short example of what it looks like.
#pragma mark Singleton Methods
+ (id)sharedManager {
#synchronized(self) {
if (sharedMyManager == nil)
sharedMyManager = [[self alloc] init];
}
return sharedMyManager;
}
- (id)init {
if (self = [super init]) {
//so some init stuff here
//...
}
-(void)savemethod {
//etc etc
}
I'm wondering if I am to call/initalize the singleton class to be used like so
//set up plist controller class as a singleton so that you dont loose cache numbers etc
EnginePropertiesController *enginePC = [EnginePropertiesController sharedManager];
then later on in the same class where I have initialized the singleton I call the save method...
[enginePC saveMethod];
So what im wondering is saveMethod part of the same instance? I think it is because i am using the same initialization name enginePC.. but would like some clarification on this.
If I'm understanding you, you are correct that saveMethod would be called on the singleton instance. What you name a pointer has no bearing on what it points to.
I created a custom object in Objective-C. Now I want to create a custom initializer. The object has two properties, name and score. So my initializer is as follows:
- (id)initWithName:(NSString *)playerName {
if ((self = [super init])) {
self.name = [playerName retain];
self.score = [NSNumber numberWithInt:0];
}
return self;
}
Am I using retain here properly? Or can I just make it something like self.name = playerName;?
Furthermore, assume I want another initializer, but keep the initWithName:playerName the designated initializer. How would I make the second initializer call the first?
And for the last question, I know I need to override the - (id)init method too. However, what do I do there? Just assign test properties incase the class was initialized with init only?
Thank you!
Am I using retain here properly?
No you are not. You should either use
self.name = playerName;
as you suggested, or (as recommended by Apple)
name = [playerName copy];
It is not recommended to use accessors in -init because subclasses might override them.
Also, note that as NSString implements NSCopying you should use a copy property, not a retain property.
Furthermore, assume I want another initializer, but keep the initWithName:playerName the designated initializer. How would I make the second initializer call the first?
Using -init as an example (because you must override the super class's designated initialiser if your designated initialiser is not the same)
-(id) init
{
return [self initWithName: #"Some default value"];
}
you could keep self.name = playerName; if you have declared name as retained property in .h class and have also #synthesized in .m file.
For the initialization you could put the belwo two line of code in separate method.
-(void) initializeWithName:(NSString*) aName withNumber:(int) aNumber
{
self.name = aName;
self.score = [NSNumber numberWithInt:aNumber];
}
Lets you have three Initialization method.
- (id)initWithName:(NSString *)playerName {
if ((self = [super init])) {
[self initializeWithName:playerName withNumber:0]
}
return self;
}
- (id)initWithNumber:(int*) aNumber {
if ((self = [super init])) {
[self initializeWithName:nil withNumber:aNumber]
}
return self;
}
- (id)init{
if ((self = [super init])) {
[self initializeWithName:nil withNumber:0]
}
return self;
}
For what's it's worth to the rest of us newbies:
In normal languages, can simply define arguments when instantiating the class:
public final class MakeBed {
private var foo:Object;
public var bar:Array;
public function MakeBed(_foo:Object, _bar:Array) {
// Do stuff
foo = _foo;
bar = _bar;
}
}
Then when we want to instantiate the class it's as simple as:
var myBeadMaker:MakeBed = new MakeBed({}, []);
In objc everything is backasswards.
You can create your custom initializer similar to:
// These #properties go into the header.h file
#property (nonatomic, retain) NSString *foo;
#property (nonatomic, retain) NSString *bar;
// This is in your implimentation.m file
- (id) initWithInfo:(NSObject*)foo withBar:(NSArray *)bar {
_foo = foo;
_bar = bar;
}
Objc automatically "synthesizes" the getters and setters and automatically creates a new variable "blindly" using the same _name _but _with _an _underscore in front when you do the #property thing -- it's magic -- bordering on the "almost too helpful" side of things.
Handy for non-newbies, but incredibly confusing for newbies -- just believe that the getter and setter is made and that a _new _var _is _available.
And the clincher that everyone forgets to mention...
When you want to instantiate the class with your custom initializer you do this:
MakeBed myBedMaker = [[MakeBed alloc] initWithInfo:*foo withBar:*bar];