OpenFlow crashes app whem trying to reset/ recreate - iphone

I am trying desperately to change the images on an OpenFlow instance with no luck.
I am kind of giving up so I am trying now to remove the instance and create a new one. But I can't avoid crashing the app.
The code to create it is:
AFOpenFlowView *of = [[AFOpenFlowView alloc] initWithFrame:CGRectMake(0, 100, 320, 380)];
[of setCenter:CGPointMake(160, 240)];
[of setBackgroundColor:[UIColor blackColor]];
[of setDataSource:self];
[of setViewDelegate:self];
[self setPeopleFlow:of];
[self.view addSubview:peopleFlow];
[of release];
Then, on a click of a button I do:
[peopleFlow removeFromSuperview];
[peopleFlow release];
Later on I call the same function with the first block of code to create it again and it's when the application crashes with no log error.
Any ideas on how to clean the OpenFlow object to repopulate it without having to remove/recreate? Or how create/recreate reliably?

When you create the peopleFlow instance, it has a retain count of 1.
Then when you add it as a subview, the super view retains it, so it's retain count is 2.
Then you release it after adding it to the superview, so it's retain count is 1 again.
Then You remove it from the superview, and the superview releases it, so it's retain count is 0 and the object gets deallocated.
Then you try and release it again, and it crashes because you're sending release to a deallocated object.
Long story short, in this case, you don't need to release it after removing it from the superview.
Also, it is good practise to assign nil to a pointer if you release it and don't care about what is pointing at any more. This is because after you release and deallocate an object, the pointer variable is still pointing to the memory that the object used to occupy. Assigning nil to the pointer prevents any bad stuff happening if you try to send a message to whatever the dangling pointer is pointing to.

Related

How to release subviews

