Monday, 19 August 2013

How to add dynamically rows to a UITableView in iOS?

How to add dynamically rows to a UITableView in iOS?

I'm developing a view controller for a chat application and I want to show
a UIViewController that contains a UITableView (where messages are shown
with different format [if is your message or if is a message from other
person], a UITextField (to write your messages) and a UIButton (to send
the message)
I'm using SRWebSocket example but they use a UITableViewController (that
runs perfectly but don't allow me to modify tableview size or to add the
others components to the view by storyboard)
This is the code that I have in my Controller:
ChatViewController.h
#import <UIKit/UIKit.h>
#import "SRWebSocket.h"
#import "ChatCell.h"
#import "Message.h"
#import "Person.h"
#import "Program.h"
#import "DateFactory.h"
@interface ChatViewController : UIViewController
<UITableViewDataSource,UITableViewDelegate,SRWebSocketDelegate,
UITextViewDelegate, UITextFieldDelegate>
@property (strong, nonatomic) NSDictionary *programSegue;
@property (retain, nonatomic) IBOutlet UITableView *tableView;
@property (nonatomic, retain) IBOutlet UITextView *inputView;
- (IBAction)goingUp:(id)sender;
@property (weak, nonatomic) IBOutlet UITextField *inputText;
@end
ChatViewController.m
Code that fails:
[self.tableView insertRowsAtIndexPaths:[NSArray
arrayWithObject:[NSIndexPath indexPathForRow:_messages.count - 1
inSection:0]] withRowAnimation:UITableViewRowAnimationNone];
in:
- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message;
{
NSLog(@"Received \"%@\"", message);
NSError *e;
NSDictionary *allJSON =
[NSJSONSerialization JSONObjectWithData: [message
dataUsingEncoding:NSUTF8StringEncoding]
options: NSJSONReadingMutableContainers
error: &e];
NSString *kindJSON = [allJSON objectForKey:@"kind"];
NSString *userJSON = [allJSON objectForKey:@"user"];
NSString *messageJSON = [allJSON objectForKey:@"message"];
NSArray *membersJSON = [allJSON objectForKey:@"members"];
DateFactory *dateFactory = [DateFactory alloc];
NSString *formatDate = @"dd/MM/YYYY HH:mm";
NSString *dateString = [dateFactory dateToString:[NSDate date]
withFormat:formatDate];
switch([@[@"join", @"talk", @"quit"] indexOfObject:kindJSON]){
// join
case 0:
break;
// talk
case 1:
[_messages addObject:[[Message alloc]
initWithMessage:messageJSON fromMe:NO]];
[self.tableView insertRowsAtIndexPaths:[NSArray
arrayWithObject:[NSIndexPath indexPathForRow:_messages.count -
1 inSection:0]] withRowAnimation:UITableViewRowAnimationNone];
[self.tableView
scrollRectToVisible:self.tableView.tableFooterView.frame
animated:YES];
break;
// quit
case 2:
[[self.navigationItem.titleView.subviews objectAtIndex:1]
setText:
[NSString stringWithFormat:@"Sin conexión desde %@",
dateString]];
break;
}
}
ERROR
Terminating app due to uncaught exception
'NSInternalInconsistencyException', reason: 'attempt to insert row 0 into
section 0, but there are only 0 rows in section 0 after the update'
Full code:
#import "ChatViewController.h"
@interface ChatViewController ()
@end
@implementation ChatViewController{
SRWebSocket *_webSocket;
NSMutableArray *_messages;
Person *person;
Program *program;
}
@synthesize programSegue;
@synthesize tableView;
@synthesize inputText;
@synthesize inputView = _inputView;
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
return [inputText resignFirstResponder];
}
#pragma mark - View lifecycle
- (void)viewDidLoad;
{
[super viewDidLoad];
[inputText setDelegate:self];
person = [programSegue objectForKey:@"PERSON"];
program = [programSegue objectForKey:@"PROGRAM"];
self.navigationItem.title = person.name;
// Creates picture to be shown in navigation bar
UIButton* picture = (UIButton *) [[UIImageView alloc]
initWithImage:[UIImage imageNamed:person.imageURL]];
CGRect buttonFrame = picture.frame;
buttonFrame.size = CGSizeMake(38, 38);
picture.frame = buttonFrame;
UIBarButtonItem *pictureItem = [[UIBarButtonItem alloc]
initWithCustomView:picture];
self.navigationItem.rightBarButtonItem = pictureItem;
// Set title and subtitle
CGRect frame = self.navigationController.navigationBar.frame;
UIView *twoLineTitleView = [[UIView alloc]
initWithFrame:CGRectMake(CGRectGetWidth(frame), 0,
CGRectGetWidth(frame), CGRectGetHeight(frame))];
UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 6,
CGRectGetWidth(frame), 20)];
titleLabel.backgroundColor = [UIColor clearColor];
[titleLabel setTextColor:[UIColor whiteColor]];
titleLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth;
[titleLabel setTextAlignment:NSTextAlignmentCenter];
[titleLabel setFont:[UIFont boldSystemFontOfSize:16]];
[titleLabel setShadowColor:[UIColor grayColor]];
titleLabel.text = person.name;
[twoLineTitleView addSubview:titleLabel];
UILabel *subTitleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0,
26, CGRectGetWidth(frame), 14)];
subTitleLabel.backgroundColor = [UIColor clearColor];
[subTitleLabel setTextColor:[UIColor whiteColor]];
subTitleLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth;
[subTitleLabel setTextAlignment:NSTextAlignmentCenter];
[subTitleLabel setFont:[UIFont boldSystemFontOfSize:12]];
[titleLabel setShadowColor:[UIColor grayColor]];
subTitleLabel.text = @"subtitleg";
[twoLineTitleView addSubview:subTitleLabel];
self.navigationItem.titleView = twoLineTitleView;
// Start messages
_messages = [[NSMutableArray alloc] init];
[self.tableView reloadData];
}
- (void)_reconnect;
{
_webSocket.delegate = nil;
[_webSocket close];
_webSocket = [[SRWebSocket alloc] initWithURLRequest:
[NSURLRequest requestWithURL:
[NSURL URLWithString:
[NSString
stringWithFormat:@"ws://81.45.19.228:8000/room/chat?username=enrimr&amp;pid=%@",
person.name]]]];
_webSocket.delegate = self;
//self.title = @"Opening Connection...";
[[self.navigationItem.titleView.subviews objectAtIndex:1]
setText:@"Conectando..."];
[_webSocket open];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self _reconnect];
}
- (void)reconnect:(id)sender;
{
[self _reconnect];
}
- (void)viewDidAppear:(BOOL)animated;
{
[super viewDidAppear:animated];
[_inputView becomeFirstResponder];
[self.tableView
scrollRectToVisible:self.tableView.tableFooterView.frame
animated:YES];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
_webSocket.delegate = nil;
[_webSocket close];
_webSocket = nil;
}
#pragma mark - UITableViewController
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section;
{
return _messages.count;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
- (void)tableView:(UITableView *)tableView
willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath
*)indexPath;
{
ChatCell *chatCell = (id)cell;
Message *message = [_messages objectAtIndex:indexPath.row];
chatCell.text.text = message.message;
chatCell.date.text = message.fromMe ? @"Me" : @"Other";
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath;
{
Message *message = [_messages objectAtIndex:indexPath.row];
ChatCell *cell = (ChatCell *)[self.tableView
dequeueReusableCellWithIdentifier:@"programCell"
forIndexPath:indexPath];
if (!cell) {
if (message.fromMe){
cell = [[ChatCell
alloc]initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:@"SentCell"];
[cell.text setText:message.message];
[cell.date setText:@"00:00"];
}
else {
cell = [[ChatCell
alloc]initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:@"ReceivedCell"];
[cell.text setText:message.message];
[cell.date setText:@"00:00"];
}
}
return cell;
}
#pragma mark - SRWebSocketDelegate
- (void)webSocketDidOpen:(SRWebSocket *)webSocket;
{
NSLog(@"Websocket Connected");
//self.title = @"Connected!";
[[self.navigationItem.titleView.subviews objectAtIndex:1]
setText:@"Conectado"];
}
- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error;
{
NSLog(@":( Websocket Failed With Error %@", error);
self.title = @"Connection Failed! (see logs)";
_webSocket = nil;
}
- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message;
{
NSLog(@"Received \"%@\"", message);
NSError *e;
NSDictionary *allJSON =
[NSJSONSerialization JSONObjectWithData: [message
dataUsingEncoding:NSUTF8StringEncoding]
options: NSJSONReadingMutableContainers
error: &e];
NSString *kindJSON = [allJSON objectForKey:@"kind"];
NSString *userJSON = [allJSON objectForKey:@"user"];
NSString *messageJSON = [allJSON objectForKey:@"message"];
NSArray *membersJSON = [allJSON objectForKey:@"members"];
DateFactory *dateFactory = [DateFactory alloc];
NSString *formatDate = @"dd/MM/YYYY HH:mm";
NSString *dateString = [dateFactory dateToString:[NSDate date]
withFormat:formatDate];
switch([@[@"join", @"talk", @"quit"] indexOfObject:kindJSON]){
// join
case 0:
break;
// talk
case 1:
[_messages addObject:[[Message alloc]
initWithMessage:messageJSON fromMe:NO]];
[self.tableView insertRowsAtIndexPaths:[NSArray
arrayWithObject:[NSIndexPath indexPathForRow:_messages.count -
1 inSection:0]] withRowAnimation:UITableViewRowAnimationNone];
[self.tableView
scrollRectToVisible:self.tableView.tableFooterView.frame
animated:YES];
break;
// quit
case 2:
[[self.navigationItem.titleView.subviews objectAtIndex:1]
setText:
[NSString stringWithFormat:@"Sin conexión desde %@",
dateString]];
break;
}
}
- (void)webSocket:(SRWebSocket *)webSocket
didCloseWithCode:(NSInteger)code reason:(NSString *)reason
wasClean:(BOOL)wasClean;
{
NSLog(@"WebSocket closed");
//self.title = @"Connection Closed! (see logs)";
[[self.navigationItem.titleView.subviews objectAtIndex:1]
setText:@"Offline"];
_webSocket = nil;
}
- (BOOL)textView:(UITextView *)textView
shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text;
{
if ([text rangeOfString:@"\n"].location != NSNotFound) {
NSString *message = [[textView.text
stringByReplacingCharactersInRange:range withString:text]
stringByTrimmingCharactersInSet:[NSCharacterSet
whitespaceAndNewlineCharacterSet]];
[_webSocket send:message];
[_messages addObject:[[Message alloc] initWithMessage:message
fromMe:YES]];
[self.tableView insertRowsAtIndexPaths:[NSArray
arrayWithObject:[NSIndexPath indexPathForRow:_messages.count - 1
inSection:0]] withRowAnimation:UITableViewRowAnimationNone];
[self.tableView
scrollRectToVisible:self.tableView.tableFooterView.frame
animated:YES];
textView.text = @"";
return NO;
}
return YES;
}
- (void) animateTextField: (UITextField*) textField up: (BOOL)up
{
const int movementDistance = 218;
const float movementDuration = 0.3f;
int movement = (up ? -movementDistance : movementDistance);
[UIView beginAnimations: @"anim" context: nil];
[UIView setAnimationBeginsFromCurrentState: YES];
[UIView setAnimationDuration: movementDuration];
self.view.frame = CGRectOffset(self.view.frame, 0, movement);
[UIView commitAnimations];
}
- (IBAction)goingUp:(id)sender {
[self animateTextField:inputText up:TRUE];
}
@end

No comments:

Post a Comment