I have some doubts in objective-C programming. I have function like this.
+ (NSManagedObjectContext *) newContext {
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil)
{
NSManagedObjectContext* managedObjectContext = [[[NSManagedObjectContext alloc] init] autorelease];
[managedObjectContext setPersistentStoreCoordinator:coordinator];
return managedObjectContext;
}
return nil;
}
But when I run analyse on my project I am seeing something like this with warning
"Object with a +0 retain count returned to caller where a +1 (owning)
retain count is expected"
Can someone point me out so as to why Xcode is giving me a warning here. What is the correct way to return any variable?
The problem lies not within your code but within the name of your method. In Objective C, methods whose names start with init or new are assumed by the analyser to return an object with a retain count of 1. You are returning an object with a retain count of zero, therefore your method name should not contain new.
Related
I get leaks if I dont put it in dealloc. I get a crash EXC_BAD_ACCESS If I do. I cannot see anything wrong with this code. The bad access is pointed at [events release]. Have I made a mistake in the code below or is Instruments just having a laugh at my expense?
events is an NSArray
#interface EventsViewController : UITableViewController
{
#private
NSArray *events;
}
- (void)viewDidLoad
{
events = [[self getEvents] retain];
}
- (void)dealloc
{
[events release];
[super dealloc];
}
- (NSArray*)getEvents
{
NSMutableArray *response = [[[NSMutableArray alloc] init] autorelease];
//Some sql
while(sqlite3_step(statement) == SQLITE_ROW)
{
Event *event = [[[Event alloc] init] autorelease];
event.subject = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 0)];
[response addObject:event];
}
return response;
}
Update
A lot of you are saying the code is fine which is a plus. I dont manipulate events elsewhere - I have removed any code that does to try and single out the crash. Perhaps its in the parent view?
This is the click event that pushes the EventsViewController:
- (void)eventsClick:(id)sender
{
EventsViewController *eventsViewController = [[EventsViewController alloc] initWithNibName:#"EventsViewController" bundle:nil];
eventsViewController.anywhereConnection = anywhereConnection;
eventsViewController.contact = contact;
[[self navigationController] pushViewController:eventsViewController animated:YES];
[eventsViewController release];
}
The crash is actually happening when I return to the parent view. (I think it is considered a parent in this scenario). But perhaps the [eventsViewController release] just triggers dealloc in the EventViewController.
Have you considered just refactoring your code to use ARC? It works with iOS 4 and up and will make your life a lot easier. There are plenty of tutorials out there that will guide you how to do it, and will remove the need to manually figure out the nuances of memory management.
If your Events object has property 'subject' set as assign, then the results of stringWithUTF8String: will not be retained. (Same thing if Events is a C++ object.)
The stringWithUTF8String: method returns an auto-released object that will be released at the next turn of the event loop.
There is a huge difference when you reference a variable via "self", and when you don't.
When you use
events = [[self getEvents] retain];
the memory allocated in getEvents never gets stored in the class property and is basically a leak.
You need to use
self.events = [self getEvents]; // no need to use retain if property is correctly defined.
Then
[events release];
should work fine.
try putting
events = nil;
in dealloc.
How to write right in this situation:
I have some method, that return NSMutableArray*. Because method not started with init, new or alloc, how write in apple memory-management guide, i return autorealese object.
-(NSMutableArray*)someMethod {
NSMutableArray *array = [NSMutableArray alloc] init] autorealese];
//Some code here
return array;
}
And i have some another methods, that call this one:
-(NSMutableArray*)method1 {
NSMutableArray *array = nil;
if(condition){
array = [self someMethod];
}
return array;
}
-(NSMutableArray*)method2 {
NSMutableArray *array = nil;
array = [self method1];
}
Code work.But XCode analyze tool says that in method2 i get object with count 0. So, how to write this code good?
There is nothing wrong with your code, except that the method2 will return the array that is autoreleased. Thus whatever is calling this method should retain the return value.
Creating an autoreleased NSMutableArray and returning it.
-(NSMutableArray*)someMethod {
NSMutableArray *array = [NSMutableArray alloc] init] autorealese];
//Some code here
return array;
}
Method1 uses autorelease NSMutableArray from someMethod and for the life of Method1 the array will not be autoreleased. That's one of the rules of memory management in objective-c that object lives through the method cycle.
-(NSMutableArray*)method1 {
NSMutableArray *array = nil;
if(condition){
array = [self someMethod];
}
return array;
}
Method2 uses still waiting to be autoreleased NSMutableArray from method1. It's important to notice that b/c you have a condition in method2 the array might be nil.
-(NSMutableArray*)method2 {
NSMutableArray *array = nil;
array = [self method1];
}
So in another words, you are passing autoreleased object along your methods. There is nothing wrong with this. You just have to remember that if you want to store the value of method2 you need to retain it, or it will get autoreleased.
Because of your condition in method1 the analyzer will complain b/c it's not guaranteed that the method1 will return an object, there is a possibility it will return nil.
I'm having the code as below.
- (void)viewDidLoad
{
NSArray* myarr = [self createArray];
for (NSString* str in myarr)
{
NSLog(#"%#",str);
}
[myarr release];
}
-(NSArray*)createArray
{
NSArray* arr1 = [[NSArray alloc] initWithObjects:#"APPLE",#"MAC",#"IPHONE",nil];
return arr1;
}
When I "Build & Analyze", its showing two leaks. One at [myarr release] saying, incorrect decrement of the reference count of an object that is owned at this point. and Other at return arr1, saying, Potential leak of an object allocated on line 152 and stored into arr1.
From my above code, the method "createArray" is returning a pointer and I'm releasing it as well. Is my way of coding right or wrong?
From my above code, the method "createArray" is returning a pointer and I'm releasing it as well. Is my way of coding right or wrong?
that depends on how you look at it.
1) the ref counting looks ok
2) the static analyzer flags objc methods based on names, in some cases. so the issue will likely vanish if you rename createArray to newArray, or something named new*. so it expects a convention (the ones used by Apple) to be followed.
therefore, it's the message that's bit shallow, it doesn't really analyze the program, but bases its findings/results on convention -- and not an actual evident issue which a human can read.
If you're just using the array in your viewDidLoad method, then you don't need to alloc an array in there at all. You can just use an autoreleased array returned as 7KV7 suggested. You can return an autoreleased array in your -(void)createArray as well without alloc'ing an object. Here is an example.
- (void)viewDidLoad
{
NSArray* myarr = [self createArray];
for (NSString* str in myarr)
{
NSLog(#"%#",str);
}
}
-(NSArray*)createArray
{
return [NSArray arrayWithObjects:#"APPLE",#"MAC",#"IPHONE",nil];
}
If you don't have to alloc an object to use it, it makes for less, and cleaner code, IMO.
Try this
- (void)viewDidLoad
{
NSArray* myarr = [[NSArray alloc] initWithArray:[self createArray]];
for (NSString* str in myarr)
{
NSLog(#"%#",str);
}
[myarr release];
}
-(NSArray*)createArray
{
NSArray* arr1 = [[NSArray alloc] initWithObjects:#"APPLE",#"MAC",#"IPHONE",nil];
return [arr1 auotrelease];
}
The problem with your code is that
You do not allocate myarr using alloc or new so you do not take ownership of the object. Hence the issue in release.
You allocate arr1 so you take ownership of the object and you return arr1. Hence you do not release it. That is the reason for the leak.
I was running Leaks tool and discovered a massive leak in my Dictionary mutableDeepCopy but I can't figure out what's wrong with the code. Any suggestions?
#interface RootViewController : UIViewController{
NSDictionary *immutableDictionary;
NSMutableDictionary *mutableDictionary;
}
Here is the line of code that's highlighted in Instruments
self.mutableDictionary = [self.immutableDictionary mutableDeepCopy];
Here is the method for creating a mutable copy of a Dictionary
#interface NSDictionary(MutableDeepCopy)
-(NSMutableDictionary *)mutableDeepCopy;
#end
Here is method implementation, I've highlighted the code that Leaks saids is leaking 100%
- (NSMutableDictionary *) mutableDeepCopy {
NSMutableDictionary *dictionaryToReturn = [NSMutableDictionary dictionaryWithCapacity:[self count]];
NSArray *keys = [self allKeys];
for(id key in keys) {
id value = [self valueForKey:key];
id copy = nil;
if ([value respondsToSelector:#selector(mutableDeepCopy)]) {
copy = [value mutableDeepCopy];
} else if ([value respondsToSelector:#selector(mutableCopy)]) {
copy = [value mutableCopy]; //This is the Leak
}
if (copy == nil) {
copy = [value copy];
}
[dictionaryToReturn setValue:copy forKey:key];
}
return dictionaryToReturn;
}
You need to analyse this in light of Apple's Memory Management Rules.
Starting with this line:
self.mutableDictionary = [self.immutableDictionary mutableDeepCopy];
I would expect mutableDeepCopy to return an object I own, so at some point I need to release or autorelease it. e.g.
NSMutableDeepCopy* temp = [self.immutableDictionary mutableDeepCopy];
self.mutableDictionary = temp;
[temp release];
or
self.mutableDictionary = [[self.immutableDictionary mutableDeepCopy] autorelease];
So now we need to look at mutableDeepCopy. Because it has 'copy' in the name it needs to returned an "owned" object which, in practice means "forgetting" to release the returned object. You have already failed to do that when you create the returned object in the first line, since dictionaryWithCapacity: gives you an object you do not own. Replace it with
NSMutableDictionary *dictionaryToReturn = [[NSMutableDictionary alloc] initWithCapacity:[self count]];
Now you own it.
It is important that you make your mutableDeepCopy obey the rules because it means you can treat the objects returned from mutableDeepCopy, mutableCopy and copy in exactly the same way. In all three cases you own the object copy that you insert into the array. Because you own it, you must release it or it'll leak as you found out. So, at the end of the loop, you need
[copy release];
That'll stop the leak.
How is your property declared? If is is retain or copy, then this doesn't leak.
Your problem is that the name mutableDeepCopy suggests that it returns a retained object, and not an autoreleased one as it actually does.
Edit:
And at the mutableDeepCopy itself, you need to release the copy variable after adding to the dictionary.
mutableCopy increments the retain count of the object, as does setValue:forKey:. This means that when dictionaryToReturn is dealloc'ed, the object that had mutableCopy called still has a retain count of one.
Try doing this instead:
copy = [[value mutableCopy] autorelease];
Whenever I read about how to avoid memory leaks, I always came across a concept that
"Number of alloc must be equal to number of release".
But I came across a concept where we require more than one release. Like What I used to practise was as follows:
(NSString*) func1
{
NSString* result = [[NSString alloc] initWithFormat:#"Test String"]];
return result;
}
(void) func2
{
NSString* temp = [self func1];
[temp release];
}
But I came across a concept of retain count which says that in the above case the memory is not deallocated for the string since the retain count for the string is 1 at the end. So the right practise is
(NSString*) func1
{
NSString* result = [[NSString alloc] initWithFormat:#"Test String"]];
[result autorelease];
return result;
}
(void) func2
{
NSString* temp = [self func1];
[temp release];
}
So now I have two releases for deallocating the memory which is a contradictory to my above sentence which I read on most of the blogs ""Number of alloc must be equal to number of release".
I am little bit confused about the above stuff. Becoz if I autorelease the string in the first function and want to use the string in second function for a long time, and what if the release pool is flushed in between, on the other side if I dont use autorelease it will still block the memory.
So whats the correct way of doing it.
At the time you call alloc whatever is returned will have a retainCount of 1. Calling release on that object will cause it to be deallocated (it's retainCount will drop to 0). In your first example, then, the second line of func2 will deallocate the NSString* you received from func1, and your memory management chores are complete.
In the second example you are tossing result in func1 into the current autorelease pool, which will cause it to become deallocated when the pool drains. You do not want to attempt to manage the memory of that object once it has been placed into the pool- it is no longer your responsibility.
If you want to generate the string and keep it around for a while (e.g., through the lifetime of several autorelease pools), I would recommend the first form of memory management.
The correct way is this:
(NSString*) func1 {
NSString* result = [[NSString alloc] initWithFormat:#"Test String"];
// retaincount == 1
return [result autorelease];
}
(void) func2 {
NSString* temp = [self func1];
// retaincount == 1
// temp is autoreleased, therefore no [release] is necessary.
}
Autorelease is automatically done at the end of the run loop, that means it cannot be emptied while your code is doing something. -> The code you have is safe. This isn't true for multithreaded application!
(NSString*) func1
{
NSString* result = [[NSString alloc] initWithFormat:#"Test String"]];
return result;
}
[result retainCount] is 1
(void) func2
{
NSString* temp = [self func1];
[temp release];
}
[temp retainCount] is 0
No need for autorelease.
From Memory Management Rules:
This is the fundamental rule:
You take ownership of an object if you create it using a method whose name begins with “alloc” or “new” or contains “copy” (for example, alloc, newObject, or mutableCopy), or if you send it a retain message. You are responsible for relinquishing ownership of objects you own using release or autorelease. Any other time you receive an object, you must not release it.
The following rules derive from the fundamental rule, or cope with edge cases:
As a corollary of the fundamental rule, if you need to store a received object as a property in an instance variable, you must retain or copy it. (This is not true for weak references, described at “Weak References to Objects,” but these are typically rare.)
A received object is normally guaranteed to remain valid within the method it was received in (exceptions include multithreaded applications and some Distributed Objects situations, although you must also take care if you modify the object from which you received the object). That method may also safely return the object to its invoker.
Use retain in combination with release or autorelease when needed to prevent an object from being invalidated as a normal side-effect of a message (see “Validity of Shared Objects”).
autorelease just means “send a release message later” (for some definition of later—see “Autorelease Pools”).
In general, I'd feel safer to do a retain on a return value, like the one in the "func 2":
(NSString*) func1 {
NSString* result = [[NSString alloc] initWithFormat:#"Test String"];
return [result autorelease];
}
(void) func2 {
NSString* temp = [[self func1] retain];
// Do something with temp
[temp release];
}
Is this unnecessary? I understand that in this example "temp" is just a local variable. But it could have been an instance variable, which may need to be retained.