While I realize one is a class method and the other an instance method, they have the exact same description in the Apple docs so I'm not quite understanding the different syntax/use cases.
Their functionality is equivalent, but the class method returns an autoreleased object. That is, it's probably implemented along the lines of:
+ (NSFetchRequest *)fetchRequestWithEntityName:(NSString *)entityName {
return [[[NSFetchRequest alloc] initWithEntityName:entityName] autorelease];
}
This is a fairly common pattern in Objective-C libraries known as Class Factory methods.
Based on what you said, if they really have the same use case, the only difference has to do with the garbage collection on objective-C, according to the memory management design Apple uses.
Whenever you call an init method over an object, you own it and you are responsible for releasing it when you no longer need the object.
When you call any other kind of method that returns an object, that object is added to a NSAutoreleasePool, and it is autoreleased when the pool gets drained.
You can get more insights here.
So, following Apple's way, if you don't want so save the object for further use, you can call fetchRequestWithEntityName and not worry about releasing the object at the end of the method call. If you want to save it as an instance variable, you call the initWithEntityName method . They can, of course be interchanged, but this approach follows apple guidelines in what comes to memory management.
-(void)myMethod {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
id obj1 = [[Object alloc] initWithEntityName:...];
id obj2 = [Object fetchRequestWithEntityName:...];
//obj1 retain count is +1
//obj2 retain count is +0 (likely autoreleased)
[pool drain];
//obj1 still exists
//obj2 is no longer valid; may or may not have been deallocated
}
So basically, fetchRequestWithEntityName is achieved by:
+(id)fetchRequestWithEntityName:... {
return [[[self class] alloc] initWithEntityName:...] autorelease];
}
The main difference between those two API is as below:
fetchRequestWithEntityName will give you an autorelease object, so once the event loop is over it will be deallocated from the memory until you retain it.
But initWithEntityName will give you object which is to be released by you otherwise there will be memory leak.
Related
Suppose I have this code:
-(SomeOtherType*) getMyObject {
SomeType someObject = [[SomeType alloc] init];
// ... later on
SomeOtherType toReturn = [[[someObject interiorObject] retain] autorelease];
[someObject release];
return toReturn;
}
The toReturn object, am I handling it correctly? I want to deliver it as an autoreleased object, but I do want to scrap someObject. Is this the pattern to transfer ownership? I've gone over it in my head and on paper, and it seems OK, but I'd rather be informed by someone more enlightened.
Edit This is a very contrived example, just to illustrate the problem at hand. someObject lives across many method calls, and in the end, I want to "dump its guts". This is NOT a Daily WTF example. Please don't ridicule me. :)
The code you have provided in your question is correct. Lets go over why. When thinking about retain/release you need to think about ownership. Objects are typically owned by another object or within some particular scope. In this case getByObject's scope. The object you want to return is the interiorObject which is owned by someObject. But you need to release someObject before you return. The proper thing to do is take ownership of the interiorObject and return an autoreleased copy. And finally release or autorelease someObject.
If ownership was not acquired to the interiorObject before the release of someObject then the interiorObject could be deallocated and we would be returning a dangling pointer. The first time someone tries to send a message to it the program would likely crash.
I'm not 100% sure you need to do the retain / autorelease dance unless your expecting another thread to potentially deallocate your object?
- (SomeOtherType *)getMyObject
{
SomeType someObject = [[SomeType alloc] init];
// ... later on
SomeOtherType toReturn = [someObject interiorObject];
[someObject release];
return toReturn;
}
The retain / autorelease dance will guarantee that the object hangs around to the end of the runloop even if another thread releases it's retains on it.
I'm new to Obj-C and I have a question concerning the autorelease. Is it ok to return an autoreleased variable for several methods? For example:
- (void) methodC {
Object anObj = [self methodB];
//Do something with anObj
}
- (Object *) methodB {
return [self methodA];
}
- (Object *) methodA {
Object anObj = [[anObj alloc] init];
release [anObj autorelease];
}
Will the variable remain valid even if it is returned up a method chain and used at the top? Or does it have to be retained somewhere along the way?
thank you
Yes, it will be valid in this case. You only have to worry about the variable being deallocated if somebody drains the autorelease pool. As long as you've written every function that returns along the way and you don't explicitly drain the autorelease pool, you don't have to worry about objects being deallocated from under you.
In the vast majority of cases, the code in the NSRunLoop takes care of draining the autorelease pool. When you return control from your application code to the API code (such as by returning from a touchesBegan handler etc.), you don't know if the autorelease pool will be drained, so you have to assume in the worst case that it will. In that case, you have to retain any objects you want to keep references to.
For example:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
Object *anObj = [self methodC]; // Your methodC as before -- anObj is valid
[pool drain]; // anObj will be deallocated here
The variable should remain valid. You only need to retain an object if it is actually "owned" by some other object and could be indirectly/unintentionally released along with it. For example, if you extracted an object from an array and then released the array, your object reference could become invalid unless you explicitly retain it.
For more details, see Object Ownership and Dismissal, particularly the sections on Autorelease and Validity of Shared Objects. The latter uses the following code to illustrate how you could "accidentally" make an object reference invalid.
heisenObject = [array objectAtIndex:n];
[array removeObjectAtIndex:n];
// heisenObject could now be invalid.
The following code shows how to mitigate this problem using retain.
heisenObject = [[array objectAtIndex:n] retain];
[array removeObjectAtIndex:n];
// use heisenObject.
[heisenObject release];
after having spent few months in trying to master the syntax and rules, I am going deeper in memory management rules.
One thing I do not understand and causing me confusion is how one creates objects.
Based on what stated in apple memory management guide, the following is a valid approach:
– (NSArray *)sprockets {
NSArray *array = [NSArray arrayWithObjects:mainSprocket,auxiliarySprocket, nil];
return array;
}
because I am not causing any memory leaks.
The reason why is that it's not using alloc for creating array and therefore sprockets is not the owner.
However I am wondering now what's inside arrayWithObjects.
Because it happens that in my apps I often have factory for creating custom objects using something similiar to:
return [[MyObject alloc] initWithParameter:(id)params]; // possible leak
If I want to change with a static method like:
return [MyObject initWithParameter:(id)params];
what could be in initWithParameter for adhere to memory rules ? And what if MyObject extends some other object ? I also find out that method naming rules are important to properly advise programmer, what are this rule ?
Also could you point out a web link where this is explained (I am not yet good in finding docs on apple web site).
thanks
This is the page you're looking for: Memory Management Rules. It all comes down to adhering to the rules of ownership for an object.
If you create an object using alloc then you own that object and must release it. For example:
NSString* str = [[NSString alloc] init];
//do something with your str object
[str release];
str = nil; //don't forget to set it to nil, it's still
//pointing to the (now unallocated) block of memory
If you create an object using a factory method, for example:
NSString* str = [NSString stringWithString:#"blah"];
Then what is happening here is that it is creating the string object using alloc for you and then returning the object but first adding it to the local autorelease pool. To use the example in your question.
return [[MyObject alloc] initWithParameter:(id)params]; // possible leak
return [[[MyObject alloc] initWithParameter:(id)params] autorelease]; //now autoreleased -- no leak
Here is the page on Autorelease Pools. Apple say it better than me.
An autorelease pool is an instance of NSAutoreleasePool that “contains” other objects that have received an autorelease message; when the autorelease pool is deallocated it sends a release message to each of those objects. An object can be put into an autorelease pool several times, and receives a release message for each time it was put into the pool. Thus, sending autorelease instead of release to an object extends the lifetime of that object at least until the pool itself is released (the object may survive longer if it is retained in the interim).
Method naming rules are important as it gives a strong indication as to whether the method returns an autoreleased object. In this example I would name the method:
[MyObject myObjectWithParameter:(id)param]
Hope this has helped.
It is standard practice for alloc and creation methods to return a retained object. Anything that starts with init, create, or the object name will clue other programmers into the purpose of the method.
Even if you create with alloc, if the purpose of your method is to pass on ownership, you should not release the object.
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
I'm just starting out (reading up a lot for the past couple of days). Here's some questions that I have stacked up, hopefully someone can answer them.
1. the (self != nil) check in initializer code. Why do it? To prevent accidental access to some "run-only-once" code that's wrapped up in there? Where from could this accidental access come from? Doing such checks suggest that I don't have control over what's going on.
- (id)init {
self = [super init]
if (self != nil) {
// Code..
}
return self;
}
2. How is it that you don't have to free up anything that static methods return? (or this is the idea I've got)
3. How is str = #"Hi there!" different from
str = [[NSString alloc] initWithString:#"Hi there!"];
As I understand, you have to release str in aquired with second method, but not with first? If so, when does the first one get released? Which one is preferable (not minding the typing length)?
4. What is autorelease, if iphone has no garbage collection? I've noticed something called "an autorelease pool" being created in main.m. Is [myObject autorelease]; a way of adding myObject to the nearest wrapping "autorelease pool", which will release it? Basically, some magic to avoid releasing it yourself? Why use it?
Well, thats it for now. Thanks for any answers!
In Objective-C, it's possible to return an instance other than self from -init. Classes do this, for example, to enforce a singleton instance, or in the case of class clusters. NSNumber, for example, returns a subclass depending on the type of value passed to its initializer. So when you call [[NSNumber alloc] initWithLong:long_value], NSNumber's -initWithLong: initializer is called after NSNumber's +alloc, but a subclass of NSNumber may be returned to the oringial caller. Thus the pattern
self = [super init];
which reassigns self to the value of [super init] so that self points to the actual instance that [super init] returned. If +alloc or the super's init method fails, the result of [super init] may be nil. To avoid, side effects in the case of a failed initialization, the pattern then becomes
- (id) init {
if(self = [super init]) {
// do initialization of instance variables etc.
}
return self;
}
Note that you must return self (or nil or an other instance) from the init method. You should assign self to [super init] and you may check for nil before doing more work.
You may have to release the return value of a staic method. You should read the Cocoa memory management guide. The rule is generally quite simple: If the method you call has "new", "alloc", or "copy" in its signature, the result belongs to the caller and the caller must call -release on that instance or there will be a memory leak. Of course you should call -retain on anything else (i.e. not from an "alloc","new" or "copy" method) you want to keep a reference to and then call -release or -autorelease when you are done with that instance.
str = #"Hi there!", assuming str was declared as NSString *str; assigns the address of the string constant #"Hi there!" to the value of thestrvariable. You do not need to retain or release string constants.str = [[NSString alloc] initWithString:#"Hi there!"];allocates a new string instance. The value ofstrwill be the address of this instance. Each call ofstr = [[NSString alloc] initWithString:#"Hi there!"];again will allocate a new instance. So afterstr2 = [[NSString alloc] initWithString:#"Hi there!"];,str != str2, while afterstr2 = #"Hi There!", str==str2. See this answer as well.
-autorelease adds the receiver to the current NSAutoreleasPool. When the pool is drained (usually at the end of the current run loop iteration, or when the pool is manually drained), the pool calls -release on all instances in the pool. If this -release drops the retain count to 0, the object is deallocated (and -dealloc called) just as with any other -release. Using an autorelease pool is generally frowned upon on the iPhone because it may cause you to accumulate many unused instances in the pool before it is drained at the end of the run loop iteration. If you can use -release instead of -autorelease, you generally should. Again, see the Cocoa memory management guide for more info.
There is a school of thought that in most cases, allocating the self pointer is something that the system should do, and not the programmer.
Also, many people prefer to keep the main line of program flow as un-indented as possible. In which case the initialisation code could be re-written as:
- (id)init {
if (![super init]) {
return nil; // There is a problem so bail early.
}
// Initialisation code here.
return self
}
Will Shipley explains this much better than I do.
1: This check is to ensure that the super constructor returned a new object.
2: Static methods don't refer to an instance
3:
str = #"Hi there!"
This assigns the address of the constant string "Hi there!" to the pointer str
str = [[NSString alloc] initWithString:#"Hi there!"];
This allocates a string and copies "Hi There!" to it. This means that a) str is modifiable and b) needs to be deallocated when you are done with it.
calling
self = [super init];
May return nil if the superclass cannot initialize itself for some reason or other, including memory being unavailable, or certain prerequisites have not been met. If that is the case, you don't want to be trying to set variables of self, or set self as a delegate, or add self to an array, if self is nil.
The autorelease pool is something created upon every event the iPhone sends your application. It is created before any code runs, and released after all your code is done, for each event. Any objects that you call autorelease on will be put into the current autorelease pool. Any objects in the autorelease pool will be released as many times as they were added, after your code completes. In this way, you don't have to worry about who's responsible for releasing an object created by one method and returned to another method.
You can create your own autorelease pools as necessary.
str = [[NSString alloc] initWithString:#"Hi there!"];
This line creates a string that is not in an autorelease pool, so you have to release it manually. Simply writing
#"Hi there!";
returns a string that you don't have to worry about releasing. Extending your previous example:
str = [[[NSString alloc] initWithString:#"Hi there!"] autorelease];
would be another method of creating a string you don't need to worry about releasing.
One difference between garbage collection and autorelease pools is that garbage collection works with circular references. Using autorelease pools, you don't want to have two objects that retain each other and hope that once nothing else refers to them, they will go out of existence; they won't.
If self is nil after the super initialisation then you're probably out of memory. Your only reasonable course of action is to return nil and hope things get handled gracefully further up the stack.
Static methods aren't allowed allocate on the heap, therefore there's nothing to free.
In the first instance, the string is compiled into the data segment of your app and cannot be freed. In the second instance, you are allocating memory from the heap and copying your static string (from the data segment) into it.
It's simple garbage collection. As to why to use it, the simple answer is don't. It's not recommended to use autorelease on the iPhone due to limited resources.