UIActivityIndicatorView nillify makes it crash - iphone

For the code below if I nillify the indicator by "self" it crashes if dont use self than no crash.
Isnt it the rule that I should always use "self" to access ivars created and retained by #property ?
#property(nonatomic,retain) UIActivityIndicatorView* activityIndicator;
if(activityIndicator!=nil){
[activityIndicator removeFromSuperview];
//self.activityIndicator = nil; //crashes!
activityIndicator = nil; //does not crash
}

Generally speaking:
self.activityIndicator = nil; //crashes!
will release the activityIndicator, so this is possibly related to the crash.
activityIndicator = nil; //does not crash
will not release the activity indicator, you don't have a crash, you have a memory leak.
In your concrete case, possibly the crash depends on the fact that when you execute this:
[activityIndicator removeFromSuperview];
the activity indicator is released; now, if it also happens that retain count goes to 0, the object is also deallocated, but the property is not updated to reflect the fact that the object has been deallocated. SO, when you set it to nil, the setter tries to release it, but the obejct dos not exist anymore and hence the crash.
This is a guess. It should not happen if you retained correctly the activity indicator in your class. So, either you review the code where you create the activity indicator and the places in your code where you use activityIndicator or you post it for more help...

Related

Do I need to send release to my instance variable in the dealloc method? (iOS)

In my class dealloc method I have
- (void) dealloc
{
[searchField release];
[super dealloc];
}
Where searchField is defined in the class variables.
#interface SearchCell : UITableViewCell
{
UISearchBar *searchField;
id delegate;
}
The class is used with the following way:
if (indexPath.section == 0)
{
SearchCell *mycell = [[SearchCell alloc] init];
[cell setDelegate:self];
return [mycell autorelease];
}
searchField is created here:
- (id) init
{
self = [super initWithFrame:CGRectZero];
[self create];
return self;
}
- (void) create
{
searchField = [[UISearchBar alloc] initWithFrame:CGRectZero];
searchField.autocorrectionType = UITextAutocorrectionTypeNo;
[self addSubview:searchField];
}
Do I need to use [searchField release]; in my dealloc? The application crashes with message: "*[UISearchBar respondsToSelector:]: message sent to deallocated instance *".
No, don't release it there. Since you return it with "autorelease", the next run through your event loop will automatically decrease the retain count.
When you finally hit your "dealloc" method, the retain count is already 0 and your app will raise an exception.
You need to be aware of object ownership rules. In manual retain & release environment (as opposed to ARC) the rules for Objective-C objects can be remembered with the acronym NARC.
If you have a reference to an object that you created fresh using new or alloc, or any object that you called retain on, or any object you created by calling copy or mutableCopy on another, or any object created by any methods that start with any of these names (e.g. newInstance), then
you own that object and before you are deallocated you must release it.
But, if you didn't do any of those things, then you do not own that object, and must not release it. source
In your case - you don't show the code where you set the value searchField, but from the crash I'd imagine you never take ownership of the object. Show the code where you assign to searchField and we'll all know for sure.
EDIT: You do take ownership by creating it with alloc. You need to keep the release there in dealloc. Is it being released from somewhere else? Or is the cell itself possibly getting overreleased?

UIActivityIndicatorView proper usage

My question regards the use of activity indicator in an iPhone project.
I have a class that contains an UIActivityIndicatorView
#interface StatusView : UIView
{
UIActivityIndicatorView *indicator;
UILabel *textLabel;
}
- (id)initWithFrame:(CGRect)frame Text:(NSString*)text andShowIndicator:(BOOL)value;
In my business logic code I call [indicator startAnimating] and the frame appears at the bottom of the screen. The code also contains a dealloc method that releases the indicator
- (void)dealloc
{
[indicator release];
[super dealloc];
}
Most of the time the indicator works well, however there are a few occasions that never disappears.
Do I always need to explicitly call the stopAnimating method? Does the release handle it?
What is the proper usage?
stopAnimating: method stops the wheel of UIActivityIndicatorView and release release the object.In Objective-C each object has an internal counter that is used to keep track of all references used by the objects or object has. [object retain] increments the counter by 1 and [object release] decrements the counter by 1. When counter reaches to zero, dealloc is then called. release is about memory management while stopAnimating: is a functionality of UIActivityIndicatorView.
So if you want to stop animating your UIActivityIndicatorView you would have to call stopAnimating: method. In ARC dont have to do release so better to use ARC.
the best way when you are using this object is stopAnimating when you want to stop, remove from super view ( [activityObject removeFromsuperview] ) and finally release it. [ activityObject release];

