Why does UIViewController extend under UINavigationBar, while UITableViewController doesn't?

By default, UITableViewController's views are automatically inset in iOS7 so that they don't start below the navigation bar/status bar. This is controller by the "Adjust scroll view insets" setting on the Attributes Inspector tab of the UITableViewController in Interface Builder, or by the setAutomaticallyAdjustsScrollViewInsets: method of UIViewController.

For a UIViewController's contents, if you don't want its view's contents to extend under the top/bottom bars, you can use the Extend Edges Under Top Bars/Under Bottom Bars settings in Interface Builder. This is accessible via the edgesForExtendedLayout property.


Objective-C:

- (void)viewDidLoad {
    [super viewDidLoad];
    self.edgesForExtendedLayout = UIRectEdgeNone;
 }

Swift 2:

self.edgesForExtendedLayout = UIRectEdge.None

Swift 3+:

self.edgesForExtendedLayout = []

@Gank's answer is correct, but the best place to do this is on the UINavigationControllerDelegate (if you have one):

func navigationController(navigationController: UINavigationController, willShowViewController viewController: UIViewController, animated: Bool) {
    viewController.edgesForExtendedLayout = UIRectEdge.None
}