+ All Categories
Home > Software > Pragmatic Swift

Pragmatic Swift

Date post: 13-Apr-2017
Category:
Upload: kenneth-blake-merryman
View: 162 times
Download: 0 times
Share this document with a friend
28
Pragmatic Swift Blake Merryman
Transcript
Page 1: Pragmatic Swift

Pragmatic SwiftBlake Merryman

Page 2: Pragmatic Swift

A collection of "use everyday" tips & tricks to help keep your code base

maintainable, understandable, & extendable.

Page 3: Pragmatic Swift

Covered tonight…Documentation

Organization

Striving for Smallness

Access Control

Early Exits

Collection-Type APIs

Property Initialization

Lazy Loading

Lazy Sequences

Slow Build Times

Page 4: Pragmatic Swift

DocumentationSave valuable time when ⌥ + clicking around

Easily write rich Quick Help docs in Markdown

Add quick notes to function, variable, etc.: /// Important (but brief) QH note.

Auto-document functions:  ⌘ + ⌥ + /

Page 5: Pragmatic Swift

Documentation

Useful comments…

// TODO: *** Shows in Jump Bar *** // NOTE: Something important!

Integrate these into build systems with scripts or special tools (e.g. swiftlint)

Page 6: Pragmatic Swift

Documentation

// Forces Xcode to flag a warning at compile time // Source: http://stackoverflow.com/a/26869489/1418335 // Disclaimer: Not tested; I use swiftlint :) if [ "${CONFIGURATION}" = "Debug" ]; then TAGS=“TODO:|FIXME:" echo "searching ${SRCROOT} for ${TAGS}" find "${SRCROOT}" \( -name "*.swift" \) -print0 | xargs -0 egrep \ --with-filename \ --line-number \ --only-matching "($TAGS).*\$" \ | perl -p -e "s/($TAGS)/ warning: \$1/" fi

Page 7: Pragmatic Swift

OrganizationA well organized project can save hours of time

Files are Free!

Group according to large ideas

Extensions are great for grouping functionality:

// MARK: - Private Helpers extension MyViewController { /***/ }

// MARK: - + UICollectionViewDataSource extension MyViewController: UICollectionViewDataSource { /***/ }

Page 8: Pragmatic Swift

Strive for Smallness

Being small at scope improves understanding

Take advantage of typed parameters:

func configure(_ cell: MyCollectionViewCell, at indexPath: IndexPath) func configure(_ cell: YourCollectionViewCell, at indexPath: IndexPath) func configure(_ cell: TheirCollectionViewCell, at indexPath: IndexPath)

Page 9: Pragmatic Swift

Strive for Smallness

How else can we keep things small? Extensions, Data Sources, Network Stacks, Inheritance, Composition, Rich Enums, Generics, Access Control

Page 10: Pragmatic Swift

Access ControlWhat is need to know and Who needs to know it?

Access Control dictates how an API is viewed

Levels: private, fileprivate, internal, public, open

Tips: - Use private to hide extension helpers - Use fileprivate to hide extensions

Page 11: Pragmatic Swift

Access Control

Page 12: Pragmatic Swift

Early Exits

Help prevent nesting

Important validation logic is up front

Clearly indicates success/failure

Prefer “guard” over “if”

Page 13: Pragmatic Swift

Early Exits // Not Preferred if let a = optionalA, a.someBoolean == true { // Do GOOD thing :) } else { // Do BAD thing :( }

// Preferred guard let a = optionalA, a.someBoolean == true else { // Do Bad thing :( return } // Do GOOD thing! :D

Page 14: Pragmatic Swift

Collection-Type APIs

Take advantage of new closure-based APIs to keep logic tight & readable

Chainable to allow for building complex logic fast

Great reference implementation for using Protocols (with default implementations) + Generics

Page 15: Pragmatic Swift

Collection-Type APIsvar numbers = [Int]() numbers += 1...1_000

var oddNumbers = [Int]() for x in numbers { if x % 2 != 0 { oddNumbers.append(x) } }

var multNumbers = [Int]() for x in oddNumbers { let x10 = x * 10 multNumbers.append(x10) }

for x in multNumbers { print(x) }

// Prints: 10, 30, 50, ..., 9950, 9970, 9990

Page 16: Pragmatic Swift

Collection-Type APIs

var numbers = [Int]() numbers += 1...1_000

