简体   繁体   中英

'EXEC_BAD_ACCESS' in Table View, “[TasksPageViewController tableView:numberOfRowsInSection:]”

I've been trying to solve this bad reference for 2 days now, but I cannot find a fix.

My application is a basic to-do list with several pages (UIPageControl) for different categories and a first page for statistics about the tasks the user has finished. (if you got 3 categories, you end up with 4 pages).

It loads an array of categories from NSUserDefaults, which can be modified by a modal view accessed through a UIButton just like the (i) in the wheather app.

The Page Control is built by the ViewController class, (which is the primary view). For each element in the array of categories, the view controller generates a new TasksPageViewController class instance and instantiates a storyboard view for it.

Everything was working fine untill I put a UITableView in the TasksPageViewController view in storyboard and linked its dataSource to the same class.

After implementing the required classes for the UITableView dataSource in the TasksPageViewController , it runs fine, but if I try to go to the modal view for modifying the categories, when I press DONE (and it should reload the ViewController and rebuild the many pages for the UIPageControll), the application crashes with a EXEC_BAD_ACCESS.

Debugging with NSZombiesEnabled, I got:

2012-02-12 18:55:49.460 Pontinhos[25601:fe03] * -[TasksPageViewController tableView:numberOfRowsInSection:]: message sent to deallocated instance 0x68c3040

But I don't really know how to proceed, I don't know which object that have been released I'm calling.

The scripts are the following:

ViewController.h

#import <UIKit/UIKit.h>
#import "MainPageViewController.h"
#import "TasksPageViewController.h"

@interface ViewController : UIViewController{

   IBOutlet UIScrollView *scrollView;
    IBOutlet UIPageControl *pageControl;
    NSMutableArray * views;

    // To be used when scrolls originate from the UIPageControl
    BOOL pageControlUsed;
}

@property (nonatomic, retain) IBOutlet UIScrollView *scrollView;
@property (nonatomic, retain) IBOutlet UIPageControl *pageControl;
@property (nonatomic, retain) NSMutableArray *views;

- (void)scrollViewDidScroll:(UIScrollView *)scrollView;
- (IBAction)changePage;

@end

ViewController.m

#import "ViewController.h"

@implementation ViewController

@synthesize scrollView;
@synthesize pageControl;
@synthesize views;

//carrega views que estão na array.
- (void)viewDidLoad
{
    [super viewDidLoad];

    //LoadCategories
    NSUserDefaults *data = [NSUserDefaults standardUserDefaults];
    NSMutableArray *categories = [[NSMutableArray alloc] initWithArray:[data objectForKey:@"categories"]];

    // MAIN PAGE
    MainPageViewController *mainpage = [self.storyboard instantiateViewControllerWithIdentifier:@"MainPageViewController"];
    CGRect mframe = scrollView.frame;
    mframe.origin.x = 0;
    mframe.origin.y = 0;
    mainpage.view.frame = mframe;

    [self.scrollView  addSubview:mainpage.view];

    int i = 1;

    NSLog(@"Iniciando criação de páginas!");

    for(id name in categories) {

        NSLog(@"Carregou página.%i",i);
        NSLog(@"categories count:%i",[categories count]);
        TasksPageViewController *tasks = [self.storyboard instantiateViewControllerWithIdentifier:@"TasksPageViewController"];

        CGRect frame = scrollView.frame;
        frame.origin.x = frame.size.width * i;
        frame.origin.y = 0;
        tasks.view.frame = frame;

        [tasks populateWithData:(i-1) categoryName:name];

        [scrollView addSubview:tasks.view];
        tasks = nil;
        i++;

    }

    self.pageControl.numberOfPages = [categories count]+1;
    self.scrollView.contentSize = CGSizeMake(self.scrollView.frame.size.width * ([categories count]+1), self.scrollView.frame.size.height);

}

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {

    if (pageControlUsed)
    {
        // do nothing - the scroll was initiated from the page control, not the user dragging
        return;
    }

    // Update the page when more than 50% of the previous/next page is visible
    CGFloat pageWidth = self.scrollView.frame.size.width;
    int page = floor((self.scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
    self.pageControl.currentPage = page;
}

- (IBAction)changePage {
    // update the scroll view to the appropriate page
    CGRect frame;
    frame.origin.x = self.scrollView.frame.size.width * self.pageControl.currentPage;
    frame.origin.y = 0;
    frame.size = self.scrollView.frame.size;
    [self.scrollView scrollRectToVisible:frame animated:YES];
    pageControlUsed = YES;
}


// At the begin of scroll dragging, reset the boolean used when scrolls originate from the UIPageControl
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
    pageControlUsed = NO;
}

// At the end of scroll animation, reset the boolean used when scrolls originate from the UIPageControl
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
    pageControlUsed = NO;
}

- (void)viewDidUnload
{
    [super viewDidUnload];
    self.scrollView = nil;
}

@end

TasksPageViewController.h

#import <UIKit/UIKit.h>
#import "TasksTableCellPrototypes.h"

@interface TasksPageViewController : UIViewController <UITableViewDataSource>{

    IBOutlet UILabel *categoryName;
    IBOutlet UITableView *tableView;
    //NSMutableArray *tasksData;

}

//@property (nonatomic,retain)  NSMutableArray *tasksData;
@property (nonatomic,retain)  UITableView *tableView;
@property (nonatomic,retain) UILabel *categoryName;
- (void) populateWithData:(int)dataId categoryName:(NSString *)name;

@end

TasksPageViewController.m

#import "TasksPageViewController.h"

@implementation TasksPageViewController

@synthesize tableView;
//@synthesize tasksData;
@synthesize categoryName;

- (void)viewDidLoad
{
    [super viewDidLoad];

   // NSUserDefaults *data = [NSUserDefaults standardUserDefaults];

    //tasksData = [[NSMutableArray alloc] initWithArray:[data objectForKey:@"tasks"]];

    //tasksData = [[NSMutableArray alloc] initWithObjects:@"lalal",@"lololo",nil];

}


- (void) populateWithData:(int)dataId categoryName:(NSString *)name {

    //self.categoryName.text = name;
}   

// Número de categorias

- (NSInteger)tableView:(UITableView *)tableViewnumberOfSectionsInTableView:(UITableView *)tableView
{
    // Return the number of sections.
    return 1;
}



- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    NSLog(@"contou table view tasks");
    return 4;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{

    TasksTableCellPrototypes *cell = [[TasksTableCellPrototypes alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"taskCell"];
    return cell;

}

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)didReceiveMemoryWarning
{
    // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];

    // Release any cached data, images, etc that aren't in use.
}


- (void)viewDidUnload
{
    [super viewDidUnload];
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
}

Thank you.

EDIT: apparently The ViewController isn't retaining the reference to the TasksPageViewController and the UITableView cannot find its dataSource. I don't really know how to retain this using ARC.

In your ViewController viewDidLoad , when you loop through the categories you instantiate a TasksPageViewController named tasks , but then you do not retain the reference anywhere. So later the TasksPageViewController cannot be found when the tableView:numberOfRowsInSection: message is sent.

I see that in your ViewController your synthesize a property named views but then you do not use that property anywhere. Perhaps you should rename that property viewControllers and then at the end of the loop in viewDidLoad , you should add your tasks object to the viewControllers mutable array, instead of setting tasks to nil. I think that might prevent the crash.

for(id name in categories) {

    TasksPageViewController *tasks = [self.storyboard instantiateViewControllerWithIdentifier:@"TasksPageViewController"];

    ... 

    [scrollView addSubview:tasks.view];
    [self.viewControllers addObject:tasks];
    i++;

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM