Objective-C : Something that I don't understand with the init method - objective-c

I was encountering an issue with my code and somebody explained me that it was because I wasn't creating an instance for my property, he told be that I should do that in my init method. What I don't understand is this : I already created my object by doing like this :
TADIgnoringConstraint *ignorer = [TADIgnoringConstraint new];
I know that I could also use [[TADIgnoringConstraint alloc] init] but I see that the init method is already existing, so should I create a new custom initialization method with another name ? In that case, how do I create a init function ? What does this function returns ?

[TADIgnoringConstraint new]
Is exactly the same thing with
[[TADIgnoringConstraint alloc] init]
Which allocates the object in memory and initializes it. When you call init on a allocated object, it runs the init method of the object if declared, if not it runs the init of the superclass which returns the object it self.
Now what #Wain told you was to instantiate your array in your init method. Which is the typical practice in most cases.
You can do something like this:
- (id)init
{
self = [super init];
if (self) {
// Set your properties properly here
// before you actually return the object so they can be ready to use
_someMutableArray = [NSMutableArray array];
}
return self;
}

new is the same as alloc followed by init. In NSObject, new is defined as
+ (id)new
{
return [[self alloc] init];
}

Looking at the other thread, the assumed problem is that you may not be initializing the tockensArray property. If that's true, then you need to do that in the init method of TADIgnoringConstraint, which you say already exists.
What you need in that case would be something like:
self.tockensArray = [NSMutableArray array];
If that's not the actual problem, show how you declare tockensArray and what is currently in your init.

TADIgnoringConstraint *ignorer = [TADIgnoringConstraint new];
That line of code creates a new object of class TADIgnoringConstraint and stores a pointer to that object into a local variable. Because it is a local variable and apparently not stored anywhere else, it will be deleted by ARC as soon as you leave the function or method where this happens.
I strongly recommend using [[TADIgnoringConstraint alloc] init], mostly for the reason that everybody does. Following conventions means that your code is easier to read, and people including yourself don't need to check whether your problems are caused by not following conventions. (You may say: "But new is the same as alloc + init" to which I would reply "your code isn't working. Would you bet $1000 that it is indeed the same?").

Related

Why should I not separate alloc and init?

