超越界限错误

时间:2015-03-22 22:23:26

标签: ios objective-c uitableview

我的应用程序有一个表视图,其中包含从Parse表中获取的作业列表。用户可以点击" +"导航栏上的按钮转到另一个屏幕以创建新作业。创建新作业后,它将返回到刚刚创建的作业列表,现在将添加到列表中。问题是我可以选择已经在列表中的两个作业没有问题但是当我尝试选择新作业时,应用程序崩溃时出现此错误:

Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayI objectAtIndex:]: index 2 beyond bounds [0 .. 1]'

以下是职位列表的代码:

#import "UnassignedJobs.h"
#import "AppDelegate.h"
#import "NavController.h"
#import "LogInViewController.h"
#import "NewJobViewController.h"
#import "JobDetailViewController.h"
#import <Parse/Parse.h>

@interface UnassignedJobs ()

@property (nonatomic, strong) NSMutableArray *jobs;
@property (nonatomic, strong) NSMutableArray *objectIds;
@property (nonatomic, strong) UIActivityIndicatorView *loadingIndicator;
@property (nonatomic, strong) UIRefreshControl *refresh;

@end

@implementation UnassignedJobs

- (void)viewDidLoad {
    [super viewDidLoad];

    [self.tableView setDataSource:self];
    [self.tableView setDelegate:self];

    UIBarButtonItem *logoutButton = [[UIBarButtonItem alloc]initWithTitle:@"Logout" style:UIBarButtonItemStylePlain target:self action:@selector(logoutPressed)];
    self.navigationItem.leftBarButtonItem = logoutButton;

    UIBarButtonItem *newJobButton = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(createJob)];
    self.navigationItem.rightBarButtonItem = newJobButton;

    NSString *currentUserFullName = [[PFUser currentUser]objectForKey:@"Name"];
    if ([currentUserFullName isEqualToString:@"Cory Pollard"] || [currentUserFullName isEqualToString:@"Richie Ray"]) {
        newJobButton.enabled = YES;
    }
    else {
        newJobButton.enabled = NO;
    }

    CGFloat width = CGRectGetWidth(self.view.bounds);
    CGFloat height = CGRectGetHeight(self.view.bounds);

    self.loadingIndicator = [[UIActivityIndicatorView alloc]initWithFrame:CGRectMake(width / 2, height / 2, 37, 37)];
    self.loadingIndicator.center = CGPointMake(width / 2, height / 2 - 37);
    self.loadingIndicator.autoresizingMask = (UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleTopMargin);
    self.loadingIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyleGray;
    self.loadingIndicator.hidesWhenStopped = YES;
    [self.view addSubview:self.loadingIndicator];
    [self.loadingIndicator startAnimating];

    [self getJobs];

    self.refresh = [[UIRefreshControl alloc]init];
    self.refresh.tintColor = [UIColor blackColor];
    [self.refresh addTarget:self action:@selector(refreshData) forControlEvents:UIControlEventValueChanged];
    self.refreshControl = self.refresh;
}

- (void)viewDidAppear:(BOOL)animated {

}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (void)getJobs {
    self.jobs = [[NSMutableArray alloc]init];
    self.objectIds = [[NSMutableArray alloc]init];

    PFQuery *query = [PFQuery queryWithClassName:@"Jobs"];
    [query setLimit:1000];
    [query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
        if (!error) {

            for (NSDictionary *objectDictionary in objects) {
                NSString *assigned = [objectDictionary objectForKey:@"assigned"];
                if ([assigned isEqualToString:@"no"]) {
                    [self.jobs addObject:objectDictionary];
                    // self.objectIds = [objects valueForKeyPath:@"objectId"];
                }

                for (int i = 0; i < self.jobs.count; i++) {
                    [self.objectIds addObject:[self.jobs valueForKeyPath:@"objectId"]];
                }
            }

            dispatch_async(dispatch_get_main_queue(), ^ {

                [self.tableView reloadData];

                [self.loadingIndicator stopAnimating];
            });
        }
        else {
            NSLog(@"Error: %@ %@", error, [error userInfo]);
        }
    }];
}

