Issues with addNewPossession:


#1

Hello,

I’ve so far managed to solve any Rodney-made issues that I’ve come across, but this time I’m stumped. I’ve implemented the HeaderView.xib per instructions. toggleEditingMode works fine when I click “EDIT.” To this point, my Simulator output is showing and acting as described in the book. But, when I click “NEW” to kick off addNewPossession, I get a strange green message “EXC_BAD_ACCESS.” The “All Output” Section at the bottom of the Xcode screen only shows my two NSLog lines, and no error messages.

I added a couple of NSLog lines, so I can see where execution stops. NSLog shows the new count for allPossessions had increased by one, but things fall apart at [[self tableView] reloadData].

When [[self tableView] reloadData] is encountered, I get that green message. I’ve included a screen shot. I’m also attaching my ItemsViewController.h & .m files.

Any suggestions are welcome. I’m hoping I did something obvious. I’m running OSX Lion 10.7.2 and Xcode 4.1 Build 4B110

Thanks, (files below) I apologize for the loss of indentation below (not sure why that happened during pasting…)

Link to SnapShot.PNG

[quote]ItemsViewController.h

//
// ItemsViewController.h
// Homepwner
//
// Created by Rodney Johnson on 9/2/11.
// Copyright 2011 Tech Infected. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface ItemsViewController : UITableViewController
{
IBOutlet UIView *headerView;
}

  • (UIView *)headerView;
  • (IBAction)addNewPossession:(id)sender;
  • (IBAction)toggleEditingMode:(id)sender;

@end
[/quote]

[quote]ItemsViewController.m

//
// ItemsViewController.m
// Homepwner
//
// Created by Rodney Johnson on 9/2/11.
// Copyright 2011 Tech Infected. All rights reserved.
//

#import “ItemsViewController.h”
#import “Possession.h”
#import “PossessionStore.h”

@implementation ItemsViewController

  • (id)init
    {
    self = [super initWithStyle:UITableViewStyleGrouped];

    if (self) {
    for (int i = 0; i < 5; i++) {
    [[PossessionStore defaultStore] createPossession];
    }
    }

    return self;
    }

  • (id)initWithStyle:(UITableViewStyle)style
    {
    return [self init];
    }

//Mandatory for UITableViewDataSourceProtocol

  • (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    {
    return [[[PossessionStore defaultStore] allPossessions] count];
    }

  • (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@“UITableViewCell”];

    if (!cell) {
    cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
    reuseIdentifier:@“UITableViewCell”] autorelease];
    }

    Possession *p = [[[PossessionStore defaultStore] allPossessions] objectAtIndex:[indexPath row]];

    [[cell textLabel]setText:[p description]];

    return cell;
    }

  • (UIView *)headerView
    {
    if (!headerView) {
    //Load the headerView.XIB
    [[NSBundle mainBundle] loadNibNamed:@“HeaderView” owner:self options:nil];
    }

    return headerView;

}

  • (UIView *)tableView:(UITableView *)tv viewForHeaderInSection:(NSInteger)sec
    {
    return [self headerView];
    }

  • (CGFloat)tableView:(UITableView *)tv heightForHeaderInSection:(NSInteger)sec
    {
    //NSLog(@“height: %f”,self.headerView.bounds.size.height);
    return self.headerView.bounds.size.height;
    }

  • (void)toggleEditingMode:(id)sender
    {
    if ([self isEditing]) {

      [sender setTitle:@"Edit" forState:UIControlStateNormal];
      [self setEditing:NO  animated:YES];
    

    }else {
    [sender setTitle:@“Done” forState:UIControlStateNormal];
    [self setEditing:YES animated:YES];
    }
    }

  • (IBAction)addNewPossession:(id)sender
    {
    NSLog(@“Trying to Add new Possession”);

    [[PossessionStore defaultStore] createPossession];

    NSLog(@“Created Possession. %d Items In Store.”, [[[PossessionStore defaultStore] allPossessions]count]);

    [[self tableView] reloadData]; //Bombs Here
    }

@end
[/quote]


#2

The thing about EXC_BAD_ACCESS is that the point at which a crash happens is not likely where the issue exists. We know that EXC_BAD_ACCESS is about memory. I didn’t see any obvious issue in the code.

As a first step, try Product > Analyze in Xcode. It will probably complain about +allocWithZone: in PossessionStore.m, but as long as your code matches that in the book then don’t worry about this one. If it complains about another line and you don’t understand why, then post that here.

If nothing turns up, then post Possession.m and PossessionStore.m.

(Tip: instead of using bracket-quote-bracket to post the code, use bracket-code-bracket. It causes the code to be rendered in a monospaced font and preserves the indentation so it’s easier to read.)


#3

Hello,

Thanks very much for your reply and advice! I’ve ran Project/Analyze as suggested. It turned up three occurrences of the same error: one in PossessionStore.m as expected, and two in Possession.m which I understand why they occurred. I was able to fix and get rid of the two in Possession.m. Even after doing so and re-running the simulator, I get the same behavior with EXC_BAD_ACCESS. I’ve pasted below my Possession.m and PossessionStore.m files.

Thanks in advance again!

Possession.m

//
//  Possession.m
//  RandomPossessions
//
//  Created by Franz Parkins on 5/24/11.
//  Copyright 2011 __MyCompanyName__. All rights reserved.
//

#import "Possession.h"
#import <Foundation/Foundation.h>

@implementation Possession

