π 2020.1.30 (THU)
WWDC 2015 | Session : 231| Category : UIKit
π Cocoa Touch Best Practices - WWDC 2015 - Videos - Apple Developer
First best practice is launch quickly. That's how you appear responsive when the user taps on your icon and right away they get your app ready to interact with.
- Return quickly from
applicationDidFinishLaunching
- Defer long running work
- App killed if too much time passes
Being responsive to every input
- Not just about asynchrony
- Move long running work to background queues
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]?) -> Bool {
globalDataStructure = MyCoolDataStructure()
// defer work until later
DispatchQueue.global().async {
globalDataStructure.fetchDataFromDatabase()
}
return true
}
Whenever it does run, user interface continues to happen, and your application seems responsive all the time. So this technique, putting the work on background queues, can be applied anytime in your app.
That app is the first on that's going to die when the foreground app needs additional memory.
β¬οΈ
Properly manage version change
- Target two most recent major release
- Include version fallbacks
- Have an else clause
No longer makes sense to build layouts that are built specific for a particular dimension that your ViewController expects to be in.
Instead, layout in general wants to think of itself as being done to proportions, and we do that by specifically avoiding hard-coded values in the layout of Views and ViewControllers.
- Avoid hard-coded layout values
- Either or both dimensions may scale
- Some size thresholds trigger major change
- Packaged in UITraitCollection
Avoid setTag:
and viewWithTag:
- Possible collisions with other code
- No compiler warnings
- No runtime errors
Instance variables and properties provide better alternative
class ViewController: UIViewController {
var imageView: UIImageView
overrride func viewDidLoad() {
super.viewDidLoad()
imageView = UIView(frame: CGRect(x: 0, y :0, widht: 50, height: 50))
view.addSubview(imageView)
}
}
Keep real reference to that view, also has better type information because viewWithTag:
only is a type UIView.
Leverage UIViewControllerTransitionCoordinator
(to know what the timings are for the animations that you have)
- Animate alongside a transition
- Get accurate completion timing
- Support interactive and cancelable animations
- Identify constraints that get changed, added, or removed
- Unchanged constraints are optimized
- Avoid removing all constraints
- Use explicit constraint references
βββ
override func updateViewConstraints() {
super.updateViewConstraints()
view.removeConstraints(view.constraints())
view.addConstraints(self.genereatdConstraints())
}
β β β
override func updateViewConstraints() {
super.updateViewConstraints()
view.removeConstraints(imageViewHorizontalConstraint)
imageViewHorizontalConstraints = self.generatedImageViewHorizontalConstraint()
view.addConstraint(imageViewHorizontalConstraint)
}
De-duplicating constraints
- Duplicates are implied by existing constraints
- Duplicates causes excess work in layout engine It's solving for these constraints because they are there, but didn't actually need to solve for them.
This view hierarchy would have laid out exactly the same if I hadn't specified the left margin of the bottom view.
Get rid of that we'll be faster.
Create flexible constraints
- Avoid hard-coded values
- Describe constraints using bounds
Fully specify constraints
- Underspecification generates ambiguity
- Ambiguity is undefined View might come out different ways different times I run my app.
Testing and debugging
-[UIView hasAmbiguousLayout] It will let you know if there's ambiguity in you view.
- When called on UIWindow, returns result for entire view tree
-[UIView _autolayoutTrace]
- Both can be used for unit testing
- Fully specify constraints
- Width = input, height = output
tableView.beginUpdates
- Update model
- Update cell contents
tableView.endUpdates
Modify only what is needed
- Invalidate on bounds change
- Build targeted invalidation context
- Repeat as necessary