title: How to add dynamically rows to a UITableView in iOS?
body: <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>