Just some random stuff I'm learning as I make my first iOS app.
present()
will always show the view controller modally, whereas with show()
it will bubble up the chain where it can be handled by some parent view
controller.
For example, if you use UIAlertController
, you should use present()
,
because alert dialogs are modal.
If you are using UINavigationController
, use show()
to display the view
controller for navigation like the settings app (nested menus).
This generates a trampoline function that allows Objective-C code to call into Swift. This is necessary as Swift uses a different ABI from Objective-C.
@UIApplicationMain
tells Swift that the class contains the entry point of the
program, and that it should instantiate your class and call
UIApplicationMain()
for you. @main
tells Swift that the class contains a
function called main()
which is the entry point of the program.
You can use either one for iOS apps, as UIApplicationDelegate
contains its
own main()
implementation that just calls UIApplicationMain()
.
Or if you want to do it yourself, put this into main.swift
:
import UIKit
UIApplicationMain(
CommandLine.argc,
CommandLine.unsafeArgv,
nil,
NSStringFromClass(AppDelegate.self)
)
Most of these have Android analogies:
willConnect
<--> onCreate
- you create the views/view controllers here
willEnterForeground
<--> onStart
- app is about to be shown on the screen
didBecomeActive
<--> onResume
- app is top-level and receiving user input
willResignActive
<--> onPause
- app is about to be hidden (e.g. by a modal dialog)
didEnterBackground
<--> onStop
- user pressed the home button/switched apps
didDisconnect
<--> onDestroy
- not sure when you get this
Note that this lifecycle is not strict. As in, it's possible to get some messages twice in a row. Always assume this can happen, and make your lifecycle handlers idempotent.
Load into images using UIImage(systemName: "<icon name>")
. Note that the
color of the icon is set by the tint color of the control you put this in,
which is by default blue. Do not try to force the "tint" onto the image
itself using withTintColor
.
In your scene:willConnextTo:options:
method, replace the content with:
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = YourViewController()
window.makeKeyAndVisible()
self.window = window
}
To create views, override loadView()
in your view controller, and (this is
super important) set self.view
to whatever view you want to be the "root"
of the window. If you don't need a custom root view, you can skip this; the
default loadView()
implementation behaves as if you had written
self.view = UIView()
. Make sure that you WRITE to self.view
as the first
thing in this function, as reading from self.view
with no value set will
call loadView()
again and wreck your stack.
If you're creating your views manually (see above), there is no difference.
If you're using interface builder, override viewDidLoad()
.
Child views should never set their own layout constraints relative to their superview. Instead, the parent should set constraints on the child view after adding them to the view hierarchy.
ALWAYS set this to false if you are using auto layout. Which you should be doing. In other words, ALWAYS set this to false. If you don't, views will mysteriously fail to layout correctly.
More generally, to create UIs that scale well, think really hard every time you
write .frame
or .bounds
. 99% of the time, that code is wrong and will break
the moment you rotate your device.
UIView.animate
can be used to animate auto layout constraints. To make this
work, you should (in this order):
-
Call
layoutIfNeeded
on the PARENT of the view you want to lay out. It's absolutely critical that you do it on the parent view. If you do it on the view itself, the animation will not work. The reason we do this is to make sure that the view is in the correct position to begin the animation. -
Adjust constraints as needed.
-
Call
UIView.animate
, and in theanimations
block, calllayoutIfNeeded
, again on the PARENT view.
You can also put the constraint adjustments into the animations
block before
the call to layoutIfNeeded
, that has the same effect.