- (void)createJob {
    AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication]delegate];

    NewJobViewController *jobCreateScreen = [[NewJobViewController alloc]initWithNibName:@"NewJobViewController" bundle:nil];
    NavController *newJobNav = [[NavController alloc]initWithRootViewController:jobCreateScreen];
    newJobNav.delegate = jobCreateScreen;

    appDelegate.window.rootViewController = newJobNav;
}

- (void)logoutPressed {
    [PFUser logOut];

    AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication]delegate];

    LogInViewController *loginScreen = [[LogInViewController alloc]initWithNibName:@"LogInViewController" bundle:nil];
    NavController *loginNavController = [[NavController alloc]initWithRootViewController:loginScreen];
    loginNavController.delegate = loginScreen;

    appDelegate.window.rootViewController = loginNavController;
}

- (void)refreshData {
    [self getJobs];

    [self.refresh endRefreshing];
}

#pragma mark - Table view data source

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

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    // Return the number of rows in the section.
    return self.jobs.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"UITableViewCell"];
    NSDictionary *jobDictionary = [self.jobs objectAtIndex:[indexPath row]];

    if (cell == nil) {
        cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"UITableViewCell"];
    }

    if (cell) {
        cell.backgroundColor = [UIColor clearColor];
        cell.textLabel.textColor = [UIColor blackColor];

        cell.textLabel.text = [jobDictionary objectForKey:@"job"];
    }

    return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    NSDictionary *jobDictionary = [self.jobs objectAtIndex:[indexPath row]];

    JobDetailViewController *jobDetails = [[JobDetailViewController alloc]initWithNibName:@"JobDetailViewController" bundle:nil];
    jobDetails.jobName = [jobDictionary objectForKey:@"job"];

    NSDateFormatter *formatter = [[NSDateFormatter alloc]init];
    // [formatter setDateFormat:@"MM-dd-yyyy"];
    formatter.dateStyle = NSDateFormatterLongStyle;
    formatter.timeStyle = NSDateFormatterShortStyle;
    jobDetails.jobDate = [formatter stringFromDate:[jobDictionary objectForKey:@"date"]];

    jobDetails.objectId = [[self.objectIds objectAtIndex:indexPath.row]objectAtIndex:indexPath.row];
    jobDetails.assignedWorker = [jobDictionary objectForKey:@"worker"];
    jobDetails.details = [jobDictionary objectForKey:@"details"];

    [self.navigationController pushViewController:jobDetails animated:YES];
}

@end

以下是创建新工作的代码:

#import "NewJobViewController.h"
#import "AppDelegate.h"
#import "NavController.h"
#import "TabController.h"
#import "UnassignedJobs.h"
#import "AssignedJobs.h"
#import "MyJobs.h"
#import "Users.h"
#import "CompletedJobs.h"
#import <Parse/Parse.h>

@interface NewJobViewController ()

@property (weak, nonatomic) IBOutlet UITextField *jobName;
@property (weak, nonatomic) IBOutlet UITextView *detailTextView;
@property (weak, nonatomic) IBOutlet UIDatePicker *datePicker;
@property (weak, nonatomic) IBOutlet UIButton *createJobButton;
@property (nonatomic, strong) NSDate *jobDate;
@property (nonatomic, strong) NSString *dateString;

@end

