I have a function that is synchronized, but it seems that I can't directly change the value of my instance variables in that block.
+(id)allocWithZone:(NSZone *)zone
{
#synchronized(self) {
if (sharedInstance == nil) {
sharedInstance = [super allocWithZone:zone];
//This is not allowed
something = #"hello";
//This is allowed
self.something = #"hello world!";
return sharedInstance;
}
}
return nil;
}
Why is this the case? I have a variable that I need to access directly (and I don't want to synthesize that variable). How do I get around this?
You can't change instance variables because this isn't an instance method. The value of self is, in fact, the class itself. Your line of code self.something = #"hello world!" won't work either. What you really want is sharedInstance.something = #"hello world!", and that will only work if something is a property. Even better would be to set up the ivars in the init method.
Oh, and you have no business setting ivars in +allocWithZone: anyway. The object has not been initialized yet.
Assuming you're trying to create a singleton here (as that's what it looks like), you may want to read this blog post on singletons in Obj-C.
Related
Are there any implication, when i don't assign self to it's super init, but to a completely different pointer, even a Static one? Will arc behave correctly? what are the implications of such an action?
static NSObject * StaticObject;
- (instancetype)init {
self = StaticObject;
if (self) {
}
return self;
}
ARC will behave just fine. You'll have a problem initialising StaticObject. You could do something like
if (StaticObject == nil) {
self = [super init];
StaticObject = self;
} else {
self = StaticObject;
}
I would think that the NSNull class does something like that.
Assuming that StaticObject isn't nil and has been initialised, you will cause confusion if you modify StaticObject, since others might be holding a reference to it.
I'm not sure this is safe. I think you will be leaking the memory of the original self, and potentially later on over-releasing your singleton. ARC isn't magic, it just sneaks in retain/release calls in the caller and your logic probably never lets ARC see the result of the alloc call.
When i was going through Singleton design pattern in Objective C, I found lot of people using the below code to create it.
#interface Base : NSObject {}
+(id)instance;
#end
#implementation Base
+(id) instance
{
static id theInstance = nil;
if (theInstance == nil)
{
theInstance = [[self alloc] init];
}
return theInstance;
}
#end
Here i did not get the why do we have to assign the static variable to nil in a method instead it can be declared outside the method and assigned to nil.
Because everytime this +instance() method is called, theInstance variable will be assigned to nil.
Will it not lose its previous object to which it was pointing to?
I have tried debugging it, surprisingly , it will not point to nil when +instance() method is called.
Can anyone explain me whats happening here?
static variables only get initialized once, regardless of if they're at global or local scope. In this case, you don't even need the nil - static storage class variables are zero-initialized by default. This declaration:
static id theInstance;
is enough to be the same as what you have there.
Is it safe to reinitialise self within a class method?
MyClass * a = [[MyClass alloc]init];
#implementation MyClass
{
-(id)init
{
if(self = [super init])
{
...
}
return self;
}
-(void)redefine
{
//??
self = [self init];
}
}
will a point to the reinitialized instance of MyClass?
Thank You,
nonono
Provided that (a) your class and its superclasses can be re-init'ed without leaking memory or resources and (b) you know that your class and its superclasses inits all return the self they are passed and not a reference to some other object, then yes...
Otherwise things will go wrong. Consider your redefine method; in the body of this method self is just a local variable whose contents is initialized to point to some object. Changing the value in that local variable does not change the object it originally pointed at, or the value of any other variables which point to that object. E.g. consider the variation:
#implementation Q
{
- (void) redefine
{
self = [[Q alloc] init]; // changes the *local* self to refer to a new object
}
...
}
...
Q *someQ = [[Q alloc] init]; // allocate an object
[someQ redefine]; // NO effect on someQ, another Q is just created and leaked
Clearly this does not alter someQ, and your version may not either. Your code will have the effect you wish if and only if you know init always returns the object it was passed - which is not guaranteed in Obj-C.
As long as init returns self, which it normally does, nothing will go wrong.
But you probably want to split your initialization to some separate method, which you can call from both init and redefine.
You need to return your new object from -init, not simply assign a new value to self. And you must remember to release the old self, since it was created with +alloc. Caveats aside though, returning a different object from -init is explicitly allowed. That's why you'll see newbies being corrected when they write something like this:
// Bad example! Do NOT do this!
Foo *foo = [Foo alloc];
[foo init];
This is an anti-pattern because -init is not required to return the same object it was called on. That means the above can end up assigning foo to point to an object that's been released, instead of to the object that was initialized in its place. This is why you always see +alloc and `init chained together like so:
Foo *foo = [[Foo alloc] init];
It's also why you need to reassign self when calling super's -init, because it may also have returned a different object.
self = [super init];
Hey, I am making a imageloading system with my tablecells and I need each cell to share the same instance of my imageloader class. Sorry if this is a nooby question, but is it possible to archieve this? So what I am meaning is that if I have int variable in other instance of the same class, the value of the int variable is same in both classes.
Thanks in advance!
For a "single instance for everything", you need a singleton:
+(SomeClass *)sharedInstance {
static SomeClass *instance = nil;
if (instance == nil) {
instance = [[self alloc] init];
}
return instance;
}
Then wherever you need the shared instance, just do:
SomeClass *obj = [SomeClass sharedInstance];
The static variable is basically what makes it work, when coupled with the "is nil" test, since static variables are only ever initialized once.
Incidentally, I think due to the way UITableViewCells are used (i.e. copied) you may already have what you need without any further work such as creating a singleton. Just provide the correct shallow-copy logic in copyWithZone:.
I am trying to create an object only instantiatable through a factory method. I prevented init being used by throwing an exception (see Creating a class with no init method). However this meant that I had to create a new method secretInit to use in the factory method.
//Factory method
- (URLReqs *)buildURLReq:(NSString *)location
{
URLReqs *tmp=[[URLReqs alloc] secretInit];
tmp.str=location
return tmp;
}
- (id) secretInit{
return [super init];
}
This method is messy and while we can avoid declaring secretInit in the header file, someone could still access it. Is there a nicer solution?
One idea is to try calling init on the super object of URLReqs directly rather than creating a function to do it.
You don't want to do it this way, but it is possible:
#include <objc/message.h>
#implementation MyClass
+ (id) factoryMethodWithParameter:(NSString *) someString;
{
struct objc_super instanceSuper;
id myInstance = [self alloc];
instanceSuper.receiver = myInstance;
instanceSuper.super_class = [self superclass];
// instanceSuper.class = [self superclass]; // use this line if the above doesn't compile
myInstance = objc_msgSendSuper (&instanceSuper, #selector(init));
//continue on setting up myInstance's ivars . . .
[myInstance setVariable:someString];
return myInstance;
}
- (id) init
{
self = [super init];
if (!self) return nil;
[self release];
[self doesNotRecogniseSelector:_cmd];
return nil;
}
#end
This will allow you to continue to send init messages to myInstance's “super” object, but won't allow anyone to send init to MyClass instances.
Be careful though, although this is using standard runtime functions declared in objc/*.h, don't expect Apple to keep this runtime API consistent.
The solution is to use a category on your object to hide the secret initialization method.
Private Methods through categories
What goal are you trying to accomplish? There might be a better solution than this.
It only exposes it if it's referenced in the header file.
No, wait. I should state that another way. There's no better way to hide it than to not declare it in the header file. Private methods don't exist in Objective-C.