There’s a very strange line spacing bug in iOS5+ for iPad: If you’re using a UITableView within which each UITableViewCell is a custom type that contains a UITextView, then cells containing multiple lines of text from non-A-Z languages such as Arabic are dequeued with the wrong line height AFTER the keyboard has been opened in a modal view.
Note: While this seems to be a bug in iOS, I am looking to find a workaround so that my app is backwards-compatible with versions of iOS5+.
Here is how to replicate the bug:
(1)(a) In your storyboard, create a UIViewController (create your own subclass, though) where you have a UIToolbar and a UITableView. In the UITableView, create one “Dynamic Prototype” cell with the identifier “CellIdentifier” and a UITextView with a tag of “1” and all AutoResize properties on (so it takes up the full size of the cell).

(1)(b) In your storyboard, link up the UIToolbar to the “toolbar” variable and the UITableView to the “mainTableView” variable. Set the UITableView “dataSource” and “delegate” to the UIViewController and set the UITextView “delegate” to the UIViewController.
(1)(c) Add the following code to your UIViewController subclass:
MyViewController.h:
#import <UIKit/UIKit.h>
@interface MyViewController : UIViewController <UITableViewDataSource, UITableViewDelegate, UITextViewDelegate>
// the toolbar at the top of the screen
@property (weak, nonatomic) IBOutlet UIToolbar *mainToolbar;
// the table view taking up the screen
@property (weak, nonatomic) IBOutlet UITableView *mainTableView;
@end
MyViewController.m:
#import "MyViewController.h"
@interface MyViewController ()
// array to store text for cells
@property (strong, nonatomic) NSMutableArray *data;
// the number of rows to show
@property (nonatomic) NSInteger numberOfRowsToShow;
// when toolbar buttons are pressed
- (void)showModalViewButtonPressed;
- (void)redrawVisibleCellsButtonPressed;
- (void)insertButtonPressed;
- (void)deleteButtonPressed;
@end
@implementation MyViewController
@synthesize mainTableView;
@synthesize mainToolbar;
@synthesize data;
@synthesize numberOfRowsToShow;
- (void)viewDidLoad {
[super viewDidLoad];
// create data array for cell contents
self.data = [[NSMutableArray alloc] initWithObjects:
@"سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام",
@"سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام",
@"سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام",
@"سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام",
@"سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام",
@"سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام",
@"سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام",
@"سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام",
@"سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام",
@"سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام",
nil];
self.numberOfRowsToShow = 0;
// set toolbar buttons
[self.mainToolbar setItems:[NSArray arrayWithObjects:
[[UIBarButtonItem alloc] initWithTitle:@"Show Modal View" style:UIBarButtonItemStyleBordered target:self action:@selector(showModalViewButtonPressed)],
[[UIBarButtonItem alloc] initWithTitle:@"Redraw Visible Cells" style:UIBarButtonItemStyleBordered target:self action:@selector(redrawVisibleCellsButtonPressed)],
[[UIBarButtonItem alloc] initWithTitle:@"Insert" style:UIBarButtonItemStyleBordered target:self action:@selector(insertButtonPressed)],
[[UIBarButtonItem alloc] initWithTitle:@"Delete" style:UIBarButtonItemStyleBordered target:self action:@selector(deleteButtonPressed)],
nil] animated:YES];
}
- (void)viewDidUnload {
[super viewDidUnload];
// clean up
self.data = nil;
self.mainTableView = nil;
self.mainToolbar = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// only one section
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// return the number of items in the data array
return self.numberOfRowsToShow;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// dequeue cell from storyboard
UITableViewCell *cell = [self.mainTableView dequeueReusableCellWithIdentifier:@"CellIdentifier"];
// get text view
UITextView *cellText = (UITextView *)[cell viewWithTag:1];
// set text using data array
cellText.text = [self.data objectAtIndex:indexPath.row];
// set large font
cellText.font = [UIFont systemFontOfSize:20.0f];
// set background color based on whether the line spacing is correct
if (cellText.contentSize.height == 100.0f) {
// correct height sets a green background
cellText.backgroundColor = [UIColor greenColor];
} else if (cellText.contentSize.height == 88.0f) {
// wrong height sets a red background
cellText.backgroundColor = [UIColor redColor];
}
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
// return constant height
return 150.0f;
}
- (void)textViewDidChange:(UITextView *)textView {
// get parent cell for text view
UITableViewCell *parentCell = (UITableViewCell *)textView.superview.superview;
// get parent cell indent path
NSIndexPath *parentIndexPath = [self.mainTableView indexPathForCell:parentCell];
// save new text to data array
[self.data replaceObjectAtIndex:parentIndexPath.row withObject:textView.text];
}
#pragma mark - Other methods
- (void)showModalViewButtonPressed {
// segue to modal view
[self performSegueWithIdentifier:@"modalSegue" sender:self];
}
- (void)redrawVisibleCellsButtonPressed {
// reload all visible cells in the table view
[self.mainTableView reloadRowsAtIndexPaths:[self.mainTableView indexPathsForVisibleRows] withRowAnimation:UITableViewRowAnimationNone];
}
- (void)insertButtonPressed {
// insert a cell in the table view (increments number of rows to show first)
[self.mainTableView insertRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:self.numberOfRowsToShow++ inSection:0]] withRowAnimation:UITableViewRowAnimationNone];
}
- (void)deleteButtonPressed {
// delete a cell in the table view (decrements number of rows to show first)
[self.mainTableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:--self.numberOfRowsToShow inSection:0]] withRowAnimation:UITableViewRowAnimationNone];
}
@end
(2)(a) In your storyboard, create a UINavigationController and a UIViewController (subclass it too), and set the UIViewController as the root view controller for the UINavigationController in its properties. Add a UIToolbar with a “Done” button to the UIViewController as well as a UITextField. Add a modal segue to the UINavigationController the main view controller called “modalSegue”.

