Note that there are some explanatory texts on larger screens.

plurals
  1. POHow to add dynamically rows to a UITableView in iOS?
    text
    copied!<p>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)</p> <p>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)</p> <p>This is the code that I have in my Controller:</p> <h2>ChatViewController.h</h2> <pre><code>#import &lt;UIKit/UIKit.h&gt; #import "SRWebSocket.h" #import "ChatCell.h" #import "Message.h" #import "Person.h" #import "Program.h" #import "DateFactory.h" @interface ChatViewController : UIViewController &lt;UITableViewDataSource,UITableViewDelegate,SRWebSocketDelegate, UITextViewDelegate, UITextFieldDelegate&gt; @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 </code></pre> <h2>ChatViewController.m</h2> <h3>Code that fails:</h3> <pre><code>[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:_messages.count - 1 inSection:0]] withRowAnimation:UITableViewRowAnimationNone]; </code></pre> <p>in:</p> <pre><code>- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message; { NSLog(@"Received \"%@\"", message); NSError *e; NSDictionary *allJSON = [NSJSONSerialization JSONObjectWithData: [message dataUsingEncoding:NSUTF8StringEncoding] options: NSJSONReadingMutableContainers error: &amp;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; } } </code></pre> <p>ERROR</p> <pre><code>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' </code></pre> <h3>Full code:</h3> <pre><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;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: &amp;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 </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload