Releasing after pushing in iOS - iphone

So I have the following code where I am releasing an object after pushing it to another view. When I analyse it I get the error - Incorrect decrement of the reference count of an object that is not owned at this point by the caller. Would anyone know how to fix this? I've tried so many options each time getting a different memory leak
- (void)showCurrentArticle:(id)sender {
if(animating)
return; //it is already there
animating = YES;
JsonViewController *newsController = [(JsonViewController *)[self.newsNavController.viewControllers objectAtIndex:0]retain];
newsNavController.title = #"Parliament";
Item *currentItem = (Item *)[self.fetchedObjectsArray objectAtIndex:currentItemIndex];
NSString * urlString = [CONST_FEED_DISCRIPTION_URL stringByAppendingString:currentItem.guid];
[newsController initWithURLString:urlString date:currentItem.date];
[self.navigationController pushViewController:newsController animated:YES];
[newsController release];
}

This code takes a view controller that's already present in the navigation stack, reinitialises it, then pushes it onto the stack again. This doesn't seem right at all. You probably should be creating a new view controller. What's the background on this? What are you trying to achieve?

You are popping, change a title, than you are doing an initialization...
Decide if you will do deep clone of JsonViewController (alloc, init, copy field values) or just reference copy (retain). It will be mess later if you try to mix.

Your retain and release of the newsController object are unnecessary. That is why you are getting the warning. It looks like newsController is owned by the newsNavController object, which will retain it. The only reason you would need to retain newsController in this code is if you needed to use it outside the scope of this method. Since you don't need to retain it, you don't need to release it, hence the error. You may be assuming that the -initWithURLString:date: method is incrementing the retain count, but it is only new, alloc, and retain that do this. You should probably rename that method to not use the term init to avoid confusion.

What are you doing with -initWithURLString:date:??? Are you just adding a url? Then you should call it addURL...... If you really initialize it again, you set the pointer of the newsController variable to a new object. The first object it pointed to gets lost -> leak.
I assume you named the init method wrong and just add a url to a controller, which is already in the stack and add it again with a higher retain count, but still the very same object.
Don't do this. Copy the object or better - create a new instance of the viewController!!!

Related

How the local and member variable behaves in Objective C - IOS

I have not clear how Objective C handle the local and member variable, as I am new to this.
Consider I am creating a view inside a function like this...
fun () {
new_class *var = [new_class alloc] init]
// some code to push the view here...
}
everything works fine here, now my question is var is a local variable, when the function scope ends, will it die or not? if it dies how the view is working properly when I am doing some action in it...
thanks...
The var should be release, if it doesn't have other objects point at it. The thing is:
if it dies how the view is working properly when I am doing some action in it
If your "var" is an UIView for instance, and you [self.view addSubview:var], now you have two objects pointing at it: *var and your self.view, that's why everything is ok.
The pointer var will go out of scope and be "deleted", but the object to which it points won't be deleted until it is later released (either manually or through ARC, if enabled).
No it won't die. The variable is scoped local to the function, so the compiler won't let you access var outside your fun() method, however you will have a memory leak (assuming no ARC)
You've allocated memory, but haven't released it.
You can release it manually, or make use of the AutoReleasePool and have it release when the pool is drained.
In newer version of IOS, Apple has added support for Automatic Reference Counting (ARC), where the compiler will add the [obj release]; statements for you.
From the comments:
If you have an object that is placed on a stack, and you later want to release it. When you pop the UIView, a pointer to that view is returned. If you assign that to some local variable, you can release it when you are ready to:
UIView * myView = [someViewHandler popView];
[myView release]; myView = nil;

ARC delegate issue