@implementation NewJobViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.

    self.title = @"Create Job";

    UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc]initWithTitle:@"Cancel" style:UIBarButtonItemStylePlain target:self action:@selector(cancel)];
    self.navigationItem.leftBarButtonItem = cancelButton;

    [self.datePicker addTarget:self action:@selector(updateDateString) forControlEvents:UIControlEventValueChanged];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (void)returnToMainScreen {
    AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication]delegate];

    UnassignedJobs *unassignedJobs = [[UnassignedJobs alloc]initWithNibName:@"UnassignedJobs" bundle:nil];
    unassignedJobs.title = @"Unassigned";
    NavController *navController = [[NavController alloc]initWithRootViewController:unassignedJobs];
    navController.delegate = unassignedJobs;

    AssignedJobs *assignedJobs = [[AssignedJobs alloc]initWithNibName:@"AssignedJobs" bundle:nil];
    assignedJobs.title = @"Assigned";
    NavController *assignedNav = [[NavController alloc]initWithRootViewController:assignedJobs];
    assignedNav.delegate = assignedJobs;

    CompletedJobs *completed = [[CompletedJobs alloc]initWithNibName:@"CompletedJobs" bundle:nil];
    completed.title = @"Completed";
    NavController *completedNav = [[NavController alloc]initWithRootViewController:completed];
    completedNav.delegate = completed;

    MyJobs *myJobs = [[MyJobs alloc]initWithNibName:@"MyJobs" bundle:nil];
    myJobs.title = @"My Jobs";
    NavController *myNav = [[NavController alloc]initWithRootViewController:myJobs];
    myNav.delegate = myJobs;

    Users *userList = [[Users alloc]initWithNibName:@"Users" bundle:nil];
    userList.title = @"Users";
    NavController *userNav = [[NavController alloc]initWithRootViewController:userList];
    userNav.delegate = userList;

    TabController *tabController = [[TabController alloc]init];
    tabController.viewControllers = @[navController, assignedNav, completedNav, myNav, userNav];

    appDelegate.window.rootViewController = tabController;
}

- (void)updateDateString {
    NSDateFormatter *formatter = [[NSDateFormatter alloc]init];
    formatter.dateStyle = NSDateFormatterLongStyle;
    formatter.timeStyle = NSDateFormatterMediumStyle;
    self.dateString = [formatter stringFromDate:self.datePicker.date];
    self.jobDate = [formatter dateFromString:self.dateString];
}

- (IBAction)createJob:(id)sender {
    PFObject *job = [PFObject objectWithClassName:@"Jobs"];
    job[@"job"] = self.jobName.text;
    job[@"details"] = self.detailTextView.text;
    job[@"assigned"] = @"no";
    job[@"date"] = self.jobDate;
    [job saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
        if (succeeded) {
            // Close this window and return to unassigned jobs
            [self returnToMainScreen];
        }
        else {
            NSString *errorString = [[error userInfo] objectForKey:@"error"];
            UIAlertView *errorAlert = [[UIAlertView alloc]initWithTitle:@"Job could not be saved!" message:errorString delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
            [errorAlert show];
        }
    }];
}

- (void)cancel {
    [self returnToMainScreen];
}

# pragma mark UITextView Delegate Methods

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {

    if([text isEqualToString:@"\n"]) {
        [textView resignFirstResponder];
        return NO;
    }

    return YES;
}

# pragma mark UITextField Delegate Methods

- (BOOL)textFieldShouldReturn:(UITextField *)textField {
    [textField resignFirstResponder];
    return NO;
}

@end

2 个答案:

答案 0 :(得分:0)

您必须重新加载作业数据源,然后再次显示该表,

所以,

@implementation UnassignedJobs ...
- (void)viewDidAppear:(BOOL)animated {
[self getJobs];
[self.table reloadData];
}

并且不要忘记清理可变数组

- (void)getJobs {
    [self.jobs removeAllObjects];
    [self.objectIds removeAllObjects];
    self.jobs = [[NSMutableArray alloc]init];
    self.objectIds = [[NSMutableArray alloc]init];
...}

答案 1 :(得分:0)

MaKo说明你需要重新加载作业数据源是正确的(因为在你弹回到表控制器之后,数据源在重新加载之前不会知道新行。但是,你不要&# 39;需要重新启动数组(即使你这样做了,你也不需要先删除所有对象,因为它是多余的)。最好还是要正确维护你现有的数组而不是每次创造新的。