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
Related
So I'm trying to write an initializer for a subclass of NSOperation. This is my first time using NSOperation. My NSOperation subclass looks like this:
.h
#property (nonatomic, copy) NSString *fileName;
.m
#synthesize fileName = _fileName;
- (id)initWitFileName:(NSString *)fileName {
if (self = [super init]) {
_fileName = fileName;
}
return self;
}
- (void)dealloc {
[_fileName release];
[super dealloc];
}
- (void)main {
// do long task
}
So I thought when I create my own initializers, I should just set the ivar myself since the state of the object is undetermined in the init method. So I don't use the accessor in the initializer. When my main method gets run, I get a memory bad access and a crash. However, in my init method, if I do this instead:
- (id)initWitFileName:(NSString *)fileName {
if (self = [super init]) {
_fileName = [fileName retain];
}
return self;
}
I do not get a crash. What is correct? I'd think in this second case that I wouldn't be releasing the memory since the accessor is (copy). Or is it because I don't use the accessor, that my fileName object basically gets dealloc'd only since there is no +1 in the initWithFileName method? Thanks!
The second one is close, but:
- (id)initWitFileName:(NSString *)fileName
{
if (self = [super init]) {
_fileName = [fileName copy];
}
return self;
}
is more usual since NSString* properties are generally defined with (nonatomic, copy).
This is done to avoid problems or unintended consequences if the caller is actually passing a NSMutableString and later changes the value.
When you #synthesize something with a set of properties, you're generating getters and setters for the object. This allows you to use methods like
[self setFilename:#"MyFile.txt"]
or
self.filename = #"MyFile.txt"
Both of the lines above function in exactly the same way, and might be implemented like this:
- (void)setFilename:(NSString *)string {
_filename = [string copy];
// Or, for a retained property:
// _filename = [string retain];
}
This implementation is overly simplified. See idz's comment below for a better understanding of the logic that a real setter would use.
In your example above, you're simply using the = operator, and not a generated function.
_fileName = fileName;
Because of this, you're simply setting the address of _fileName to fileName. None of your synthesize properties matter, and don't make a difference here.
Your explanation:
Is it because I don't use the accessor, that my fileName object basically gets dealloc'd only since there is no +1 in the initWithFileName method?
is exactly correct. To properly replicate the copy property used by your synthesizer, use this:
_fileName = [fileName copy];
Idea 1: Use ARC. In ARC, you'd declare your ivar strong, and then either use the synthesized setter or assign the ivar directly. A retain will be added for you and all will be well.
Idea 2: Use retain. If you're unable to use ARC for some reason, why you don't declare the NSString as retain, instead of copy? It's okay to hold onto the same instance of an immutable thing. (Sharing a mutable thing can be useful, too, as long as both classes understand that they are doing that).
Idea 3: If you must use non-arc and you must use copy, set the ivar with copy. That will fix your crash by doing the copy. As it is now, the code is copying the handle to the passed string, but not it's contents. The passed string is dealloc'd and your class is stuck with a zombie. You can say _filename = [string copy]; as others have suggested.
As a side-note, calling self = [super init]; is correct inside the overridden init method. Since you're making your own init variant, I think it's more proper to call self = [self init];
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 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];
I wanna ask if I allocated an instance variable for private use in that class, should i release it immediately on site, or i can depend on dealloc function. (because maybe i will need it on other function) ?
//Player.h
#interface Player : NSObject
{
NSMutableArray * objectArray;
}
- (void)awake;
- (void)add;
#end
//Player.m
#implementation Player : NSObject
{
-(id) init {
self = [super init];
if (self != nil ){
[self awake];
[self add];
}
return self;
}
- (void) awake {
objectArray = [[NSMutableArray alloc] init]; //is it cause leakage?
[objectArray addObject:#"foobar"];
}
- (void) add {
[objectArray addObject:#"foobar2"];
}
- (void) dealloc {
[objectArray release];
[super dealloc];
}
}
#end
or should i using property to set the objectArray iVar?
//Player.h
#interface Player : NSObject
{
NSMutableArray * objectArray;
}
#property (nonatomic,retain)NSMutableArray* objectArray;
- (void)awake;
- (void)add;
#end
//Player.m
#implementation Player : NSObject
{
-(id) init {
self = [super init];
if (self != nil ){
[self awake];
[self add];
}
return self;
}
- (void) awake {
self.objectArray = [[NSMutableArray alloc] init autorelease]; //cause leakage?
[objectArray addObject:#"foobar"];
}
- (void) add {
[objectArray addObject:#"foobar2"];
}
- (void) dealloc {
[objectArray release];
[super dealloc];
}
}
#end
if both of them doesn't cause a leakage, what type should i use?
should i always set iVar property, and access iVar value with self even if i only want to use it in this class?
I like to take the stance that if the instance variable should not be visible outside of the class then it should not be implemented as a property. But it's a personal thing that other developers may not agree with.
Either way you would need to release the objectArray in your classes dealloc method - which is what you're currently doing.
However you need to be careful with your awake method - if it's invoked multiple times then objectArray is leaked. This is the downside of not using properties. A use of self.objectArray = [[NSMutableArray alloc] init] here would have released the previous object.
In my opinion, you should only declare properties in your header if other objects are allowed to use them. There is no good reason why you would provide an -add: method (as in your example) that adds something to your array while also providing a getter for your array so other objects can manipulate it directly. It's called encapsulation.
If you do want to have the benefits of generated getters/setters for your implementation file, you can always use a class continuation (a nameless category) inside your implementation file and include your property declarations there. That way you get real, auto-generated properties that are only visible to your class' implementation.
Personally, I wouldn't use any getter or setter methods in your example. Just allocate the NSArray in your -init and release it in -dealloc. If this -awake method of yours might be called multiple times, just add an [objectArray removeAllObjects] call and you're sure to have an empty array without worrying about memory management.
It is very likely that memory will leak in your first example because you are not sending release to the previously set instance variable (if it already existed).
This is why you should use property setters - they handle all of this stuff for you.
Also, since you are obtaining ownership of the instance variable through the property (which is defined with the retain keyword), you will definitely leak memory if you don't send the instance variable the -release message in your -dealloc method.
So the verdict is that you should use the second example, not the first.
I have create a SinglestonClass in my code but i have a problem.
My variable are initialized in the -init method but when i call the singlestonClass these variable are re-initialize.
Can you help me for create a single initialization for my variable?
thanks.
#implementation SingletonController
#synthesize arrayPosition;
#synthesize arrayMovement;
#synthesize actualPosition;
#synthesize actualMove;
#synthesize stopThread;
+(SingletonController*)sharedSingletonController{
static SingletonController *sharedSingletonController;
#synchronized(self) {
if(!sharedSingletonController){
sharedSingletonController = [[SingletonController alloc]init];
}
}
return sharedSingletonController;
}
//I don't want a re-initialization for these variables
-(id)init{
self = [super init];
if (self != nil) {
arrayPosition = [[NSMutableArray alloc]init];
arrayMovement = [[NSMutableArray alloc]init];
actualPosition = [[Position alloc]init];
actualMove = [[Movement alloc]init];
stopThread = FALSE;
}
return self;
}
-(void) dealloc {
[super dealloc];
}
#end
Your init method should not be called by anyone except for your singleton class itself. That's what the sharedSingletonController method is for. This is your factory method that is responsible for returning the same static instance of your class. I'd also suggest that you rename the static instance of your singleton object and/or the sharedSingletonController selector itself to disambiguate between the two and for cleaner design. In this particular case, it may confuse someone who has to read your code.
Without seeing how the client code is calling on your singleton factory method, it's difficult to decipher where your problem is. We'd need to see the rest of the code including how it's being called. In your client code, you should be using something such as:
SingletonController *sigController = [SingletonController sharedSingletonController];
DO NOT DO:
SingletonController *sigController = [[SingletonController alloc] init];
Read here for more information in the Cocoa Fundamentals Guide.