The normal way to initialise and allocate in Objective-C is
NSObject *someObject = [[NSObject alloc] init];
Why is the following not practised?
NSObject *someObject = [NSObject alloc];
[someObject init];
The main problem is that you might end up using the wrong object.
init is special in many classes as it might just release the receiver and instead create a new object that resides at a different address. So your someObject then points to the wrong (uninitialized) instance.
There are a lot of framework classes that use the arguments of the init method to decide which kind of specialized subclass is best to use. This frequently happens with class clusters like NSString or NSArray but it can really happen with each kind of object.
One place where you can see this special behavior of initializers is ARC: It explicitly declares that the init family of methods eats up the receiver and returns a +1 retained object. This would not be necessary if initializers would just always return the receiver.
Of course you could fix your code by just doing another assignment:
NSObject *someObject = [NSObject alloc];
someObject = [someObject init];
This would fix the problem. But there's also no sense in doing it.
From the Object Initialization official documentation:
Because an init... method might return nil or an object other than the one explicitly allocated, it is dangerous to use the instance returned by alloc or allocWithZone: instead of the one returned by the initializer
Another reason from the same document is that:
Once an object is initialized, you should not initialize it again
given this example:
NSString *aStr = [[NSString alloc] initWithString:#"Foo"];
aStr = [aStr initWithString:#"Bar"];
where:
the second initialization in this example would result in NSInvalidArgumentException being raised.
Because it is less simple and more error-prone.
An allocated but not initialised object is useless, so it make sense to put allocation and initialisation in one line. If they are separated, there is more possibility for errors and bugs if the two lines are not directly after each other (perhaps after refactoring), which may lead to errors while trying to use an uninitialised object.
There simply isn't a single good reason to alloc and init in separate lines, and many reasons against it.
As per my understanding an allocated object makes no sense without it being initialized,
if you alloc an object first and then later plan to initialize it, there might be a case that you may forget to initialize the object and give a direct call to any of its instance method which would result in run time error.
Example:
NSString *str = [NSString alloc];
// Override point for customization after application launch.
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
NSLog(#"%ld",str.length);
When i run the above code i get this in my console
Did you forget to nest alloc and init?
*** Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: '*** -length only defined for abstract class. Define -[NSPlaceholderString length]!'
if i would do the below I would still get the exception as str is not being initialized because whatever is being initialized is not being consumed or pointed by str
[str init];
Hence if you want to do it in two lines it should be like this
NSObject *someObject = [NSObject alloc];
someObject = [someObject init];
But it's always better to keep them nested
NSObject *someObject = [[NSObject alloc]init];
If you plan on doing it on single line then use the new keyword which servers the purpose of allocation and initialization on a single line.
Example: YourClass *object_ofClass = [YourClass new];

calling super from within a GCD dispatch_async block: is it safe?

I'm in a bit of a pickle. I know that calling [self methodName] from within a block will lead to a retain cycle.
However in this class due to multithreading I cannot allow execution of the method that the block is accessing from anywhere else other than the block, as it would potentially lead to serious problems.
Current code:
if (_getRunning==NO){
__weak SyncArrayMT *_weak_self = self;
_get_t = ^void (void){
_weak_self->_getRunning = YES;
NSArray *objects = [_weak_self get:getQuery
usingClassCtor:ctor
withAuthBlock:authBlock];
if (_weak_self.getBlockCb)
_weak_self.getBlockCb(objects);
_weak_self->_getRunning = NO;
};
}
Does exactly that, it calls [self getmethod]. While its ok for the dispatched block to run this method, I do not want anything outside this class calling this method.
So, would it be ok to override this inherited method as such:
- (NSArray *) get:(NSString *)getQuery usingClassCtor:(initBlock)initCb withAuthBlock:(authenticate)authBlock
{
NSLog(#"Direct call to get is not allowed - use the threaded method");
return nil;
}
And then change the block to this:
_get_t = ^void (void){
_weak_self->_getRunning = YES;
NSArray *objects = [super get:getQuery
usingClassCtor:ctor
withAuthBlock:authBlock];
if (_weak_self.getBlockCb)
_weak_self.getBlockCb(objects);
_weak_self->_getRunning = NO;
};
I have tried it and it works without doing a call to the [self getMethod], but will super be retained, properly released, etc? Yes I am using ARC. Would calling super within a block lead to any problem ? Is there a hack to get a __weak to super instead ?
Alternatively, how can I disallow direct calls to [self getMethod] (which is inherited) and only use it internally ?
I know that Objective-C doesn't exactly implement this, but I know there are tricks, such as declaring and implementing a method in the implementation file only.
EDIT#1:
I have tried with SEL & IMP and function pointers. Problem is that IMP and function pointers require as a parameter an instance, and this renders the hole point mute:
NSString * (*getFuncPtr)(id,SEL,id,id) = (NSString * (*)(id,SEL,id,id))[super methodForSelector:#selector(sendObjectsPassingTest:withAuthBlock:)];
NSString *reply = getFuncPtr(_weak_self,#selector(sendObjectsPassingTest:withAuthBlock:),predicate,authBlock);
This simply calls the inherited method. Trying to use it with super simply gives an error. At this point I will go ahead and simply use super within the block, and try and profile to see if it leads to any retain cycle.
EDIT#2:
Based on newacct's answer, this is what I ended up doing:
typedef NSArray * (* getFuncPtr)(id,SEL,id,id,id);
...
...
__weak SyncArrayMT *_weak_self = self;
_getMethod = (NSArray * (*)(id,SEL,id,id,id))[[[self class] superclass] instanceMethodForSelector:#selector(get:usingClassCtor:withAuthBlock:)];
_get_t = ^void (void){
NSArray *objects = _weak_self->_getMethod(_weak_self,#selector(get:usingClassCtor:withAuthBlock:),getQuery,ctor,authBlock);
}
I am hoping this should avoid any retain cycles, although I haven't actually profiled it yet.
I know that calling [self methodName] from within a block will lead to
a retain cycle.
That is not true in general. The block will retain self, yes. But there will only be a "retain cycle" if self somehow retains the block. In this case, it does.
but will super be retained
Yes, self will be retained (super is a call on self with a different method lookup pathway).
I have tried with SEL & IMP and function pointers. Problem is that IMP
and function pointers require as a parameter an instance, and this
renders the hole point mute:
NSString * (*getFuncPtr)(id,SEL,id,id) = (NSString * (*)(id,SEL,id,id))[super methodForSelector:#selector(sendObjectsPassingTest:withAuthBlock:)];
NSString *reply = getFuncPtr(_weak_self,#selector(sendObjectsPassingTest:withAuthBlock:),predicate,authBlock);
This simply calls the inherited method. Trying to use it with super simply gives an error. At this point I will go ahead and simply use super within the block, and try and profile to see if it leads to any retain cycle.
There are many wrong points here. First, as said above, super is a call on self (there is no such thing as a super object), so it would be sufficient to get the IMP for the method in the superclass, and call it on self.
BUT, [super methodForSelector:... does not get the method in the superclass. It actually gets the method in this class. The super in [super methodForSelector:... affects which methodForSelector: method is called. However, no class ever overrides methodForSelector:, so there is actually no difference between [super methodForSelector:... and [self methodForSelector:.... As said above, super calls the method on self, so it still finds the method based on the class of the current object.
You can get the right IMP by using the class method +instanceMethodForSelector::
NSString *(*getFuncPtr)(id,SEL,id,id) = (NSString * (*)(id,SEL,id,id))[[[self class] superclass] instanceMethodForSelector:#selector(sendObjectsPassingTest:withAuthBlock:)];
However, using the above will not work correctly if the current object is an instance of a subclass, because then [self class] will be the subclass. So to make sure it does what we want, we need to hard-code the name of our current class, or the superclass:
NSString *(*getFuncPtr)(id,SEL,id,id) = (NSString * (*)(id,SEL,id,id))[[SyncArrayMT superclass] instanceMethodForSelector:#selector(sendObjectsPassingTest:withAuthBlock:)];
NSString *reply = getFuncPtr(_weak_self,#selector(sendObjectsPassingTest:withAuthBlock:),predicate,authBlock);
It is also possible to do it using objc_msgSendSuper directly, but that function is not really that easy to use either. So I think you should stick with the IMP approach above.

Potential leak of an object warning -- clarification needed

After I Analyzed my code, Xcode indicated a potential leak as shown below.
Is this something I should be concerned about?
In this code, the class that sets doublyLinkedList is the sole owner and continues to manage this object throughout program execution.
The reason you're getting the warning is because the new call returns a retained object, and then your setter is probably doing another retain on it (depends on whether it's synthesized or manually generated).
Also, I would recommend you use the standard alloc/init instead of new, so that the two-phase creation is obvious.
This is better:
if (self) {
DoublyLinkedList *dll = [[[DoublyLinkedList alloc] init] autorelease];
self.doublyLinkedList = dll;
}
or just
if (self) {
self.doublyLinkedList = [[[DoublyLinkedList alloc] init] autorelease];
}
You may wish to do this instead:
if (self) {
DoublyLinkedList *dll = [DoublyLinkedList new];
self.doublyLinkedList = dll;
[dll release];
}
In the header, declare doublyLinkedList a #property that is retained.
You have a "potential leak" because the Analyzer sees that you have allocated memory for a DoublyLinkedList instance (using new), put it into a local variable called dll, and not released that memory in the same scope.
Assuming that the doublyLinkedList member that you're setting happens to also be a property declared as retaining, you also have an actual leak, because you have over-retained the DoublyLinkedList that you create here.
The ownership rules say that you have one claim on this instance because you called new to create it. When you pass the instance to setDoublyLinkedList:, it is retained, and you then have two claims. When the init method ends, you only have one reference to the instance, through the ivar/property -- you've lost the local variable -- which means that you have more ownership claims than you have references. This is a good indication that you will have a leak.
To fix the leak, you need to relinquish one of your claims before the end of the init method. You can do this in one of two ways, using release as soon as the property is set:
DoublyLinkedList * dll = [DoublyLinkedList new];
[self setDoublyLinkedList:dll];
[dll release];
or autorelease:
[self setDoublyLinkedList:[[DoublyLinkedList new] autorelease]];
// Or equivalent procedures involving a temp variable
However, it should be noted that using setters in init may be problematic (see also Mike Ash's writeup on the topic), because accessors can -- potentially -- have side effects that depend on your object already being fully set up. There seem to be two camps on this issue, and it's probably best to read about it and come to your own conclusions, but you may find that it simplifies your initializer methods to assign to ivars rather than using properties:
if( self ){
doublyLinkedList = [DoublyLinkedList new];
}
This is completely correct in terms of memory management.
Finally, if DoublyLinkedList is a class whose code you have, you can also consider writing a convenience constructor, which will return a new, autoreleased instance for you. The convention in Cocoa is to simply name the method after the class, with standard method name casing, like so:
+ (id) doublyLinkedList {
return [[[self alloc] init] autorelease];
}
Note that this is a class method:
if( self ){
[self setDoublyLinkedList:[DoublyLinkedList doublyLinkedList]];
}
and see my answer to "Self-allocating objects" for an explanation of these constructors.
If you have a property called "doublyLinkedList" (assumption based on code given), and it is "retained," you can do the following:
if (self) {
DoublyLinkedList *dll = [[DoublyLinkedList alloc] init]
self.doublyLinkedList = dll;
[dll release];
}

Assigning to self in Objective-C

I'm from the C++ world so the notion of assigning this makes me shudder:
this = new Object; // Gah!
But in Objective-C there is a similar keyword, self, for which this is perfectly acceptable:
self = [super init]; // wait, what?
A lot of sample Objective-C code uses the above line in init routines. My questions:
1) Why does assignment to self make sense (answers like "because the language allows it" don't count)
2) What happens if I don't assign self in my init routine? Am I putting my instance in some kind of jeopardy?
3) When the following if statement fails, what does it mean and what should I do to recover from it:
- (id) init
{
self = [super init];
if (self)
{
self.my_foo = 42;
}
return self;
}
This is a topic that is frequently challenged by newcomers:
Wil Shipley: self = [stupid init];
Matt Gallagher: What does it mean when you assign [super init] to self?
Apple documentation: Implementing Initializers
Cocoa-Dev: self = [super init] debate
Basically, it stems from the idea that a superclass may have over-ridden the designated initializer to return a different object than the one returned from +alloc. If you didn't assign the return value of super's initializer into self, then you could potentially be dealing with a partially initialized object (because the object that super initialized isn't the same object that you're initializing).
On the whole, it's pretty rare for super to return something different, but it does happen in a couple of cases.
In Objective-C, initializers have the option of returning nil on failure or returning a completely different object than the one the initializer was called on (NSArray always does this, for example). If you don't capture the return value of init, the method might be executing in the context of a deallocated object.
Some people disagree about whether you should do the whole assign-to-self rigamarole if you don't expect to get something else back from the superclass initializer, but it's generally considered to be good defensive coding.
And yes, it looks weird.
It is true that init may return nil, if the initialization fails. But this is not the primary reason why you should assign to self when you implement your own initializers.
It has been mentioned before, but it is needed to stress even harder: the instance returned from an initializer may not be the same instance as the one you sent in, in fact it may not even be of the same class!
Some classes use this as a standard, for example all initializer to NSString and NSArray will always return a new instance of a different class. Initializers to UIColor will frequently return a different instance of a specialized class.
And you yourself can happely implement something like this if you want:
-(id)initWithName:(NSString*)name;
{
if ([name isEqualToString:#"Elvis"]) {
[self release];
self = [[TheKing alloc] init];
} else if (self = [super init]){
self.name = name;
}
return self;
}
This allows you to break out the implementation of some special case into a separate class, without requiring the clients of your API to care or even know about it.
All the other points here are valid, but it's important for you to understand as well that self is an implicit parameter to every Objective-C method (objc_msgSend() passes it) and can be written to, just like any other method parameter. (Writing to explicit parameters is generally frowned upon, unless they are out parameters.)
Typically, this is only done in the -init method, for the reasons others have stated. It only has any effect because self is returned from the method and used in the assignment id obj = [[NSObject alloc] init]; It also affects the implicit resolution of ivars, because, for example, if myVar is an ivar of my class, then accessing it in a method causes it to be implicitly resolved to self->myVar.
I'm still new to Objective C, but this post helped me in understanding this.
To sum it up, most init calls return the same object that self is already initialized to. If there is an error, then init will return nil. Also, some objects such as singletons or unique objects (like NSNumber 0) will return a different object than the one initialized (the singleton or a global 0 object). In these situations you need to have self reference that object. I'm by no means an expert in what is going on behind the scenes here, but it makes sense on the surface, to me.
If [super init] returns nil that means that you have been deallocated and your self parameter is now an invalid pointer. By blindly following the self = [super init] convention you will save you from potentially nasty bugs.
Consider the following non-typical initializer:
- (id)initWithParam:(id)param {
if (!param) {
// Bad param. Abort
self = [super init]; // What if [super init] returns nil?
[self release];
return nil;
}
else
{
// initialize with param.
...
}
}
Now what happens if my superclass decides to abort and return nil? I have been de-allocated and my self parameter is now invalid and [self release] will crash. By re-assigning self, I avoid that crash.

Cocoa without Interface Builder, initialize an instance of app controller?

I don't plan to write applications without IB, I'm just in the process of trying to learn more about programming.
How can I get a single instance of my AppController class at startup? (It's normally loaded from the nib.) And can you clear up the use of +initialize and -init? If I understand, +initialize is called on all classes at startup. How can I use this to create an instance of my AppController with instance variables that make up my interface?
Hope that makes sense, and thanks for any help.
+initalize is sent to a class the first time it or one of its subclasses receives a message for the first time. So, when you do:
instance = [[[YourClass alloc] init] autorelease];
That alloc message triggers initialize.
If you do the same thing with a subclass:
instance = [[[SubclassOfYourClass alloc] init] autorelease];
That alloc message will trigger +[YourClass initialize] the same way the other one did (prior to also triggering +[SubclassOfYourClass initialize]. But only one of these will do it—each class's initialize never gets called more than once. (Unless you call it yourself with [super initialize] or [SomeClass initialize]—so don't do that, because the method won't be expecting it.)
-init, on the other hand, initializes a new instance. In the expression [[YourClass alloc] init], you are personally sending the message directly to the instance. You may also call it indirectly, through another initializer ([[YourClass alloc] initWithSomethingElse:bar]) or a convenience factory ([YourClass instance]).
Unlike initialize, you should always send init (or another initializer, if appropriate) to your superclass. Most init methods look roughly like this:
- (id) init {
if ((self = [super init])) {
framistan = [[Framistan alloc] init];
}
return self;
}
Details differ (this method or the superclass's or both may take arguments, and some people prefer self = [super init] on its own line, and Wil Shipley doesn't assign to self at all), but the basic idea is the same: call [super init[WithSomething:…]], make sure it didn't return nil, set up the instance if it didn't, and return whatever the superclass returned.
This implies that you can return nil from init, and indeed you can. If you do this, you should [self release], so that you don't leak the failed object. (For detecting invalid argument values, an alternative is NSParameterAssert, which throws an exception if the assertion fails. The relative merits of each are beyond the scope of this question.)
How can I use this to create an instance of my AppController with instance variables that make up my interface?
The best way is to do it all in main:
int main(int argc, char **argv) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
AppController *controller = [[[AppController alloc] init] autorelease];
[[NSApplication sharedApplication] setDelegate:controller]; //Assuming you want it as your app delegate, which is likely
int status = NSApplicationMain(argc, argv);
[pool drain];
return status;
}
You'll do any other set-up in your application delegate methods in AppController.
You already know this, but for anyone else who reads this: Nibs are your friend. Interface Builder is your friend. Don't fight the framework—work with it, and build your interface graphically, and your application will be better for it.
Another solution to the problem of launching an app without a nib.
Instead of allocing your own controller, just use the extra parameters in the NSApplicationMain() method:
int retVal = NSApplicationMain(argc, argv, #"UIApplication", #"MyAppDelegate");
This takes care of all the proper linking one would need.
Then, the only other thing you'd need to remember is to make your own window and set it to visible.
A set of NIBs seem to be an unsatisfactory answer, even when represented in XML (as a XIB), because there's no easy way to compare or merge them with any standard subversion or SCM-style tool. The encoded information is fragile and not intended to be edited by mere humans. How would changes be represented by a GUI? Would I step through each attribute of each control and visually check them?
If the app's behavior is written in code, however, there is a chance that I can figure out what's going in, even if I have to keep lots of details close at hand at the same time.
A proposed solution: use a top-level NIB that the main architect coded up, but then code the rest of the app explicitly.
Anybody got a better idea?