Subtracting two numbers gives EXC_BAD_ACCESS

Discussion in 'iOS Programming' started by blueeye, Nov 2, 2009.

  1. macrumors member

    blueeye

    Joined:
    Oct 27, 2007
    #1
    Hi MacRumours,

    I'm writing an iPhone app which uses the accelerometer to control another external application (just for some context).

    In order to calculate the difference between the previous accelerometer value and this one I use the following two lines (I only need X and Y):

    Code:
    float diffx = ([acceleration x] - [prevAccel x])*100;
    float diffy = ([acceleration y] - [prevAccel y])*100;
    
    This works most of the time, but sometimes (either randomly or when the difference becomes large, mostly the latter) I get EXC_BAD_ACCESS on the first of the two lines above.
    In GDB I tried the following:

    Code:
    (gdb) p acceleration
    $3 = (UIAcceleration *) 0x128500
    (gdb) p acceleration.x
    $4 = 0.869384765625
    (gdb) p acceleration.y
    $5 = -0.036224365234375
    (gdb) p acceleration.z
    $6 = -0.543365478515625
    (gdb) p prevAccel.x
    $7 = 4.6495020515960297e-315
    (gdb) p prevAccel.y
    $8 = 1.7286328172809227e-38
    (gdb) p prevAccel.z
    $9 = 0
    (gdb) p (acceleration.x - prevAccel.x)
    $10 = 0.869384765625
    
    after I got the EXC_BAD_ACCESS code and as you can see, the sum works...

    I then tried the following:

    Code:
    (gdb) continue
    Continuing.
    Program received signal:  “EXC_BAD_ACCESS”.
    
    Program received signal EXC_BAD_ACCESS, Could not access memory.
    Reason: KERN_PROTECTION_FAILURE at address: 0x0000000f
    0x31ec3ebc in objc_msgSend ()
    (gdb) x/s $r1
    0x34370cc4 <__PRETTY_FUNCTION__.55878+13008>:	 "x"
    
    I'm not entirely sure what to do here since it works most of the time. Any ideas would be much appreciated.
     
  2. Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
  3. thread starter macrumors member

    blueeye

    Joined:
    Oct 27, 2007
    #3
    It's not retained explicitly. I tried copying the acceleration as follows:

    Code:
    if(prevAccel == nil) {
    	prevAccel = [acceleration copy];
    } else {
    ...
    
    but it didn't work so I've just got
    Code:
    prevAccel = acceleration;
    
     
  4. Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #4
    So if you don't retain it and it's autoreleased what happens to it at the end of the current runloop? Normally it'll get released and next time in you'll access memory you no longer own and bang! Sometimes you'll get lucky, other times you won't.
     
  5. thread starter macrumors member

    blueeye

    Joined:
    Oct 27, 2007
    #5
    Fabulous, I think I've fixed it by assigning prevAccel as follows:

    Code:
    prevAccel = [acceleration retain];
    
    Thanks for pointing me in the right direction :)
     
  6. Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #6
    Remember to release it after you are done with it otherwise you are leaking memory...
     
  7. thread starter macrumors member

    blueeye

    Joined:
    Oct 27, 2007
    #7
    I guess it was that "Sometimes you'll get lucky bit" that threw me off the scent. I'm still relatively new to the concept of memory management.
    Thanks for the help :)

    Done. Thanks again. I would have missed that otherwise.
     
  8. Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #8
    Does that include releasing it before reassigning it? (Sometimes memory management confuses even me.)
     
  9. thread starter macrumors member

    blueeye

    Joined:
    Oct 27, 2007
    #9
    I released before reassigning and it hasn't broken but I'm not entirely sure if it's correct either. It makes sense (to me) to do it that way but I'm hardly an expert memory manager.
     
  10. macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #10
    Few points.

    I haven't used the accelerometer but a quick look at the header shows that it doesn't implement the NSCopying protocol so it won't copy correctly. This is arguably a bug but at any rate you can't expect the copy method to work correctly.

    You probably want to add a retain property for your prevAccel ivar. That will make your memory management easier.

    Code:
    self.prevAccel = acceleration;
    will retain the new value and release the old value.

    When you see crashes in objc_msgSend they usually mean that you've tried to access an ivar where you failed to retain it.
     
  11. Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #11
    Yes. Otherwise the object you retained and failed to release will hang around until the app quites. If you retain an object you must release it. Assigning a new object to the pointer does not release the original object you retained...
     
  12. thread starter macrumors member

    blueeye

    Joined:
    Oct 27, 2007
    #12
    As it stands I've simply assigned it to [acceleration retain], although prevAccel is assigned as (nonatomic, retain).
     
  13. Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #13
    If prevAccel is already a property with (nonatomic, retain), then just assigning it
    Code:
    prevAccel = [acceleration retain];
    is not taking advantage of the property you have setup. As PhoneyDeveloper has suggested, you should be using
    Code:
    self.prevAccel = acceleration;
    instead.
     
  14. thread starter macrumors member

    blueeye

    Joined:
    Oct 27, 2007
    #14
    Ahh! I see. I'd misunderstood and thought that writing
    Code:
    prevAccel
    
    was a convenience method of accessing
    Code:
    self.prevAccel
    
    Thanks for clearing this up.
     
  15. Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #15
    Using just prevAccel accesses the instance variable directly and doesn't use the getters or setters created via the @synthesize part of your property definition.
     
  16. thread starter macrumors member

    blueeye

    Joined:
    Oct 27, 2007
    #16
    I'll definitely keep that in mind then.
    When I try using
    Code:
    self.prevAccel = acceleration;
    
    Do I still have to using [acceleration retain] or is it sufficient that prevAccel has retain set?
     
  17. Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #17
    You do not.

    Code:
    self.prevAccel = acceleration;
    
    is equivalent to

    Code:
    [self setPrevAccel:acceleration];
    
    The synthesized code for setPrevAccel will look something like

    Code:
    -(void) setPrevAccel:(UIAcceleration) newValue
    {
    if (prevAccel!= newValue) {
    
        [prevAccel release];
    
        prevAccel= [newValue retain];
    
    }
    }
    
    As you can see this releases any existing value set for the property and retains the new value for you (this assumes you declared the property as retain)
     
  18. thread starter macrumors member

    blueeye

    Joined:
    Oct 27, 2007
    #18
    @robbieduncan:

    Okay, that's brilliant. Thanks for explaining that to me.
     

Share This Page