我正在尝试基于Parse进行聊天我遵循本教程http://attila.tumblr.com/post/21180235691/ios-tutorial-creating-a-chat-room-using-parse-com,但当我尝试发送消息时,应用程序崩溃并出现此异常:
'NSInternalInconsistencyException', reason: 'attempt to insert row 0 into section 0, but there are only 0 rows in section 0 after the update'
我一直在努力修复它,但我找不到这个错误的原因,所以现在我正在努力找到帮助。这是我的代码:
#import "DMChatRoomViewController.h"
#import "chatCell.h"
@interface DMChatRoomViewController ()
@end
@implementation DMChatRoomViewController
@synthesize tfEntry;
@synthesize chatTable;
@synthesize chatData;
#define MAX_ENTRIES_LOADED 25
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
tfEntry.delegate = self;
tfEntry.clearButtonMode = UITextFieldViewModeWhileEditing;
[self registerForKeyboardNotifications];
if (_refreshHeaderView == nil) {
PF_EGORefreshTableHeaderView *view = [[PF_EGORefreshTableHeaderView alloc] initWithFrame:CGRectMake(0.0f, 0.0f - chatTable.bounds.size.height, self.view.frame.size.width, chatTable.bounds.size.height)];
view.delegate = self;
[chatTable addSubview:view];
_refreshHeaderView = view;
}
// update the last update date
[_refreshHeaderView refreshLastUpdatedDate];
}
- (void)viewWillAppear{
className = @"chatroom";
userName = @"John Appleseed";
chatData = [[NSMutableArray alloc] init];
[self loadLocalChat];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
//Chat Room
- (void)viewDidUnload
{
[super viewDidUnload];
[self freeKeyboardNotifications];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#pragma mark - Chat textfield
-(IBAction) textFieldDoneEditing : (id) sender
{
NSLog(@"the text content%@",tfEntry.text);
[sender resignFirstResponder];
[tfEntry resignFirstResponder];
}
-(IBAction) backgroundTap:(id) sender
{
[self.tfEntry resignFirstResponder];
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
NSLog(@"the text content%@",tfEntry.text);
[textField resignFirstResponder];
if (tfEntry.text.length>0) {
// updating the table immediately
NSArray *keys = [NSArray arrayWithObjects:@"text", @"userName", @"date", nil];
NSArray *objects = [NSArray arrayWithObjects:tfEntry.text, userName, [NSDate date], nil];
NSDictionary *dictionary = [NSDictionary dictionaryWithObjects:objects forKeys:keys];
[chatData addObject:dictionary];
NSMutableArray *insertIndexPaths = [[NSMutableArray alloc] init];
NSIndexPath *newPath = [NSIndexPath indexPathForRow:0 inSection:0];
[insertIndexPaths addObject:newPath];
[chatTable beginUpdates];
[chatTable insertRowsAtIndexPaths:insertIndexPaths withRowAnimation:UITableViewRowAnimationTop];
[chatTable endUpdates];
[chatTable reloadData];
// going for the parsing
PFObject *newMessage = [PFObject objectWithClassName:@"chatroom"];
[newMessage setObject:tfEntry.text forKey:@"text"];
[newMessage setObject:userName forKey:@"userName"];
[newMessage setObject:[NSDate date] forKey:@"date"];
[newMessage saveInBackground];
tfEntry.text = @"";
}
// reload the data
[self loadLocalChat];
return NO;
}
-(void) registerForKeyboardNotifications
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWasShown:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}
-(void) freeKeyboardNotifications
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
-(void) keyboardWasShown:(NSNotification*)aNotification
{
NSLog(@"Keyboard was shown");
NSDictionary* info = [aNotification userInfo];
NSTimeInterval animationDuration;
UIViewAnimationCurve animationCurve;
CGRect keyboardFrame;
[[info objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve];
[[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration];
[[info objectForKey:UIKeyboardFrameBeginUserInfoKey] getValue:&keyboardFrame];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:animationDuration];
[UIView setAnimationCurve:animationCurve];
[self.view setFrame:CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y- keyboardFrame.size.height+49, self.view.frame.size.width, self.view.frame.size.height)];
[UIView commitAnimations];
}
-(void) keyboardWillHide:(NSNotification*)aNotification
{
NSLog(@"Keyboard will hide");
NSDictionary* info = [aNotification userInfo];
NSTimeInterval animationDuration;
UIViewAnimationCurve animationCurve;
CGRect keyboardFrame;
[[info objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve];
[[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration];
[[info objectForKey:UIKeyboardFrameBeginUserInfoKey] getValue:&keyboardFrame];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:animationDuration];
[UIView setAnimationCurve:animationCurve];
[self.view setFrame:CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y + keyboardFrame.size.height-49, self.view.frame.size.width, self.view.frame.size.height)];
[UIView commitAnimations];
}
#pragma mark -
#pragma mark Data Source Loading / Reloading Methods
- (void)reloadTableViewDataSource{
// should be calling your tableviews data source model to reload
// put here just for demo
_reloading = YES;
[self loadLocalChat];
[chatTable reloadData];
}
- (void)doneLoadingTableViewData{
// model should call this when its done loading
_reloading = NO;
[_refreshHeaderView egoRefreshScrollViewDataSourceDidFinishedLoading:chatTable];
}
#pragma mark -
#pragma mark UIScrollViewDelegate Methods
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
[_refreshHeaderView egoRefreshScrollViewDidScroll:scrollView];
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{
[_refreshHeaderView egoRefreshScrollViewDidEndDragging:scrollView];
}
#pragma mark - Parse
- (void)loadLocalChat
{
PFQuery *query = [PFQuery queryWithClassName:className];
// If no objects are loaded in memory, we look to the cache first to fill the table
// and then subsequently do a query against the network.
if ([chatData count] == 0) {
query.cachePolicy = kPFCachePolicyCacheThenNetwork;
[query orderByAscending:@"createdAt"];
NSLog(@"Trying to retrieve from cache");
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
// The find succeeded.
NSLog(@"Successfully retrieved %lu chats from cache.", (unsigned long)objects.count);
[chatData removeAllObjects];
[chatData addObjectsFromArray:objects];
[chatTable reloadData];
} else {
// Log details of the failure
NSLog(@"Error: %@ %@", error, [error userInfo]);
}
}];
}
__block int totalNumberOfEntries = 0;
[query orderByAscending:@"createdAt"];
[query countObjectsInBackgroundWithBlock:^(int number, NSError *error) {
if (!error) {
// The count request succeeded. Log the count
NSLog(@"There are currently %d entries", number);
totalNumberOfEntries = number;
if (totalNumberOfEntries > [chatData count]) {
NSLog(@"Retrieving data");
int theLimit;
if (totalNumberOfEntries-[chatData count]>MAX_ENTRIES_LOADED) {
theLimit = MAX_ENTRIES_LOADED;
}
else {
theLimit = totalNumberOfEntries-[chatData count];
}
query.limit = [NSNumber numberWithInt:theLimit];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
// The find succeeded.
NSLog(@"Successfully retrieved %lu chats.", (unsigned long)objects.count);
[chatData addObjectsFromArray:objects];
NSMutableArray *insertIndexPaths = [[NSMutableArray alloc] init];
for (int ind = 0; ind < objects.count; ind++) {
NSIndexPath *newPath = [NSIndexPath indexPathForRow:ind inSection:0];
[insertIndexPaths addObject:newPath];
}
[chatTable beginUpdates];
[chatTable insertRowsAtIndexPaths:insertIndexPaths withRowAnimation:UITableViewRowAnimationTop];
[chatTable endUpdates];
[chatTable reloadData];
[chatTable scrollsToTop];
} else {
// Log details of the failure
NSLog(@"Error: %@ %@", error, [error userInfo]);
}
}];
}
} else {
// The request failed, we'll keep the chatData count?
number = [chatData count];
}
}];
}
#pragma mark -
#pragma mark EGORefreshTableHeaderDelegate Methods
- (void)egoRefreshTableHeaderDidTriggerRefresh:(PF_EGORefreshTableHeaderView*)view{
[self reloadTableViewDataSource];
[self performSelector:@selector(doneLoadingTableViewData) withObject:nil afterDelay:3.0];
}
- (BOOL)egoRefreshTableHeaderDataSourceIsLoading:(PF_EGORefreshTableHeaderView*)view{
return _reloading; // should return if data source model is reloading
}
- (NSDate*)egoRefreshTableHeaderDataSourceLastUpdated:(PF_EGORefreshTableHeaderView*)view{
return [NSDate date]; // should return date data source was last changed
}
#pragma mark - Table view delegate
- (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 [chatData count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
chatCell *cell = (chatCell *)[tableView dequeueReusableCellWithIdentifier: @"chatCellIdentifier"];
NSUInteger row = [chatData count]-[indexPath row]-1;
if (row < chatData.count){
NSString *chatText = [[chatData objectAtIndex:row] objectForKey:@"text"];
cell.textLabel.lineBreakMode = UILineBreakModeWordWrap;
UIFont *font = [UIFont systemFontOfSize:14];
CGSize size = [chatText sizeWithFont:font constrainedToSize:CGSizeMake(225.0f, 1000.0f) lineBreakMode:UILineBreakModeCharacterWrap];
cell.textString.frame = CGRectMake(75, 14, size.width +20, size.height + 20);
cell.textString.font = [UIFont fontWithName:@"Helvetica" size:14.0];
cell.textString.text = chatText;
[cell.textString sizeToFit];
NSDate *theDate = [[chatData objectAtIndex:row] objectForKey:@"date"];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"HH:mm a"];
NSString *timeString = [formatter stringFromDate:theDate];
cell.timeLabel.text = timeString;
cell.userLabel.text = [[chatData objectAtIndex:row] objectForKey:@"userName"];
}
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *cellText = [[chatData objectAtIndex:chatData.count-indexPath.row-1] objectForKey:@"text"];
UIFont *cellFont = [UIFont fontWithName:@"Helvetica" size:14.0];
CGSize constraintSize = CGSizeMake(225.0f, MAXFLOAT);
CGSize labelSize = [cellText sizeWithFont:cellFont constrainedToSize:constraintSize lineBreakMode:UILineBreakModeWordWrap];
return labelSize.height + 40;
}
-(void)presentChatNameDialog
{
UIAlertView *message = [[UIAlertView alloc] initWithTitle:@"Chat Name"
message:@"Choose a chat name, it can be changed later in the Options panel"
delegate:self
cancelButtonTitle:@"Cancel"
otherButtonTitles:@"Continue", nil];
[message setAlertViewStyle:UIAlertViewStylePlainTextInput];
// [message setBackgroundColor:[UIColor colorWithRed:0.7765f green:0.1725f blue:0.1451f alpha:1.0f]];
// [message setAlpha:0.8f];
[message show];
}
@end