Crash in TableViewController

Discussion in 'iOS Programming' started by gameplayerxp, Dec 1, 2010.

  1. gameplayerxp macrumors newbie

    gameplayerxp

    Joined:
    Dec 1, 2010
    Location:
    Sydney
    #1
    Hi,

    I have a table view controller which shows 2 sections with 2 rows in each. It display well initially but causes exceptions when I scroll them up.

    The following is my code. I checked the variable onlineBooks - it's "out of scope" when exception happened in cellForRowAtIndexPath and its type was changed from NSArray* to NSCFString*

    Can anyone suggest me where could be the problem?


    Code:
    @interface RootViewController : UITableViewController {
    	NSArray *onlineBooks;
    	NSArray *localBooks;
    }
    
    @property (nonatomic, retain) NSArray *onlineBooks;
    @property (nonatomic, retain) NSArray *localBooks;
    
    @end
    
    ...
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
        self.navigationItem.rightBarButtonItem = self.editButtonItem;
    	
    	self.title = NSLocalizedString(@"Book Library", @"Book Library title");
    	
    	onlineBooks = [NSArray arrayWithObjects:@"Online Book 1", @"Online Book 2", nil];
    	localBooks = [NSArray arrayWithObjects:@"Local Book 1", @"Local Book 2", nil];
    }
    
    // Customize the number of sections in the table view.
    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
        return 2;
    }
    
    
    // Customize the number of rows in the table view.
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
        if (section == 0) {
    		return [onlineBooks count];
    	} else {
    		return [localBooks count];
    	}
    	
    	//return 0;
    }
    
    - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
    
    	if (section == 0) {
    		return @"Online Books";
    	} else {
    		return @"Local Books";
    	}
    }
    
    // Customize the appearance of table view cells.
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
        
        static NSString *CellIdentifier = @"Cell";
        
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
        if (cell == nil) {
            cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
        }
        
    	// Configure the cell.
    	NSString *book;
    	if (indexPath.section == 0) {
    		if (indexPath.row < [onlineBooks count]) { // !!!Exception here!!!
    			book = [onlineBooks objectAtIndex:indexPath.row];
    		}
    	} else {
    		if (indexPath.row < [localBooks count]) {
    			book = [localBooks objectAtIndex:indexPath.row];
    		}
    	}
    	
    	cell.textLabel.text = book;
    
        return cell;
    }
    ...
    
     
  2. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #2
    Your problem is that you are not using the synthesized setters to set your properties so your arrays (which are autoreleased) are not getting retained.

    These lines:
    Code:
    onlineBooks = [NSArray arrayWithObjects:@"Online Book 1", @"Online Book 2", nil];
    localBooks = [NSArray arrayWithObjects:@"Local Book 1", @"Local Book 2", nil];
    
    These are direct assignments. You want to use
    Code:
    self.onlineBooks = [NSArray arrayWithObjects:@"Online Book 1", @"Online Book 2", nil];
    self.localBooks = [NSArray arrayWithObjects:@"Local Book 1", @"Local Book 2", nil];
    
    The difference here is that the . syntax causes this to use the synthesized setters which will retain the autoreleased objects.
     
  3. gameplayerxp thread starter macrumors newbie

    gameplayerxp

    Joined:
    Dec 1, 2010
    Location:
    Sydney
    #3
    Awesome! It works now.

    I thought onlineBooks is a member variable of the instance of RootViewController and it should be retained before the instance is destroyed, but seems that I was wrong. Quite different to C++.:confused:
     
  4. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #4
    Whether or not it's a member variable or not does not matter. You need to read the Memory Management Guide, in particular the Memory Management Rules. And remember the difference between assignment and property setters.

    Code:
    self.property = value;
    
    is actually expanded by the Objective-C 2.0 compiler to

    Code:
    [self setProperty:value];
    
    so this is a method call to a method that will (assuming your property has been set to retain) look something like (note I wrote this myself, the actual generated code may be different/better)

    Code:
    -(void) setProperty:(type) value
    {
      if (property!=value)
      {
        [property release];
        property = [value retain];
      }
    }
    
    So the difference between just setting the value directly and calling the setter code, either explicitly or implicitly via the dot syntax should be clear (once you understand what an autoreleased object is).
     
  5. gameplayerxp thread starter macrumors newbie

    gameplayerxp

    Joined:
    Dec 1, 2010
    Location:
    Sydney
    #5
    Really thanks. I'll read that memory management.

    Before reading the book, I still have a question: do I need to manually release onlineBooks? Since it's retained.

    I tried to put the following code for RootViewControler but since the function was never called I could not actually know if it's wrong or not.

    Code:
    - (void)dealloc {
    	[onlineBooks release];
    	[localBooks release];
        [super dealloc];
    }
    
     
  6. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #6
    Yes you should release it when you are done with it. dealloc is the correct place based on your other code.
     
  7. gameplayerxp thread starter macrumors newbie

    gameplayerxp

    Joined:
    Dec 1, 2010
    Location:
    Sydney
    #7
    Thanks mate :D This makes me more confident with Objective-C programming as a newbie :p
     

Share This Page