Homepwner crashes in Simulator


#1

I am just beginning to learn IOS programming on my mac book running OSX 10.6.8 / XCode 3.2 / IOS Simulator 4.3.8 so clearly I am behind the curve; but this is what is available to me at moment.

So far (through first 13 chapters) things have worked pretty well, and I love the way you have explained concepts and introduced them at the appropriate time. Now to the problem at hand:

The app works fine I can save items in the archive and open the app again and it is initialized properly. It is only when I close the simulator and start again that the app is crashing. If I delete the archive file and restart it works fine again. Which means as long as I keep the simulator running it fine, when I restart the simulator the app is crashing with following message

Program received signal: “EXC_BAD_ACCESS”.

I have no idea how to proceed or debug this.


#2

Having had close to 50 views but no replies, gave me a hint that more information was needed. So I had to shed my fear of Debugger and venture in. I was able to pin point the problem and did fix it, which I will share here in a moment. But that changes my question, because while the problem is fixed I am not convinced the solution is “correct” (as in robust and consistent with IOS best practices). Also I would love to have a clearer grasp of why the problem is happening in the first place. I am not convinced that it is just incompatibilities between current and older versions of IOS SDK.

The app crashed as soon as I run it and the stack Trace looks like this

#0 0x00f2e09f in objc_msgSend
#1 0x04b1a0e0 in ??
#2 0x00db1c1d in __CFStringAppendFormatCore
#3 0x00cf9507 in _CFStringCreateWithFormatAndArgumentsAux
#4 0x00010600 in -[NSPlaceholderString initWithFormat:locale:arguments:]
#5 0x00010f84 in -[NSString initWithFormat:]
#6 0x00003254 in -[BNRItem description] at BNRItem.m:153
#7 0x000024ee in -[ItemsViewController tableView:cellForRowAtIndexPath:] at ItemsViewController.m:70
#8 0x0032db98 in -[UITableView(UITableViewInternal) _createPreparedCellForGlobalRow:withIndexPath:]
#9 0x003234cc in -[UITableView(UITableViewInternal) _createPreparedCellForGlobalRow:]
#10 0x003388cc in -[UITableView(_UITableViewPrivate) _updateVisibleCellsNow:]
#11 0x0033090c in -[UITableView layoutSubviews]
#12 0x01d68a5a in -[CALayer layoutSublayers]
#13 0x01d6addc in CALayerLayoutIfNeeded
#14 0x01d100b4 in CA::Context::commit_transaction
#15 0x01d11294 in CA::Transaction::commit
#16 0x002ba9c9 in -[UIApplication _reportAppLaunchFinished]
#17 0x002bae83 in -[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:]
#18 0x002c5617 in -[UIApplication handleEvent:withNewEvent:]
#19 0x002bdabf in -[UIApplication sendEvent:]
#20 0x002c2f2e in _UIApplicationHandleEvent
#21 0x01720992 in PurpleEventCallback
#22 0x00da9944 in CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION
#23 0x00d09cf7 in __CFRunLoopDoSource1
#24 0x00d06f83 in __CFRunLoopRun
#25 0x00d06840 in CFRunLoopRunSpecific
#26 0x00d06761 in CFRunLoopRunInMode
#27 0x002ba7d2 in -[UIApplication _run]
#28 0x002c6c93 in UIApplicationMain
#29 0x00001f78 in main at main.m:14

Looking at #6 and #7 it was crashing while creating the tableView from unarchived file.

I traced the signal to following piece of code (BNRItem.m)

  • (NSString *)description
    {
    NSString *desString =
    [[NSString alloc] initWithFormat:@"%@ (%@): Worth $%d, recorded on %@",
    itemName,
    serialNumber,
    valueInDollars,
    dateCreated];

    return desString;
    }

So I inspected the variables more closely and found that dateCreated was showing as out of scope. So traced where dateCreated was being updated (BNRItem.m):

  • (id)initWithCoder:(NSCoder *)aDecoder
    {
    self = [super init];
    if (self) {
    [self setItemName:[aDecoder decodeObjectForKey:@“itemName”]];
    [self setSerialNumber:[aDecoder decodeObjectForKey:@“serialNumber”]];
    [self setImageKey:[aDecoder decodeObjectForKey:@“imageKey”]];

      [self setValueInDollars:[aDecoder decodeIntForKey:@"valueInDollars"]];
      
      dateCreated = [aDecoder decodeObjectForKey:@"dateCreated"];
    

    }

    return self;
    }

I replaced

	dateCreated = [aDecoder decodeObjectForKey:@"dateCreated"];

with
dateCreated = [[aDecoder decodeObjectForKey:@“dateCreated”] copy];

to make it work. The application then started crashing when I selected on any row in the tableView. I fixed that problem too; but I will save that for another post since this is getting too long.

Here is how my BNRItem.h file looks like:

#import <Foundation/Foundation.h>

@interface BNRItem : NSObject {

NSString *itemName;
NSString *serialNumber;
int valueInDollars;
NSDate *dateCreated;
BNRItem *containedItem;
BNRItem *container;

}

@property (nonatomic, copy) NSString *imageKey;

  • (id) randomItem;
  • (id)initWithItemName:(NSString *)name valueInDollars:(int)value serialNumber:(NSString *)sNumber;

  • (void)setItemName:(NSString *)name;

  • (NSString *)itemName;

  • (void)setSerialNumber:(NSString *)sNumber;

  • (NSString *)serialNumber;

  • (void)setValueInDollars:(int)i;

  • (int)valueInDollars;

  • (NSDate *)dateCreated;

  • (void)setContainedItem:(BNRItem *)i;

  • (BNRItem *)containedItem;

  • (void)setContainer:(BNRItem *)i;

  • (BNRItem *)container;

@end

So, to recap, my question is why do I have to create an instance of NSDate in initWithCoder?

I hope I get replies this time around :slight_smile:


#3

I’m not sure exactly, but in my copy of the book I penciled in in the margin that dateCreated was readonly. (That’s why the unarchived value is assigned directly rather than set using a mutator method: a readonly property has no mutator method.) Could this be some kind of ARC glitch that is affecting the code you’re writing in a pre-v4.3 Xcode? (I don’t know the exact version needed, but that’s what the book states on the back jacket.)

I’m just trying to think this through.

Anyway, you have dateCreated set up as an instance variable in your BNRItem.h file. I have it set up as a property. Specifically, it’s set up like this:

The “strong” key word tells the compiler that we want to hold onto it. You don’t specify anything about how to handle the variable in memory. My guess is that it’s getting released.

I’m not sure why you have it as an instance variable. Can you re-implement this as a property instead? Or maybe you can use the __strong keyword. Try taking out the copy message when you unarchive it, and edit the implementation file so it looks like this:

@interface BNRItem : NSObject <NSCoding> {
    NSString *itemName;
    NSString *serialNumber;
    int valueInDollars;
    __strong NSDate *dateCreated;
    BNRItem *containedItem;
    BNRItem *container;
}

Good luck!


#4

Thanks for the reply. Indeed I had missed the point about dateCreated being readOnly.

I had to declare dateCreated as instance variable; because the compiler won’t recognize ‘strong’ as part of property declaration. I tried declaring it as propety and replacing ‘strong’ with ‘retain’ but got the same exact error at the same exact location.

Also tried _strong in the instance variable and get the same result.

This is puzzling because similar functionality should have worked in previous versions of XCode. Perhaps previous versions of BNR book may have the explaination; but I don’t know where to get my hands on it.


#5

After I wrote my post, I got to thinking that I’m pretty sure “strong” (or retain) is the default. I’m puzzled, too.