Releasing a UIView

NB: To clarify what I'm trying to do here:
I have an instance of a subclass of UIView. When this instance gets released from a View Controller I would like that the dealloc method of that instance be called.
The point being to release other objects within that instance of the subclass of UIView.
In the View Controller:
- (void)viewDidLoad
{
[super viewDidLoad];
self.mav = [[MapAreaView alloc]init];
[self.view addSubview:self.mav];
[self.mav release];
t_ = [NSTimer scheduledTimerWithTimeInterval: 20.0f target: self selector:#selector(onTick) userInfo: nil repeats:NO];
}
and:
- (void)onTick
{
NSLog(#"Releasing...");
[t_ invalidate];
t_ = nil;
[self.mav release];
[self.mav release];
[self.mav release];
NSLog(#"Done releasing.");
}
In MapAreaView:
- (void)dealloc
{
NSLog(#"map view area dealloc called.");
[super dealloc];
}
I am trying to release the MapAreaView and have it's dealloc method called.
Also, when I run this app, Releasing... and Done releasing. get printed, but not map view area dealloc called. And despite all of my excessive release messages sent to self.mav the app doesn't crash. Weird.
Ideas?
EDIT 1
#interface MemoryManagmentViewController : UIViewController {
MapAreaView *mav_;
NSTimer *t_;
}
#property (nonatomic, retain) MapAreaView *mav;
which is then synthesized: #synthesize mav = mav_;
EDIT 2
Please not that the timer is not for use in my real application. I'm just using it to learn about memory management.
First off, don't use [self.mav release]. This is incorrect use of properties, and is not guaranteed to release your object. Use self.mav = nil instead.
Secondly, I presume your crazy timer is there just to try and force the release of your view and isn't really code you are using? Because it really shouldn't be there!
To manage the memory of a view that you want to both keep a pointer to and add as a subview to your main view, remove the release and timer messages from your viewDidLoad. You now have one retained pointer to mav, via your property, and the view will be retaining it as well since it is a subview.
In viewDidUnload, your view no longer exists so it will no longer have a pointer to mav. Therefore, if you put self.mav = nil there, mav will be released.
You shouldnt try to release it while it is still a subview of another view.
You don't get to choose when dealloc gets run*
You don't know what else in the iOS framework is retaining your map view.
You should think about memory management in terms of ownership - while you want an object, make sure you've retained it (either explicitly or as a property) and when you are finished with it, make sure you release it (etiher by calling release, autorelease or by setting your property to nil).
Your map view will get released eventually, don't try to force it!
(And it's been said in many other answers but it pretty important so here it is again - don't call self.property release, do self.property = nil; instead :)
*not entirely true for object in libraries you have written yourself but it's definitely true for objects from third party frameworks, including ones from Apple!
The line:
[self.view addSubview:self.mav];
will retain self.mav and should be paired by this line in onTick.
[self.mav removeFromSuperview];
I'm not sure why your over-releasing in onTick doesn't release self.mav anyway - but if you do weird stuff you can guarantee that weird stuff will happen.
Don't release it within onTick again. Do these two steps:
[self.mavview removeFromSuperView];
self.mavview = nil;
That's it. There won't be any more references, so it will be deallocated.
First and foremost thing is
NEVER call release on self.iVar
Donot user self.iVar while allocating.
These are the basic things in memory management.

iphone - question about over-releasing

In any iphone template UIViewController class you will see this:
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
But if I set self.myOutlet = nil in viewDidUnload, and I also have [self.myOutlet release] in the dealloc method, isn't that over-releasing self.myOutlet, since setting it to nil will already set its retain count to zero?
If I don't release it in dealloc(), Leaks reports a memory leak because it never sees self.myOutlet getting released, assuming I have something like this in the header file:
#property (nonatomic, retain) UIView *myOutlet;
If you set self.myOutlet to nil in viewDidUnload, the call in dealloc to [myOutlet release] will simply send a release message to nil. It's perfectly acceptable to send messages to nil. Nothing bad will happen and you won't over-release anything.
The thing to watch out for is releasing the object referenced by myOutlet in viewDidUnload without setting myOutlet to nil. In this case, you'll get a crash in dealloc. Why? Because myOutlet will still be referring to the memory location once occupied by the myOutlet object, and your dealloc method will try to send whatever is currently at that memory location a release message.
-(void)viewDidUnload is called when a memory warning is issued, -(void)dealloc is called in the complete destruction of a view (these aren't the same). Therefore, you should be doing both
- (void)viewDidUnload {
// Release any retained subviews of the main view.
self.myOutlet = nil;
}
- (void)dealloc {
[self.myOutlet release];
}
Edit: What James said furthers the point.
Cheers!
It's not the variable that has a retain count; it's the object. When you do self.something = nil, it does indeed release the object — and it sets the variable to point to nil. So any further release messages sent to self.something do not go to the original object. Instead, they go to the new value, nil, which happily ignores anything you tell it.

Do I need to set these variables to nil in viewDidLoad as I have in this code?

- (void)viewDidUnload {
self.GPSArray = nil;
self.accelerometerArray = nil;
self.headingArray = nil;
self.managedObjectContext = nil;
self.locationManager = nil;
self.pointLabel = nil;
self.accelerometerLabel= nil;
self.headingLabel= nil;
self.startStop = nil;
self.lastAccelerometerReading = nil;
self.lastGPSReading = nil;
self.lastHeadingReading = nil;
}
- (void)dealloc {
[GPSArray release];
[accelerometerArray release];
[headingArray release];
[managedObjectContext release];
[locationManager release];
[pointLabel release];
[accelerometerLabel release];
[headingLabel release];
[startStop release];
[lastAccelerometerReading release];
[lastGPSReading release];
[lastHeadingReading release];
[super dealloc];
}
The reason viewDidUnload is called, is that your view is being released and any view resources should be freed.
So, you only need to free view related items.
In your case it looks like you'd only need to free the UILabels that are probably in your view. If they were marked as IBOutlets and not in assign properties, you'd want to release the memory used by them:
self.pointLabel = nil;
self.accelerometerLabel= nil;
self.headingLabel= nil;
That also means, that in viewDidLoad if you are setting up the other properties you want to make sure they are not being allocated again if they are there already as it can be called again if the view is unloaded and then reloaded again.
The reason this would be called is if the view controller received a memory warning. You can test this memory warning in the simulator to see how viewDidUnload and viewDidLoad are called.
You don't have to, and if you run this, you'll be wasting some substantial execution time. Using the property method to set a property to nil is the same thing as releasing the property, with the caveat that some extra stuff may or may not happen, depending on how you've set up the setter methods.
So let's walk through this code. At the end of your viewDidUnload method, all of your properties are now nil. The object is then deallocated, and your object attempts to release a dozen nil objects or so. Now, the Objective-C runtime is pretty smart, and if you send a message to nil, (surprise surprise) nothing will happen.
So you've basically got a dozen lines that do absolutely nothing.
no, you shouldn't.
if you do as if the above code, you are wasting effort.
By setting them to nil in viewDidUnload, they will be going thru a process of release and retain automatically, which means, by the time the code get to dealloc, they are actually released and nil, and you are doing another release there for the nil.
Releasing nil object might be erratic.
So, ignore those in viewDidUnload.