numbers.filter { $0 % 2 != 0 } // Grab all of the odd numbers .map { $0 * 10 } // Multiply by 10 .forEach { print($0) } // Print out new values

// Prints: 10, 30, 50, ..., 9950, 9970, 9990

Page 17: Pragmatic Swift

Property Initializationclass MyViewController: UIViewController {

var collectionView: UICollectionView?

override func viewDidLoad() { super.viewDidLoad()

let flowLayout = UICollectionViewFlowLayout() flowLayout.scrollDirection = .horizontal collectionView = UICollectionView(frame: .zero, collectionViewLayout: flowLayout) collectionView?.translatesAutoresizingMaskIntoConstraints = false collectionView?.isPagingEnabled = true collectionView?.backgroundColor = .clear collectionView?.showsHorizontalScrollIndicator = false

view.addSubview(collectionView!) // Auto Layout Code ... } }

Page 18: Pragmatic Swift

Property Initializationclass MyViewController: UIViewController {

let collectionView: UICollectionView = { let flowLayout = UICollectionViewFlowLayout() flowLayout.scrollDirection = .horizontal let collectionView = UICollectionView(frame: .zero, collectionViewLayout: flowLayout) collectionView.translatesAutoresizingMaskIntoConstraints = false collectionView.isPagingEnabled = true collectionView.backgroundColor = .clear collectionView.showsHorizontalScrollIndicator = false return collectionView }()

// MARK: - Lifecycle

override func viewDidLoad() { super.viewDidLoad()

view.addSubview(collectionView) // Auto Layout Code ... } }

Page 19: Pragmatic Swift

Lazy Loading

Initialize at access rather than init

class MyViewController: UIViewController {

lazy var collectionView = UICollectionView.configuredCollectionView()

// MARK: - Lifecycle override func viewDidLoad() { super.viewDidLoad() view.addSubview(collectionView) // Auto Layout Code ... } }

Page 20: Pragmatic Swift

Lazy Loading

ProTip: Limit the scope of setter with Access Control

class MyViewController: UIViewController {

private(set) lazy var collectionView = UICollectionView.configuredCollectionView()

// MARK: - Lifecycle override func viewDidLoad() { super.viewDidLoad() view.addSubview(collectionView) // Auto Layout Code ... } }

Page 21: Pragmatic Swift

Lazy Loading

Constants declared at global scope & statically are lazy by default. Does not apply to constants declared at instance scope.

Page 22: Pragmatic Swift

Lazy Sequences

lazy property on SequenceType & CollectionType

Lazily access elements in sequences/collections

Huge performance benefit!

Easy to implement…

Page 23: Pragmatic Swift

Lazy Sequences

var numbers = [Int]() numbers += 1...1_000

let newNumbers = numbers .filter { $0 % 2 != 0 } // Executed 1,000 times .map { $0 * 10 } // Executed 500 times

newNumbers.last

All calculations completed before access!

Page 24: Pragmatic Swift

Lazy Sequences

var numbers = [Int]() numbers += 1...1_000

let newNumbers = numbers.lazy .filter { $0 % 2 != 0 } // Executed 1 time .map { $0 * 10 } // Executed 1 time

newNumbers.last

Calculations performed as needed on access!

Page 25: Pragmatic Swift

Slow Build Times

Sometimes Swift build times are slow (**cough** type inference **cough**)

Setting to add build times to logs: - Project Settings > Build Settings > Other Swift Flags - Add -Xfrontend -debug-time-function-bodies - “Expand All Transcripts” (look for new XX ms)

Page 26: Pragmatic Swift

Slow Build Times

Pro Tip: Prioritize build time optimizations:

“Copy transcripts for shown results” for logs then in Terminal, run: pbpaste | egrep '\.[0-9]ms' | sort -t "." -k 1 -n | tail -10

Highlights the top 10 build time hogs in project

Page 27: Pragmatic Swift

Q & A

Page 28: Pragmatic Swift

Sourceshttps://developer.apple.com/reference/swift

http://stackoverflow.com/a/26869489/1418335

https://thatthinginswift.com/kill-your-viewdidload/

http://alisoftware.github.io/swift/2016/02/28/being-lazy/

https://thatthinginswift.com/debug-long-compile-times-swift/

https://twitter.com/erikaderstedt/status/725217977314992128


Recommended