I need to download some images from server. So I created a seperate class to handle NSURLConnection delegates.
At the end of didFinishDownloadingData, I called a delegate method like [(id)delegate performSelectorselector(finished:) withObject:receivedData]
I have a view controller called ListImages.
I created the above connection class from ListImages class and assigned connection.delegate = self. After image loaded from server the method -(void)didFinishDownloadingData:(NSData *)data; was called successfully, and I could display that image.
My problem starts now. To handle some common tasks, I created a new class called SharedMethods which is a subclass of NSObject. I allocated connection class as
Connection *conn = [[Connection alloc]init];
conn.delegate = self;
[conn startDownload]; //called a method which starts nsurlconnection.
I am using ARC so not released that object. My applicaion got exception in method, (In Connection class)
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[(id)delegate performSelectorselector(finished:) withObject:receivedData]; //Got an exception in this line
}
The exception was [SharedMethods retain] message send to deallocated object. I dont think I have released anything because I am using ARC.
There was also a problem while callingUIAlerView delegates inside a Class which is a subclass of NSobject. It is not called any how. My doubt is, is there any problem with using a NSObject sublass? Is there anything to consider when using NSObject sublass ?
Thanks in advance.
Using ARC doesn't mean than objects never receive the release method, or that they never get deallocated. It just means that you don't have to make explicit calls to retain and release, and that happens automatically.
The problem here is that your objects are getting deallocated because no one is owning them. Your specific problem is that SharedMethods is being deallocated because it's not getting retained, but I can't show you how exactly that's happening because you didn't post the relevant code.
I can, however, show you that you're not managing your Connection properly, and hopefully that can help you figure out what you're doing wrong with SharedMethods.
So you create Connection with alloc init, which with retain-release code would give it a retain count of 1, but since you're not using ARC anymore that's not really relevant. Unless some other object asserts ownership of the Connection, ARC will automatically insert a call to release to bring the retain count back to 0 (it's kind of like if ARC automatically inserted an autorelease).
Since you don't assign Connection to a strong or retain property, or put it in a collection, no other object is asserting ownership to it. So once execution reaches the end of the scope where the variable conn is defined, it will get released and deallocated.
So in ARC, much like in manual retain-and-release code, you still need to make sure objects are owned by some other object in order for them to stick around. The only difference is that you don't need to manually call retain and release, you just have to think about the object ownership graph—which object is owned by which other object—and make sure that any object you want to stick around is owned by some other object.
So to reiterate, you need make sure that SharedMethods is owned by some other object.

My uitableview.delegate is getting set to null. Any ideas why, or how I can figure out why?

I presume this isn't a common problem, which makes it a bit more difficult to answer. Any help is appreciated though.
I need to call this delegate a number of times in my app, and i noticed that after a number of times, the delegate starts to come back as NULL (and hence stops responding). I put an nslog everywhere the delegate gets called, so i know that at this point, it's fine:
UIImage *image = [self.delegate largeThumnailForMediaAtIndex:indexPath.row];
Then the next time this line gets called, the delegate is set to NULL. No lines around it call or set the delegate. I put an NSLog on the setDelegate method too, and that didn't get called before it changed to NULL.
Any code you might need to see, let me know. Any ideas you want me to try out, let me know about that too.
Thanks for your help.
EDIT: Bizarre, but might help to lead to a solution. I put an NSTimer scheduledTimer.. in the class which gets made the delegate, and got it to fire that once a second so I could see if it turned null at any point. The result i got, however, was that this time it didn't turn null. It returned all of the delegate methods. When i took the timer out, it goes back to returning NULL. Obviously having a timer in there is an odd workaround 'solution'. I'm hoping this rings a bell for someone and gives them a clue to where the problem might lie?
EDIT 2: I've solved this problem by, instead of using this code in my AppDelegate:
JCreateViewController *create = [[JCreateViewController alloc] init];
[create.navigationBar addLeftButtonWithTitle:#"Back" type:JButtonTypeArrow];
create.navigationBar.title = #"Entry #17";
[self.window addSubview:create.view];
Declaring it in my header file, then using this:
self.create = [[JCreateViewController alloc] init];
[self.create.navigationBar addLeftButtonWithTitle:#"Back" type:JButtonTypeArrow];
self.create.navigationBar.title = #"Entry #17";
[self.window addSubview:self.create.view];
I don't understand why this makes a difference though. I'd love to know, if anybody does know?
Looks like you're using ARC. Whatever this object is, nothing owns it. Nothing has a strong reference to it, so it gets released, and then at some point it gets deallocated.
JCreateViewController *create = [[JCreateViewController alloc] init];
This is a local variable. When the variable goes out of scope at the end of the method, you can't access that object anymore. Under MRR, this would be a leak. Under ARC, the object is going to die, just like it was in an autorelease pool.
self.create = [[JCreateViewController alloc] init];
By creating a property (presumably strong) and putting the controller into that property, you've given whatever self is an owning reference to the controller. It will now live as long as the property isn't reassigned or set to nil.
The timer fixed things because the timer retains its target (which I believe was the controller (your question is rather unclear)), and the timer itself is retained by the run loop. So the run loop keeps the repeating timer alive and the timer kept your controller alive.
In short, make sure something owns this object and it'll stick around.

Keeping a class running in the background when another has been started

I will try and explain this as best as possible if I have this code here
ViewTwoController *home = [[ViewTwoController alloc] initWithNibName:#"contentscreen" bundle:nil];
[self presentModalViewController:home animated:YES];
[home release];
I will start a new .m and .h class. What I would like to try and do however is when this is called, have the .m and .h class where it was called from running in the background so I do not lose data.
The best example I can think of is with Android. If you begin a new class, and don't add the finish() statement in the class the call was made from, the previous class runs behind the current class (that was pushed to the front) and maintains all the data it originally had, so if you hit a return button, you will see the information you had moments ago. Is this possible? I can try add more detail if people cannot understand what I am trying to do.
You need to understand a objects life cycle a little better.
An object is brought into existence generally with a 2 part process.
allocation - (grabbing the memory for the object and its members)
initialization - (setting the object up for use)
This can be combined into single step with the +new class method which combines alloc and init.
lets introduce an example class called MyClass and an object of that class called myObject. By convention classes start with uppercase letters and objects start with lowercase letters. So Without further ado, some code:
MyClass * myObject;
this this makes an object pointer, but doesn't allocate any memory for it or direct the pointer to reference anything.
myObject = [[MyClass alloc] init];
this actually creates an instance of MyClass, passes the -init message to it, then assigns the return value of the init message to myObject. At this point the reference count of this object is 1.
myObject can potentially go out of scope but that alone doesn't free the memory that was allocated during the alloc step.
in order to free that memory a release message will need to be passed to the object.
[myObject release];
The effect of release is to decrement the reference count, if the reference count is already 1 then the object will then be passed the -dealloc indicating that it is actually being freed.
back to your question... essentially [self presentModalViewController:home animated:YES]; ends up calling -retain on home, so that it will not be destroyed until you dismiss the modal view controller. In affect when you call release or autorelease you aren't dealloc'ing the object, just telling the object:
"Hey, I don't need you anymore, and if no one else does either then free up all the memory that you grabbed earlier".
Your problem has nothing to do with "class running in the background" but more with how you manage your data.
When you present a modal view controller, its parent (the view controller you presented it from) isn't destroyed (unless you specifically release it, which would probably crash your app later). So if you're wondering whether its still in memory; it is. As for tasks still running, it depends on what those tasks are. For example, you can still send it messages (call methods) and it will gladly receive those messages from your or from a delegate and perform whatever action it has to while it's off-screen.
Hope that helped.
In this case you are presenting new view controller. The main thread will be in the new controller presented. If you want something to run in background in the previous view controller then you can create a background thread. This can be done using [self perfomselectorInThebackground ... ] Or some other methods like GCD. (The main thing is you should not block Main thread)

Tricky memory management in objective-c

After reading:
Memory management of a view controller in Objective-c
and
Does UIView's addSubview really retain the view?
I wrote the following code to toggle a subview:
#synthesize switchableView, viewSelector, currentSubview;
//...
if(switchableView.subviews.count != 0)
[[switchableView.subviews objectAtIndex:0] removeFromSuperview]]
self.currentSubview = (veiwSelector.selectedSegmentIndex == 0) ?
[ViewA new] : [ViewB new];
[switchableView addSubview:currentSubview.view];
//[currentSubview release]; //<---crashes if I uncomment this line
It seems to run fine if I comment out that release line, but I can't wrap my head around why. Here's the way I understand what happens and maybe someone can tell me where I go wrong:
So lets consider currentView:
A gets alloc-ed by the 'new' message--retain count=A:1
A gets retained by the setter--retain count=A:2
A's view gets (supposedly) retained--retain count=A:2.1
next time through...
A's subview gets released count=A:2
B gets alloc-ed by the 'new' message--retain count=B:1, A:2
A gets autoreleased by the setter-- B:1, A:1
B gets retained by the setter--B:1, A:1
nothing ever gets rid of A?
So should I change my code, or am I wrong about the way memory management works in this language...or both?-
Ok, step one, ignore the retainCount. It's one of those things Apple should rename to something like lsdjiofsudfoiwjeriowhfiuwhrteiuhweifhsdjkfhsiurwoieuriosfho so people won't guess it's name, and not list it in the documentation. For your purposes, it's entirely useless, so ignore it.
Now that I've said that, let's consider something: addSubview: DOES retain its argument, and removeFromSuperview releases the receiver.
Finally, it's hard to tell what currentSubview is. It has a view property which would lean towards a VC, however, the way you're using it by itself, would indicate its a normal view. Perhaps you can clarify so I can continue my answer.
Your understanding of retain and release is correct, as is your code. That suggests that the problem lies outside of the code you've posted. For example, you would have this problem if your currentSubView property was defined as assign instead of retain.
You code is not structured well, however. This would be much clearer:
self.currentSubView = [[ViewA new] autorelease];
Furthermore, view controllers are meant to be cached, not created and released each time the user toggles a display. Typically, you create your view controllers beforehand, and access their .view property when necessary to display the view. UIViewController will automatically deallocate non-visible views in low memory conditions, and re-allocate their view when the .view property is accessed.
Change the release line to
self.currentSubview = nil;
and I think you'll be fine. You're releasing, but not setting the property to nil. So, when it gets re-assigned next time through, release will be called again on it. But you already released it so... boom.