Saurabh 😎
WWDC 2018: Adding Delight to Your iOS App
Six main topics: External displays, Layout-driven UI, Fast launch, Smooth scrolling, Continuity/Handoff, Debugging
External Display Support
Show private information on device display, public information on external one
Don't show UI controls on external displays since they're not interactive
Check UIScreen.screens.count > 1
for external display and subscribe to UIScreen
screen notifications
Layout-Driven UI
Recipe:
- Find and track all state that affects UI
- Use property observers to dirty layout when state changes with
setNeedsLayout
- Update UI with state in
layoutSubviews
For animations, after you make a state change, call self.layoutIfNeeded()
in an animation block with .beginFromCurrentState
- the animations will happen "automatically" as you make state updates
Fast Launch
Anatomy of a launch:
- Process Forking
- Dynamic Linking
- Steps include: allocating memory for execution, dynamic linking and loading, static object initialization
- 40-50% of typical launch time
- Tips:
- Avoid code duplication to reduce code size
- Limit use of third-party libraries - unlike first-party libraries (e.g. UIKit) which are cached and reused across processes, 3rd party libs are loaded separately for each app
- Avoid static initializers
- Also see: WWDC 2017 App Startup Time: Past, Present, and Future
- UI Construction
- Return quickly from app delegate methods
- Avoid reading very large data sets and avoid any disk writes at all
- First Frame
- Only prepare the UI you need and lazily load everything else
- Don't bring in views that are initially hidden (load them lazily instead before they become visible)
- Extended Launch Actions
- Background work you kicked off during launch to load initial app state
- App is responsive but not usable
- Use clear loading animation for slow network conditions
Measure launch time continuously, ideally after every commit
Smooth Scrolling
2 reasons for dropped frames:
- Too much computation
- Use Time Profiler (see WWDC 2016: Using Time Profiler in Instruments and WWDC 2015: Profiling in Depth)
- Use prefetching in UICollectionView and UITableView
- Push work to background queue (e.g. image drawing and attributed strings text sizing)
- Too much graphics compositing
- Use Core Animation instrument
- See WWDC 2014: Advanced Graphics and Animations for iOS Apps
Continuity/Handoff
Finds peer devices that are signed in to same iCloud account
Does not require Internet connection since relies on peer-to-peer
Main API is NSUserActivity
Also implemented for free with UIDocument
/NSDocument
Use continuationStreams
for sharing arbitrary data that won't fit in basic activity object
Set webpageURL
to transfer from native app to web app
Can also do web browser to native app using associated-domains entitlement
See WWDC 2014: Adopting Handoff on iOS and OS X
Debugging
Debugging mindset:
- Verify assumptions
- Look for clues (using tools)
- Test your hunches by implementing changes
Useful debugging methods:
-[UIView recursiveDescription]
-[UIView _parentDescription]
(to view everything above the view)
+[UIViewController _printHierarchy]
settings set target.language objective-c
to put debugger in Objective-C mode
Use LLDB for debugging state issues
expr
to run arbitrary code- See WWDC 2012 Debugging with LLDB and WWDC 2014 Advanced Swift Debugging in LLDB
dump
prints all of an object's propertiesexpr dump(card)
po [NSObject _ivarDescription]
Memory debugging:
- Enable malloc stack logging
- See WWDC 2017 Debugging with Xcode 9