(2)(b) In your storyboard, link up the “Done” button with the IBAction “closeButtonPressed”.
(2)(c) Add the following code to your modal UIViewController:
MyModalViewController.h:
#import <UIKit/UIKit.h>
@interface MyModalViewController : UIViewController
- (IBAction)closeButtonPressed:(id)sender;
@end
MyModalViewController.m:
#import "MyModalViewController.h"
@implementation MyModalViewController
- (IBAction)closeButtonPressed:(id)sender {
[self dismissModalViewControllerAnimated:YES];
}
@end
Testing:
(1) Run the application. When the screen loads, the UITableView will have no content.

(2) Tap the “Insert” button in the toolbar a couple times. Two cells will be added in green. Take note that the line spacing here is 4 pixels taller (at font size 20) for lines containing Arabic versus English only (you can try this yourself with all-English text in a cell). At this stage you are seeing the correct behavior of the app.

(3) Tap the “Show Modal View” button and when the modal view opens, tap inside the UITextField to open the keyboard. Tap “Done” to close the modal view. From this point on, the bug will happen in the UITableView (see next step).

(4) Tap “Insert” several more times. Notice that all new cells are red. This is because the spacing of the lines in the new cells are wrong–they are the spacing used if the text was all-English letters, as the extra 4 pixels are no longer added for Arabic like before.

(5) To really see some bugs, tap the “Redraw Visible Cells” button and watch the colors change around the UITableView as cells are redrawn.
Discussion: It seems that new cells dequeued after the keyboard has been opened in a modal view have the wrong line height for Arabic and other non-English text. This appears to be related to the caching mechanism of the UITableView. The challenge is to find a solution where the proper line spacing is loaded under all circumstances.
This is not a perfect solution, but rather a hack/workaround. The real solution will come when Apple fixes this bug.
Please note: This answer was recommended by Apple Developer Support.
This bug is caused in all UITextViews inside UITableViewCells after a UITextField or UISearchBar becomes the first responder in a modal view with the style Form Sheet.
The workaround is to either:
Option 1 is much faster, but has its own challenges related to scrolling. Option 2 works well, but takes a long time. Research EGOTextView for a good starting point.