Your modal segue is basically doing:
[loginViewController presentViewController:mainViewController animated:YES completion: ...];
What this means is that mainViewController becomes loginViewControllers presentedViewController:
loginViewController.presentedViewController == mainViewController
mainViewController.presentingViewController == loginViewController
When you're presenting a view controller, the presenting view controller remains in the view controller hierarchy, so that you can later navigate back by calling:
[loginViewController dismissViewControllerAnimated: ...];
So it's perfectly normal that loginViewController is not released, since it's still the window's rootViewController. It's only that loginViewController is obstructed by the presented mainViewController.
If you want to eradicate loginViewController you can set window.rootViewController directly, but that wouldn't animate the transition. You can achieve animation by messing around the view controllers' views, but it's kind of outside the officially sanctioned territory...
IMO the cleanest solution would be to implement a basic container view controller that would be your window's rootViewController, and that could orchestrate the transition between loginViewController and mainViewController by animating their views, and then throwing away loginViewController. It would be kind of a primitive navigation controller without a navigation bar and a navigation stack – just swapping the current view controller with the new one, and throwing away the former.