In my iPhone/iPad app,
I am adding one subview to my main view.
This subview has one imageview and button.
When to release them ?
My code is here,
customAlertView=[[UIView alloc] initWithFrame:CGRectMake(0, 0, 600, 600)];
UIImageView *imgv=[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"celebration.png"]];
UIButton *btnOK=[UIButton buttonWithType:UIButtonTypeCustom];
[btnOK setTitle:#"OK" forState:UIControlStateNormal];
[btnOK addTarget:self action:#selector(alertOKClicked) forControlEvents:UIControlEventTouchUpInside];
[customAlertView addSubview:btnOK];
[customAlertView addSubview:imgv];
[self.view addSubview:customAlertView];
[imgv release];
[btnOK release];
In one another method I am writing the code.
[customAlertView removeFromSuperview];
My confusion is imageview and button is there If
I release the customalertview here will it releases its subviews automatically.
If yes then no problem.
If NO how to release it
as I have done here released the objects immediately after adding subviews.
It will cause my OK button Unworthy. And will not affect the button click.
So, On removing from superview should I write.
[[customalertview subviews] release];
Your code is correct.
You release them after you've added them to the alert view, as the alert view takes care of retaining them. When you call removeFromSuperview, it'll get released automatically.
I think the points you are missing, based on your comments on the existing answers, are the following:
A view retains its subviews - so if you create a new view object, and add it as a subview to something else, you can then safely release it, unless you'd like to keep a reference around for it yourself.
When a view is removed from its superview, it is released. So if there are no more objects retaining it, it will be deallocated.
When a view is deallocated, it will automatically release all of its subviews, and so on down the tree.
Enable ARC as soon as you are able to.
You are doing it the right way. The customalertview will releases its subviews automatically.
Your object will be released when the release count go to 0, that means in the theory, and if you are coding well, that this object does not have any reference to it anymore.
While you maintain your custom alertView in your view, you have an object retaining your things, so the release count will not be 0 until you remove the customAlertView, because you have added they to the customAlertView, and when you remove the alert, the alert will be released, and all the things that it is retaining will be released too.
Hope it help you to understand how things work.
If you want to know more about memory management you can take a look at apple documentation here
EDIT:
I forgot to mention that you will need to release your custom alert too after you remove it.
If you do not understand the memory management you also can take a look at: http://cocoadevcentral.com/d/learn_objectivec/ section 7

UIView and memory management

A beginners question about how to be memory efficient when using an UIView which contains a couple of images (ca. 500K). I guess if I handle this in the wrong way and call this view ten or twenty times, my app will crash (as I have leaked about 5-10 MB of RAM).
I have an UIView which I create programatically like so:
myView = [[UIView alloc] initWithFrame:0,0,0,0];
To this view I add a couple of images so that it eats up 500K of memory. After I'm done with this view, I'd like to free up the memory again. So I coded:
[myView removeFromSuperview];
myView = nil;
[myView release];
Is this the way to go? I am particularly uncertain about the last release call. Is myView not already released if I remove it from my superview and set it to nil?
Also, would it be a good idea to simply autorelease myView in the first instance, i.e.
myView = [[[UIView alloc] initWithFrame:0,0,0,0] autorelease];
I'd be grateful for any suggestions and corrections.
You’re sending a release message to nil. The correct order for those statements would be:
[myView removeFromSuperview];
[myView release];
and optionally after that:
myView = nil;
For discussion on why to set to nil:
Set pointers to nil after release?
Is It Necessary to Set Pointers to nil in Objective-C After release?
What's the difference between setting an object to nil vs. sending it a release message in dealloc
The superview retains your view when you add it as a subview, and then releases it when you remove it. You still need you release your hold of it. You could use autorelease when allocating it, but since you need to hold on to a pointer to it to be able to send removeFromSuperview, the correct way is to send release when you are done with that pointer (and then set that pointer to nil).
If you set your view to nil before you call release, you will leak the view and then send a message to nil. First you must release the view:
[myView removeFromSuperview];
[myView release];
Then you can set your variable to nil to avoid sending a message to a deallocated instance.
About the autorelease, I think it's just a matter of personal preference, but I find it much easier to track memory issues when doing:
myView = [[[UIView alloc] initWithFrame:0,0,0,0] autorelease];
// add myView to wherever it belongs
.....
[myView removeFromSuperview];
myView = nil;
As others have pointed out, settting to myView to nil before you call release is incorrect and will leak memory.

What's the difference between a ModalViewController and NonModalViewController in Iphone?

The difference of look between the two controllers.
And
Game *game = [[Game alloc] initWithNibName:#"mygame" bundle:nil];
I try to put a autorelease at the end of line. the program crashed.
Therefore I am wondering if
[self presentModalViewController:game animated:YES];
would increment reference count by 1?
[self dismissModalViewControllerAnimated:YES];
would decrement the reference count by 1?
After presenting the controller just release it normally, make sure you don't send messages to game after releasing it though. presentModalViewController:animated: increases it's retain count so you are able to release it with out deallocating the object and you can successfully pass ownership to the current view controller.
Game *game = [[Game alloc] initWithNibName:#"mygame" bundle:nil];
[self presentModalViewController:game animated:YES];
[game release];
Then when it comes to dismissing it you shouldn't retain or release, just call the dismiss method.
Don't necessarily think about the retain count (and whatever you don't call the retainCount method on anything and decide what to write based on when is returned, that method is for legacy purposes only). Just match every init/new/copy with a release/autorelease.
(See listing 6-1 on this Apple doc, for prove that you should release it)
Effectively the [game release]; counteracts the init... and the dismissModalViewController... counteracts the presentModalViewController...
No, presenting a view controller only does that, it presents it. You should be calling retain and release at the appropriate times. It's important to keep track of your retain counts.
Keep in mind that when you allocate and initialize, the retain count increases by one. You will have to release that object later.
If you're still unsure, you need to read the Apple docs on view controllers and memory management.

Should I release an UIImageView added to my view if I will detect touch on it later on?

I've learnt that if you create an object, you own it and need to release it when you're done with it. In this case I create an UIImageView and add it to my view like this:
myImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"image.png"]];
[myImageView setFrame:CGRectMake(10,10,100,100)];
[self.view addSubview:myImageView];
[myImageView release];
If I later on want to detect touch on myImageView like this in my touchEnded-method:
if([touch view] == myImageView){
NSLog(#"TOUCHED!");
}
This works, but is this correct, since I now used myImageView after releasing it?
And how do I release myImageView from the self.view that I added it to earlier?
The cardinal rule of Cocoa memory management is that you should retain those things you care about, and release those things you do not care about. There are a very small number of exceptions to prevent retain loops (delegates and datasources are never retained), but this is the rule you should follow.
In this case, if you are storing the image in an ivar, I would continue to retain it, regardless of the fact that its superview will always retain it, and so you don't "have" to. But if the view is removed from its superview, you will wind up with a dangling pointer, and then you will crash, so I code defensively against that by retaining. If you used an accessor here (which you should), then this would be automatic and much safer.
Apple has grown more consistent about this in iOS, switching their recommendation about IBOutlets. On Mac, you do not retain your IBOutlets, but in iOS, Apple explicitly instructs you to do so. This is similar to the situation you are discussing, and I agree with Apple's move towards a safer approach.
As long as your myUIImageView object has a retain count > 0, it will still exist and you can continue using it. When you first add it as a subview, it gets a retain message so it's retain count is likely 2. Then you send it release, so its retain count is reduced to 1. This means it still exists in memory. Now, if you sent it release again, or sent it removeFromSuperView then its retain count would be zero, and you'd lose it.
The behavior is erratic, sometimes you may see it works, sometimes you get a crash.
If you want to use that variable to point to your image view, retain the ivar (by using a retain property). This way you ensure that the image view is available for your controller class to use.
Assuming myUIImageView is an ivar of your custom UIView subclass, your code will work as long as your image view stays in his superview. The image view instance may be deallocated and you may end with an invalid pointer referencing a deallocated object. At best you crash.
According to memory management guidelines, you should consider your image view <-> custom uiview subclass relation as wether:
strong reference. You own the image view (as you created it), and are responsible for retaining / releasing it
weak reference. You don't own the object, thus keeping a reference to it may be dangerous.
in your case, it's probably a strong reference. your myUIImageView ivar should be a nonatomic retained property of your object.
If you need to access your UIImage at some point in the future, you need to retain it.
How you do this is at your discretion, but you should not rely on the UIView to retrain your objects for you. The situation you've created works for now, but it's fragile.

iOS Development: Why are the retain counts for my view controller so strange?

I'm diving into iOS development and I'm building a navigation based app that wasn't fully releasing one of the views that was being pushed onto the nav stack. This is problematic because the view controller is never being deallocated, so the memory it uses just builds up every time the view controller is pushed on to the stack. So after investigating the issue, I found the retain counts for the view controller were really strange. The view controller in question is pushed on to the stack once a countdown timer reaches zero.
Here's the code that creates the view controller in the timer callback, displays its retain count, and pushes it onto the nav stack...
-(void)updateCountDownTimer //Defined in MyViewController_A class
{
[self setTimeRemaining:([self timeRemaining] - 1)];
[[self countDownLabel] setAlpha:1];
[[self countDownLabel] setText:[NSString stringWithFormat:#"%d", [self timeRemaining]]];
//Fade out the current time
[UIView beginAnimations:#"FadeAnimation" context:nil];
[UIView setAnimationDuration:1];
[[self countDownLabel] setAlpha:0];
[UIView commitAnimations];
if ([self timeRemaining] == 0)
{
MyViewController_B *myvc_b = [[MyViewController_B alloc] initWithNibName:#"MyView_B_iPhone" bundle:nil];
[[self navigationController] pushViewController:myvc_b animated:YES];
NSLog(#"updateCountDownTimer: %d", [myvc_b retainCount]);
[myvc_b release];
[[self countDownTimer] invalidate];
[[self countDownLabel] setHidden:YES];
}
}
and here's the code that pops the view controller off the nav stack once the pause button is pressed...
- (void)pauseButtonPressed:(id)sender
{
//Stop the timer
[puzzleTimer invalidate];
NSLog(#"pauseButtonPressed before pop: %d", [self retainCount]);
//return to the previous view
[[self navigationController] popViewControllerAnimated:YES];
NSLog(#"pauseButtonPressed after pop: %d", [self retainCount]);
}
and here's the console output that shows really strange retain counts throughout the process...
2010-12-02 17:50:38.062 MyApp[821:307] updateCountDownTimer: 5
2010-12-02 17:50:40.453 MyApp[821:307] pauseButtonPressed before pop: 2
2010-12-02 17:50:40.462 MyApp[821:307] pauseButtonPressed after pop: 4
I'm new to iOS development, but the code seems pretty straightforward to me, so I don't know what I'm missing.
Thanks so much in advance for your wisdom!
UPDATE: It looks like the Leaks instrument is reporting a leak on the line of code that pushes the previous view controller onto the stack (that is, the view controller responsible for pushing the view controller in question). The code is once again very straightforward, so I don't know why it's reporting a leak...
MyViewController_A *myvc_a = [[MyViewController_A alloc] initWithNibName:#"MyView_A_iPhone" bundle:nil];
[[self navigationController] pushViewController:myvc_a animated:YES]; //<--Leak being reported here
[myvc_a release];
*UPDATE:*Found the problem, it was just as everyone was saying and the same problem as was shown in the link posted in the comments below, I had live objects still referencing my view controller, which prevented it from deallocating. In my case, I had two timers that were targeting my view controller and those timers weren't being invalidated before I popped the view off the stack, which meant there were two live objects still referencing the view controller. Here's a snippet I found in the Apple docs which uncovered the problem...
Perhaps more importantly, a timer also
maintains a strong reference to its
target. This means that as long as a
timer remains valid (and you otherwise
properly abide by memory management
rules), its target will not be
deallocated.
Anyhow, thanks again to everyone who helped!
You're not missing anything -- instances of UINavigationController just do strange, strange things to the retain count internally.
You should only worry about the retainCount if you see a specific memory leak that you're trying to patch up. In this case, of course, you DO have a problem... the retainCount just doesn't help, since it's so bizarre.
You might check if dealloc is getting called on MyViewController when you do the pop. Also, before you test, comment out the lines that check the retainCount. Calling retainCount will sometimes add to the retainCount.
To really nail down what's going on, in Xcode, go to the Run menu, and select Run With Performance Tool > Leaks. Push and pop that view controller, and you should see it pop up as a leak. You'll be able to see all of the retain and release calls on the object.
If you're really stuck, Apple's guide to Finding Leaks has a few more clever solutions. Good luck!
There is nothing wrong with your code as far as memory management is concerned.
You should not rely on retain counts to check if your objects are being released properly as the system will also be retaining what it needs and releasing when appropriate. For instance when you add your view controller to the stack it gets retained by the nav controller along with its subviews and when it's popped out it gets send a release message which propagates all of its subviews.
The general rule is if you alloc, retain or copy an object, it is your responsibility to release it. Everything else is dealt with by the system and will be flushed with the auto release pool.
Never, ever, ever look at the retain counts of your objects. They should not be used programmatically, and are misleading when you are trying to debug your code.
Here's why: You know that in your code, you are making calls to retain and release to manage your retain count. But you may also be making calls to -autorelease, which causes your retain count to be decremented at a later date over which you have little or no control. Worse, any time you pass a reference to your object to an object that you do not control the implementation of (which is likely to happen to most of the objects you create), the receiving object may make its own adjustments to the retain count - and that object may pass your object to yet other objects, which also adjust the retain count.
The point is, you should not ever look at the retain count of your objects for any reason at any time. They will only serve to confuse you. Your job is to manage your own claims to an object correctly, and trust that the code written by others is doing so as well.