大家好,我正在通过教程 http://attila.tumblr.com/post/21180235691/ios-tutorial-creating-a-chat-room-using-parse-com在我的应用程序中插入聊天
PS 美丽的教程!
好吧,我已经更改了所有已弃用并解决了查询中的双重调用问题- (void) loadLocalChat,在教程中仍然显示了与旧 SDK Parse 一起使用的查询。
目前一切正常,但是当我发送消息时,保存日志时出现以下错误并且应用程序崩溃。
异常“NSInvalidArgumentException”,原因:“ * -[NSDictionary initWithObjects:forKeys:]:对象计数 (1) 与键计数 (3) 不同”
并且'整个下午仔细检查代码但我找不到错误......我总是求助于你,因为也许疲劳,经常可以'分散我的注意力。
非常感谢您的所有帮助....
#import "UFF_Chat.h"
#import "FF_CellChat.h"
@interface UFF_Chat ()
@end
@implementation UFF_Chat
@synthesize tfEntry;
@synthesize ChatData;
@synthesize chatTable;
BOOL _reloading;
#define TEXTFIELD_HEIGHT 70.0f
#define TOOLBAR_HEIGHT 40.0f
#define MAX_ENTRIES_LOADED 25
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
tfEntry.delegate = self;
tfEntry.clearButtonMode = UITextFieldViewModeWhileEditing;
[self registerForKeyboardNotifications];
if (refresh == 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];
refresh = view;
}
// update the last update date
[refresh refreshLastUpdatedDate];
}
- (void)viewDidUnload
{
[super viewDidUnload];
[self freeKeyboardNotifications];
}
- (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;
[refresh egoRefreshScrollViewDataSourceDidFinishedLoading:chatTable];
}
-(void)viewDidAppear:(BOOL)animated {
chatData = [[NSMutableArray alloc] init]; [self loadLocalChat];
}
- (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:@"Chat"];
[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;
}
#pragma mark -
#pragma mark UIScrollViewDelegate Methods
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
[refresh egoRefreshScrollViewDidScroll:scrollView];
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{
[refresh egoRefreshScrollViewDidEndDragging:scrollView];
}
#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
}
-(IBAction) backgroundTap:(id) sender
{
[self.tfEntry resignFirstResponder];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [chatData count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
FF_CellChat *cell = (FF_CellChat *)[tableView dequeueReusableCellWithIdentifier: @"chatCellIdentifier"];
NSUInteger row = [chatData count]-[indexPath row]-1;
if (row < chatData.count){
NSString *chatText = [[chatData objectAtIndex:row] objectForKey:@"text"];
cell.textLabel.lineBreakMode = NSLineBreakByWordWrapping;
UIFont *font = [UIFont systemFontOfSize:14];
CGSize size = [chatText sizeWithFont:font constrainedToSize:CGSizeMake(225.0f, 1000.0f) lineBreakMode:NSLineBreakByCharWrapping];
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:NSLineBreakByCharWrapping];
return labelSize.height + 40;
}
-(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+TOOLBAR_HEIGHT, 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-TOOLBAR_HEIGHT, self.view.frame.size.width, self.view.frame.size.height)];
[UIView commitAnimations];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)textFieldDoneEditing:(id)sender {
NSLog(@"the text content%@",tfEntry.text);
[sender resignFirstResponder];
[tfEntry resignFirstResponder];
}
#pragma mark - Parse
- (void)loadLocalChat
{
PFQuery *query = [PFQuery queryWithClassName:@"Chat"];
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 %d chats from cache.", objects.count);
[chatData removeAllObjects];
[chatData addObjectsFromArray:objects];
[chatTable reloadData];
} else {
// Log details of the failure
NSLog(@"Error: %@ %@", error, [error userInfo]);
}
}];
}
PFQuery *query1 = [PFQuery queryWithClassName:@"Chat"];
__block int totalNumberOfEntries = 0;
[query1 orderByAscending:@"createdAt"];
[query1 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];
[query1 findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
// The find succeeded.
NSLog(@"Successfully retrieved %d chats.", 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];
}
}];
}
@end