views:

85

answers:

3

I'm doing the following:

- (void) accelerometer: (UIAccelerometer *)accelerometer didAccelerate: (UIAcceleration *)acceleration {
if (self.lastAcceleration) {
 double i = self.lastAcceleration.x;

It works fine until I actually tilt the phone. Then I get EXC_BAD_ACCESS on the last line. lastAcceleration is a property with a retain. When I look at "x" in the debugger, it has a large negative value. Why would that throw a EXC_BAD_ACCESS exception only on tilt?

-- EDIT (Since this answer applies to responses below) --

I added this and now it works:

- (void)dealloc {
[lastAcceleration release];

Why would that matter? Also, should it be

[self.lastAcceleration release];

I wasn't previously releasing lastAcceleration anywhere. Here is the header declaration:

@interface MyViewController : UIViewController <UIAccelerometerDelegate> {
UIAcceleration *lastAcceleration;
}
@property(nonatomic, retain) UIAcceleration *lastAcceleration;
@end
A: 

EXC_BAD_ACCESS is raised when you access released memory. My guess would be that you somewhere released self.lastAcceleration but didn't set it to null.

Are you sure it is related to tilting?

Johannes Rudolph
+1  A: 

My hunch is that the accelerometer API has nothing to do with the crash, the code you have shown smells like bad memory management, given that you're mixing ivar and property access I suspect you might be doing the same in other parts you're not showing.

Anyway a couple best practice things:

  • any object you have a pointer for in your class you should have retained, and conversely when you release it you should also zap the pointer so you don't risk accessing it after it has been deallocated (the exception to this rule are some patterns like the delegate object, where retaining the object would cause a retain cycle, but that's a whole other topic)
  • ivar setters and getters that are automatically generated via the @synthesized directive will retain and release the object for you for code that simply looks like it's assigning a pointer, so they're pretty handy, but property access (self.something = ...) and ivar access (something = ...) are not equivalent so you have to be careful

One easy way to make sure you don't mix the two up is to do something like this:

@interface MyObject : NSObject
{
  SomethingObject *_something;
}

@property (nonatomic, retain) SomethingObject *something;

@end

@implementation MyObject

@synthesize something = _something;

@end

What we're doing here is making the ivar and property names slightly different, so that you are more aware of which one you're using, and the compiler will bark if you use don't use the bare something = ... syntax.

Now the @synthesize'd accessors are something like this:

- (void)setSomething:(SomethingObject *)newSomething
{
  [newSomething retain];
  [_something release];
  _something = newSomething;
}

- (SomethingObject *)something
{
  return _something;
}

With all that out of the way, [lastAcceleration release] is a bad thing to do because it isn't also setting the lastAcceleration pointer to nil, you are not guaranteed that it won't be deallocated and if you accidentally use it you are likely to crash.

[self.lastAcceleration release]; is incorrect because accessors take care of all the retain/release stuff for you.

The correct thing to do here is self.lastAcceleration = nil; that, if you look at the accessor code, will release and set the pointer to nil.

What is likely happening is that you are releasing lastAcceleration somewhere without also setting it to nil, and the if (self.lastAcceleration) { check is hitting a released object.

duncanwilcox
Thanks. Maybe this is a whole other topic: Should only ivars be set to nil and properties released and never vice versa?
4thSpace
Don't name ivars with a single leading underscore. That's an Apple internal coding convention, which they adopted to reduce the chances of your code having name collisions with theirs.
NSResponder
+1  A: 

Main reason to have retained properties is to avoid explicit retain/release calls and memory management bugs associated with them. But in dealloc method either way is fine, since object will cease to exist soon. [self.lastAcceleration release]; - not necessary.

[lastAcceleration release]; self.lastAcceleration = nil;

Both are fine if used in dealloc. Outside of dealloc use only

self.lastAcceleration = nil;
noop