alloc + init memory usage mechanism - objective-c

I am just curious to know when an object has made by alloc, and a piece of memory allocated to it, why init don't use that piece of memory and changes the address of object?
NSDate *t = nil;
NSLog(#"t = %p",t); // t = 0x0
t = [NSDate alloc];
NSLog(#"t = %p",t); // t = 0x100107af0
t = [t init];
NSLog(#"t = %p",t); // t = 0x1001035a0

Two-step initialization allows us to do these kinds of things (namely, substituting an instance of a class for another depending on the initializer called). Class clusters all over Foundation and UIKit take advantage of this to return instances optimized for a particular use-case. For example, UIColor itself is just an interface for its subclasses that implement color caching (all the named initializers like +blackColor), the RGB color space (+colorWithRed:green:blue:alpha), the black and white color space (+colorWithWhite:alpha:), CIColor compatibility, etc. And so NSDate is too. When you call -init, Apple has means and motive to return a different object that implements the same interface as NSDate as an optimization because you honestly shouldn't care what you get as long as it doesn't launch the missiles when you try to message it properly.

As of the latest iOS SDK, calling [NSDate alloc] always returns the same memory location. You can verify this behavior with the following code:
NSDate *date1, *date2;
date1 = [NSDate alloc];
NSLog(#"date1: %p", date1);
date1 = [date1 init];
NSLog(#"date1: %p", date1);
date2 = [NSDate alloc];
NSLog(#"date2: %p", date2);
date2 = [date2 init];
NSLog(#"date2: %p", date2);
I suspect that it has to do with the fact that NSDate is a class cluster.
If the private subclasses of a class cluster have different storage requirements, it's impossible to know inside of alloc how much memory to allocate. One approach to solving this problem, and it appears this is the approach that Apple is using with NSDate, is to let the init and factory methods handle all the memory allocation, since those methods know what private subclass is actually going to be used.
At that point, all alloc is doing for you is allowing the user to preserve the [[NSDate alloc] init] pattern that's used for object creation everywhere in Objective-C. Since the memory location returned by alloc is always discarded, alloc may as well just return a fixed memory location, which is what it appears to be doing.

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];

Objective-C Property assignment without #property

I'm currently developing an iOS application which was started by another developer.
Usually, I make a property for every instance variable (assign for int, bool etc. / retain for all classes).
So in my projects, this line causes a leak:
myVar = [[NSString alloc] init]; (alloc/init +1, retain in setter +1, release in dealloc -1 => +1)
So I use:
NSString *tmpMyVar = [[NSString alloc] init];
[self setMyVar: tmpMyVar];
[tmpMyVar release];
Or:
NSString *tmpMyVar = [[[NSString alloc] init] autorelease];
[self setMyVar: tmpMyVar];
In this new project, the previous developer didn't use #property/#synthesize so I'm wondering what will be the result of the previous line of code in this context (it doesn't call setter I guess)? Memory Leak?
The previous developer releases variable in dealloc method, just like me.
Thank you very much!
Since it directly assigns the instance variable to the allocated object it's retain count is 1 (because, like you said, a setter isn't called).
And because it's released in dealloc, it's all balanced out. So no memory leaks.
So in my projects, this line causes a leak:
myVar = [[NSString alloc] init]; (alloc/init +1, retain in setter +1, release in dealloc -1 => +1)
No,it wouldn't even in your projects, because, as you pointed out, no setter is used.
Also, when using properties, it is the recommended way to access instance variables directly in the init method, instead of using setters.
To inspect for questionable memory-leaks like your example, also use the clang static analyzer or instrument's leak tool.
You need to look at the other developer's setter implementation. Make sure they release the existing value and retain the new value; something like:
- (void)setMyString:(NSString *)string
{
[string retain];
[_string release]; // ivar
_string = string;
}
The only advantage to implementing your own setter/getter methods is to do something (other than setting the ivar) when a value is set. If the methods don't do anything like this then why not change all implementations to #property/#synthensize?

Memory leaking from object that I do not alloc

I have the following function, which results in *timeString leaking memory. I am fairly new to Objective-C (and memory management), but I read that you only need to release objects that you alloc in the first place. Because I alloc *formatter, and then set that to *timeString, does this mean that I now have to release *timeString too?
Here's the code:
-(NSString *)getDate{
NSLog(#"getDate");
NSDateFormatter *formatter;
NSString *timeString;
formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"yyyy-MM-dd"];
timeString = [formatter stringFromDate:[NSDate date]];
[formatter release];
return timeString;
}
EDIT: Here is where the getDate function is called:
-(NSString *)getFileName{
//nameofXMLFile = page_##
NSString *nameOfFile = [NSString stringWithString:pageTitle];
//nameOfXMLFile = page_##.DataCheckSheet.xml
nameOfFile = [nameOfFile stringByAppendingString: #".DataCheckSheet.xml"];
NSString *dateString = [self getDate];
dateString = [dateString stringByAppendingString: #"_"];
NSLog(#"datestring: %#", dateString);
dateString = [dateString stringByAppendingString:nameOfFile];
NSLog(#"datestring with append: %#", dateString);
//nameOfXMLFile = yyyy-MM-dd_page_##.DataCheckSheet.xml
nameOfFile = dateString;
return nameOfFile;
}
As you already correctly stated, all objects, that aren't explicitly alloced, are per definition 'autoreleased', which means they will be destroyed, once they leave the scope of the function that defined them.
To keep an object valid longer than that, for example, by keeping it around as a class object, you would call 'retain' on it.
This 'retain' needs to 'released', just like an 'alloced' object.
By passing the reference to the object in question as return value, the scope of the object gets expanded to the function, which called the function in the first place...which means, the object would be destroyed at the end of the calling function, unless it is retained by then.
nameOfFile is still that very object in question, since you copied the address of dateString to that variable, effectively erasing that string from existence (it will thereby get autoreleased).
Try to avoid such assignments, unless you have a reason for them, to avoid confusion.
In short: If you have a chain of function calls and returns, make sure, that there isn't a 'retain' somewhere along the line, which doesn't get released appropriately, and you'll be fine.
Your best bet to understand leaks is to use Instruments and its "Leaks" template.
The "leak" instrument will show you what objects are leaked and you will be able to jump right away to the ObjectAlloc instrument to see retain/releases calls to the leaked object. You should then be able to find where missing release(s) are.
As is, your code looks OK wrt memory management. However most of the strings created here are autoreleased, which means they will be effectively released when the outter autorelease pool will be drained. Until the pool is drained, your object might appear to leak.
In typical applications, the main thread has an autorelease pool automatically installed by NSApplication/UIApplication, yet the pool is drained only when the application receives events (see this question)
In a usual detached thread (using NSThread or pthread), you have to install your own pool(s) (and drain them regularly).
GCD dispatch queues install their own autorelease pool and drain them from time to time.

Lifetime of weak local variables with ARC

If I have a piece of code that looks like this:
- (void)testSomething
{
__weak NSString *str = [[NSString alloc] initWithFormat:#"%#", [NSDate date]];
NSLog(#"%#", str);
}
the output will be (null) because there are no strong references to str and it will be immediately released after I allocate it. This makes sense and is spelled out in the Transitioning to ARC guide.
If my code looks like this:
- (void)testSomething
{
__weak NSString *str = [NSString stringWithFormat:#"%#", [NSDate date]];
NSLog(#"%#", str);
}
then it correctly prints out the current date. Obviously you would expect it to work in a non-ARC world, since str would be autoreleased and therefore valid until this method exits. However, in ARC-enabled code people generally consider the two forms (stringWithFormat & alloc/initWithFormat) to be equivalent.
So my question is whether code like the second example is guaranteed to work under ARC. That is, if I have a weak reference to an object that I get via what we would normally consider an autoreleasing convenience constructor, is it guaranteed to be safe to use that reference in the same scope I normally would have without ARC (i.e. until the method exits)?
The conventions of autoreleasing and allocing still apply in the world of ARC. The only difference is that ARC will insert extra retain/release calls to make it much harder to leak objects or access a dealloced object.
In this code:
__weak NSString *str = [[NSString alloc] initWithFormat:#"%#", [NSDate date]];
The only place the object is retained (or equivalent) is the alloc. ARC will automatically insert a release command, causing it to be immediately dealloced.
Meanwhile, in this code:
__weak NSString *str = [NSString stringWithFormat:#"%#", [NSDate date]];
By convention, the return value of a convenience constructor like this must be an autoreleased object*. That means the current autoreleasepool has retained the object and will not release it until the pool is drained. You are therefore all but guaranteed that this object will exist for at least the duration of your method - although you probably shouldn't rely on this behaviour.
(* or retained in some other way)
The lifetime of a local weak variable is not guaranteed at all. If the object that the variable points to is deallocated, the weak variable will point to nil afterwards.
If you have a weak reference to an object that you got via a method that does not return a retained object, it is not safe to assume that this object lives until the method exits. If you want to make sure that the object survives, use a strong reference.
Here is an example that shows that a non-retaining method's return value is not guaranteed to end up in the autorelease pool:
Create a new iOS project (Single View App using ARC and Storyboards)
Add this method to the AppDelegate.m:
+ (id)anObject
{
return [[NSObject alloc] init];
}
Replace -application:didFinishLaunchingWithOptions::
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
__weak id x = [AppDelegate anObject];
NSLog(#"%#", x);
return YES;
}
Important: Now set the Optimization level for Debug to -Os.
In this example, +[AppDelegate anObject] acts like a convenience constructor, but you will see (null) logged if you execute it on a device with -Os optimization. The reason for that is a nifty ARC optimization that prevents the overhead of adding the object to the autorelease pool.
You may have noticed that I switched to not using a library method like +[NSString stringWithFormat:]. These seem to always put objects in the autorelease pool, that may be for compatibility reasons.

Releasing objects returned by method

Ok, I know the answer to this question should be obvious, but I need a little push in the right direction.
I find myself writing a fair number of methods that follow the following pattern:
-(NSThing*)myMethod{
NSThing *thing = [[NSthing alloc] init];
// do some stuff with the thing
return thing;
}
My question is, how do I handle the release of this object? Clearly I can't release it within the method.
usually you would autorelease it
-(NSThing*)myMethod{
NSThing *thing = [[NSthing alloc] init];
// do some stuff with the thing
return [thing autorelease];
}
Autoreleasing is the easy way to get out of this, as newacct said. However, you should take into consideration the "ownership" of the object you're returning.
In Objective-C, the general rule of thumb is that any method with alloc, new, or copy in its name returns an object that is not autoreleased, while other methods (like class methods) pre-autorelease the object to be returned. So these three are not equivalent in terms of autorelease (although the compiler may do some magic and reduce them all to string constants anyway):
// Autoreleased
NSString *string1 = [NSString stringWithString:#"aString"];
NSString *string2 = [[[NSString alloc] initWithString:#"aString"] autorelease];
// NOT autoreleased
NSString *string3 = [[NSString alloc] initWithString:#"aString"];
Your code can take a similar approach, where you consider who owns the object you're returning. In the specific example you provided, the method is the one allocing and initing the object, so in general you're responsible for autoreleaseing [sic] it within your own method. However, if you were to write a method that takes a preexisting object and modifies it in some way, you would not own that object and would not be responsible for autoreleasing the returned object. (Doing so could actually cause problems down the road when the autorelease pool to which the object belongs gets drained.)
See also (thanks to Peter and Quinn in the comments!):
Memory Management Rules