+ (id)randomPossession
{
    // Create an array of three adjectives
    NSArray *randomAdjectiveList = [NSArray arrayWithObjects:@"Fluffy", @"Rusty", @"Shiny", nil];
    
    // Create an array of three nouns
    NSArray *randomNounList = [NSArray arrayWithObjects: @"Bear", @"Spork", @"Mac", nil];
    
    // Get an index of a random adjective/noun from the lists with index 0 to 2
    //*** unsigned long can be casted to int ***
    unsigned long adjectiveIndex = rand() % [randomAdjectiveList count];
    unsigned long nounIndex = rand() % [randomNounList count];
    
    NSString *randomName = [NSString stringWithFormat:@"%@ %@", [randomAdjectiveList objectAtIndex:adjectiveIndex], [randomNounList objectAtIndex:nounIndex]];
    int randomValue = rand() % 100;
    NSString *randomSerialNumber = [NSString stringWithFormat:@"%c%c%c%c%c", '0' + rand() % 10, 'A' + rand() % 26, '0' + rand() % 10, 'A' + rand() % 26, '0' + rand() % 10];
    // NOTE: There are memory mangagement issues here
    Possession *newPossession = [[self alloc] initWithPossessionName:randomName 
                                                      valueInDollars:randomValue 
                                                        serialNumber:randomSerialNumber];

    [newPossession autorelease]; //gets rid of the product/analyse warning about 0 retained  #1 of 2
    return newPossession;
    
}

- (id)initWithPossessionName:(NSString *)name 
            valueInDollars:(int)value 
              serialNumber:(NSString *)sNumber
{
   // Call the super classes designated initializer
    self = [super init];
    
   // Did the superclass's designated initializer succeed?
    if(self) {
        
   // Give the instance variables initial values
    [self setPossessionName:name];
    [self setSerialNumber:sNumber];
    [self setValueInDollars:value];
    dateCreated = [[NSDate alloc] init];
    }
    
   // Return the address of the newly initialized object
    return self;
}


// defineing Accessors
- (void)setPossessionName:(NSString *)str //Setter Name
{
    possessionName = str;

}

- (NSString *)possessionName              //Getter Name
{
    return possessionName;
}

- (void)setSerialNumber:(NSString *)str   //Setter serial number
{
    serialNumber = str;
}

- (NSString *)serialNumber                //Getter serial number
{
    return serialNumber;
}

- (void)setValueInDollars:(int)i          //Setter Dollars
{
    valueInDollars = i;
}

- (int)valueInDollars                     //Getter Dollars
{
    return valueInDollars;
}

- (NSDate *)dateCreated                    //Getter Date
{
    return dateCreated;
}

- (NSString *)description                 //Method description
{
    NSString *descriptionString = [[NSString alloc] initWithFormat:@"%@ (%@): Worth $%d, recorded on %@",
                                   possessionName, serialNumber, valueInDollars, dateCreated];

    [descriptionString autorelease];  //gets rid of the product/analyze 0 retain warning  #2 of 2
    return descriptionString;
}

//Override the init method from NSObject to call the designated initializer with default values
- (id)init
{
    return [self initWithPossessionName:@"Possession" valueInDollars:0 serialNumber:@""];
}

@end

PossessionStore.m

//
//  PossessionStore.m
//  Homepwner
//
//  Created by Rodney Johnson on 9/2/11.
//  Copyright 2011 Tech Infected. All rights reserved.
//

#import "PossessionStore.h"
#import "Possession.h"

static PossessionStore *defaultStore = nil;

@implementation PossessionStore

+ (PossessionStore *)defaultStore
{
    if (!defaultStore) {
        
        //Create the singleton
        defaultStore = [[super allocWithZone:NULL] init];
    }
    
    return defaultStore;
}

+ (id)allocWithZone:(NSZone *)zone
{
    return [self defaultStore];
}

- (NSArray *)allPossessions
{
    return allPossessions;
}

- (Possession *)createPossession
{
    Possession *p = [Possession randomPossession];
    
    [allPossessions addObject:p];
    
    return p;
}

- (id)init
{
    if (defaultStore) {
        return defaultStore;
    }
    
    self = [super init];
    
    if (self) {
        allPossessions = [[NSMutableArray alloc] init];
    }
    
    return self;
}

- (id)retain
{
    return self;
}

/*
- (void)release;
{
    //do nothing
}
*/

- (NSUInteger)retainCount
{
    return NSUIntegerMax;
}

@end

#4

Just tried running Debug (sorry, I’m very newbie) and walking through code. Seems like the reloadData line is not causing the EXC_BAD_ACCESSS message. It seems it is happening from within my - (NSString *)description. I’ve added a screen shot here.

Stepping through, it goes past the reloadData, then during the reload process it calls the description method then has the issue.


#5

Thanks for posting the code.

As mentioned previously, the thing about EXC_BAD_ACCESS is that the root of the issue is rarely (if ever) the point at which the app crashes.

Both the code I saw and with the warnings you fixed makes it look like you glossed over chapter 3 on memory management, which turns out to be one of the most important chapters in the book. It may not sound like fun, but it really is key.

I’m glad that you understood the warnings. Adding autorelease was indeed the proper thing to do. The autorelease messages were added to the project on pages 66 and 67.

The setters you have for possessionName and for serialNumber are the ones left over from chapter 2 (page 47) when we didn’t know about proper memory management.

I’d strongly encourage you to review chapter 3 again. Not only will it directly address the memory issues in Property.m, it will also show you how to simplify the setters (and getters as well, though they’re less critical) with @property and @synthesize so you don’t have to worry about how to write a setter properly again.


#6

I’ll be sure to review chapter 3. Thanks for your help! :slight_smile: