Swift in Practice
Description: Learn how Swift can help you define away some common pitfalls in app development, allowing your apps to benefit from safer runtime behavior while enjoying strong guarantees provided by Swift at compile-time. Hear about how API availability checking in Swift allows you to easily take advantage of new APIs while guaranteeing safe deployment to earlier OS releases. See how enumerations and protocols can help not only maintain compile-time invariants between your app's code and assets but also reduce boilerplate.
Take advantage of new APIs while deploying to older OS releases
Problem: Users on different OS releases
Solution: Adopt new features and support the older OS releases - Always use the Latest SDK to access complete set of APIs - Use Deployment Target to set an application's minimum supported OS release
- Manually check Framework, Class, etc.
- Framework: manually check framework as optional
- Class: manually check if a method/function available.
- Compile-Time API Availability Checking.
Enforce expected application behavior using enums and protocols
Use Case: Asset Catalog Identifiers
extension UIImage {
enum AssetIdentifier: String {
case isabella = "Isabella"
case william = "William"
case Olivia = "Olivia"
}
convenience init!(assertIdentifier: AssetIdentifier) {
self.init(named: assertIdentifier.rawValue)
}
}
- Centrally located constants
- Doesn't pollute global namespace
- Must use one of the enum cases
- Image initialization are not failable
Use Case: Segue Identifiers
class ViewController: UIViewController {
enum SegueIdentifier: String {
case ShowImportUnicorn = "ShowImportUnicorn"
case ShowCreateNewUnicore = "Show CreateNewUnicorn"
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
guard let identifier = segue.identifier, segueIdentifier = SegueIdentifier(rawValue: identifier)
else { fatalError("Invalid segue identifier \(segue.identifier).")}
switch segueIdentifier {
case .ShowImportUnicorn: // Config...
case .ShowCreateUnicor: // Config...
}
}
}
When new case added to enum, then the compiler will tell us switch is not exhausted.
class ViewController: UIViewController {
func performSegueWithIdentifier(segueIdentifier: SegueIdentifier, sender: AnyObject?) {
performSegueWithIdentifier(segueIdentifier.rawValue, sender: sender)
}
}
To avoid duplicate all of the smart solution showed above, use Protocol
protocol SegueHandlerType {
typealias SegueIdentifier: RawRepresentable
}
// Shared Implementation.
extension SegueHandlerType where Self: UIViewController, SegueIdentifier.RawValue == String {
func segueIdentifier(for segue: UIStoryboardSegue) -> SegueIdentifier {
guard let identifier = segue.identifier,
let segueIdentifier = SegueIdentifier(rawValue: identifier)
else { fatalError("Unknown segue: \(segue))") }
return segueIdentifier
}
func performSegueWithIdentifier(segueIdentifier: SegueIdentifier, sender: AnyObject?) {
performSegueWithIdentifier(segueIdentifier.rawValue, sender: sender)
}
}
class ViewController: UIViewController, SegueHandlerType {
enum SegueIdentifier: String {
// ...
}
}
This note was originally published at github.com/antonio081014/WWDC_Learning_Review.