1

I have a rather large app which works in the simulator but creates in an over-released object scenario on the iPhone device. NSzombies would seem to be the route to go except that the object is not over-released on the simulator and NSZombies does not function on the device. Through hours of logging I seem to be able to pin it down to someplace between when I run -

[locManager startUpdatingLocation] and the start of -

(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation

That explains why it works on the simulator, I detect no location ability and do not run that location code.

When I NSLog in-line just before and after [locManager startUpdatingLocation] my NSString object is allocated and present. But when the app executes and it hits locationManager: NSLog shows the NSString is deallocated, gone. THis string object has absolutely nothing to do with location handling or functionality. Unrelated NSString. I have commented out all other potential activity, and commented out all explicit release code and can't find the moment it happens.

I'm further frustrated that lldb seems not to support watchpoints and gdb supports them but this version seems that they don't work ! gdb will set a hardware watchpoint and then Xcode says its running but 30 minutes later there is still no visual activity or break.

I'm on Lion, Xcode 4.1.1, and too much coffee.

What approach should I take to find this released NSString object in such a narrow spectrum of activity and limited tools ?

Ric
  • 796
  • 12
  • 28
  • 1
    There are CoreLocation simulators that let you use CL on the iPhone simulator. You might be able to duplicate the issue on the iPhone simulator that way. See [testing-corelocation-on-iphone-simulator](http://stackoverflow.com/questions/802156/testing-corelocation-on-iphone-simulator) on SO. – progrmr Aug 09 '11 at 03:19

2 Answers2

5

Once upon a time I had a complex case for locating over released object, so I just inherited from this object to MyObject and overriden a retain and release in a following way:

Here is the DebugString.h file:

#import <Foundation/Foundation.h>

@interface DebugString : NSString

@end

And here is the DebugString.m file:

#import "DebugString.h"

@implementation DebugString

- (id) retain {
    NSLog(@"%i", [self retainCount]);
    return [super retain];
}

- (void) release {
    NSLog(@"%i", [self retainCount]);
    [super release];
}

@end

I put a break points inside of this methods and turned them on at the phase when I expected a crash. Afterward I just started to go through this calls one by one and found an issue. It is complex, but it may help sometime and I never saw such approach described in forums. Maybe it will help you also.

progrmr
  • 75,956
  • 16
  • 112
  • 147
Nikita Leonov
  • 5,684
  • 31
  • 37
  • Nikita, this is an interesting approach. So I would put these two methods in both the app delegate and the singleton object where the issue exists. I'm a little unsure about the inheritance. Are these two methods in an inherited object by themselves ? Maybe if I could ask, I would really appreciate some pseudo-code to help draw me a picture of placement here. Thanks. This may be a real help. – Ric Aug 09 '11 at 02:51
  • Not really. As I understood you have an issues with over-releasing of NSString object, so you need to created a child for NSString object and create in a code not a NSString but your own string and afterward follow her life-cycle. – Nikita Leonov Aug 09 '11 at 02:54
  • These override the retain/release functions in NSObject, allowing you to breakpoint when they are called. I've used this method also. – progrmr Aug 09 '11 at 03:21
  • @progrmr You are right about NSObject but if it will be a root object for everything it maybe too much for a catching of one particular object that actually maybe have only one instance per an app. :) But yes, it seems that you reached the same zen as I did. – Nikita Leonov Aug 09 '11 at 03:26
  • @Nikita What I meant was that when you add these retain/release methods to a subclass of NSString, what you are doing is overriding the retain/release methods that were inherited from NSObject, which is a super class of NSString. I was just trying to clarify for ric. – progrmr Aug 09 '11 at 03:30
  • @progrmr and Nikita, I appreciate this, alot. But I'm having trouble visualizing the actual code of what you are suggesting. I put the 2 methods in the applicable object and actually produced no log lines. I tried it in another object to check it and got 29 retains and releases. CLLocationManager should not touch this NSString. The NSString before and after are not deallocated or written over. Just this one string which is used later in the app, which then bombs. – Ric Aug 09 '11 at 03:58
  • Once more time. You can implement a class just for this particular string and follow its lifecycle. Or you can just think in a way what is happening with it? How else touching it etc. Let me guess is it autoreleased object? Do you assign it by default to property with assign accessor or retain / copy? It is hard to say what is an actual problem. Either use earlier proposed method or NSZombie to locate an actually issue. – Nikita Leonov Aug 09 '11 at 04:02
  • I had thought about that too. It is retained in the @property stmt. I think I was clear why NSZombie is not an option. The app does not display the problem in the simulator due to the fact that the app sees no Locate capability and does not run that code. Thanks for the help. Let stop before I totally piss you off. This is my first app, its coded, and this is essentially my final bug that crept in during the last days. Best to you. – Ric Aug 09 '11 at 04:55
  • :) You will not puss me off, but it is just complex to help without a seeing a code and an option to play with it. As another complex solution that maybe helpful for you in future — you can write your own mock location service that will replace your own and will provide you a mock data to play with app even if it is run under simulator. It will help you to debug application on simulator, find this issue and with further work too. – Nikita Leonov Aug 09 '11 at 04:57
  • under gdb: "watch -location emailSubject3" would do the trick because that is a hardware watchpoint at a specific memory location and range, that does not go out of scope. A great way to see when the string is being touched. But it appears not to work in the current implementation of gdb. :( – Ric Aug 09 '11 at 05:17
  • 2
    @ric: I expanded this answer to show how you put these two methods into a class, I called it DebugString. Now whichever NSString you think you have a problem with, change its declaration from NSString* to DebugString* instead. It will work exactly the same, except all retains and releases will also go thru these two methods and you can set breakpoints on them and look at the call stack to see who called it. Hope this helps. Nikita hope you don't mind I edited your answer. – progrmr Aug 09 '11 at 05:47
  • I tried to post my code but there are no line breaks. Essentially, the app compiles but when I verify the object emailSubject3 has a value and a retain count of 1 and then place [emailSubject3 release] next, I do not catch the object's release in my DebugString breakpoint. Doesn't really make any sense. – Ric Aug 10 '11 at 03:42
  • It seems that my test release message is being caught in the app class where the emailSubject3 object is being accessed, where I then also issue [emailSubject3 release]. So I put a break in that class's explicit release method and it does break. But my NSLog statement in my release method does not display. Darn. But the real problem is that there are many many classes and I think the purpose of setting up the DebugString subclass was to catch the release from where ever it came from. In this situation where it is caught in the active class's release method, this is not happening. A problem. – Ric Aug 10 '11 at 04:37
0

Call the location "didUpdate" manually when running in the simulator - at least two calls, timed out about five seconds, after you start up the location manager. That should trigger the same bug as on the phone, then you can use NSZombies.

Also, the simulator SHOULD be able to run location code, I thought that was broken in 4.2 but OK in 4.1.

Kendall Helmstetter Gelner
  • 74,769
  • 26
  • 128
  • 150