Flexible Code for
Generic Collections
Nate Cook @nnnnnnnn
Slide 2
Slide 2 text
The standard library
collections system
(Nate’s favorite part of Swift)
Slide 3
Slide 3 text
Protocols in
Objective-C
Slide 4
Slide 4 text
Protocols in
Swift
Slide 5
Slide 5 text
1. A problem
2.Why it happens
3.What to do about it
Slide 6
Slide 6 text
struct Brick {
let color: UIColor
let size: (w: Int, h: Int)
}
Slide 7
Slide 7 text
struct Brick {
let color: UIColor
let size: (w: Int, h: Int)
}
let redSquare = Brick(color: .red, size: (2, 2))
let orangeSquare = Brick(color: .orange, size: (2, 2))
Slide 8
Slide 8 text
struct Brick {
let color: UIColor
let size: (w: Int, h: Int)
}
let redSquare =
let orangeSquare =
Slide 9
Slide 9 text
struct Brick {
let color: UIColor
let size: (w: Int, h: Int)
}
let bricks = [ , , , , , , ]
Slide 10
Slide 10 text
func createBrickPDF(_ bricks: [Brick]) -> Data {
let result = NSMutableData()
// prepare PDF context
for brick in bricks {
// generate PDF data
}
return result as Data
}
Slide 11
Slide 11 text
let bricks = [ , , , , , , ]
let pdfData = createBrickPDF(bricks)
// Success!
Slide 12
Slide 12 text
!"#
Slide 13
Slide 13 text
let bricks = [ , , , , , , ]
let firstFiveBricks = bricks.prefix(5)
Slide 14
Slide 14 text
let bricks = [ , , , , , , ]
let firstFiveBricks = bricks.prefix(5)
Wow
such swift
so declarativ
wow
Slide 15
Slide 15 text
let bricks = [ , , , , , , ]
let firstFiveBricks = bricks.prefix(5)
let pdfData = createBrickPDF(firstFiveBricks)
Cannot convert value of type ‘ArraySlice’ to expected argument type ‘[Brick]’
!
Slide 16
Slide 16 text
$%&
Slide 17
Slide 17 text
let bricks = [ , , , , , , ]
let firstFiveBricks = bricks.prefix(5)
let pdfData = createBrickPDF(firstFiveBricks)
Cannot convert value of type ‘ArraySlice’ to expected argument type ‘[Brick]’
!
Slide 18
Slide 18 text
, , , , , ]
ks = bricks.prefix(5)
ateBrickPDF(firstFiveBricks)
convert value of type ‘ArraySlice’ to expected argum
Slide 19
Slide 19 text
DF(firstFiveBrick
type ‘ArraySlice’ to exp
Slide 20
Slide 20 text
(˽°□°)˽
Ɨ ʇɟıʍs
Slide 21
Slide 21 text
let bricks = [ , , , , , , ]
let firstFiveBricks = bricks.prefix(5)
let pdfData = createBrickPDF(firstFiveBricks)
Cannot convert value of type ‘ArraySlice’ to expected argument type ‘[Brick]’
!
Slide 22
Slide 22 text
let bricks = [ , , , , , , ]
let firstFiveBricks = bricks.prefix(5)
let pdfData = createBrickPDF(Array(firstFiveBricks))
Slide 23
Slide 23 text
let bricks = [ , , , , , , ]
let firstFiveBricks = bricks.prefix(5)
let pdfData = createBrickPDF(Array(firstFiveBricks))
// '☕
Slide 24
Slide 24 text
1. A problem
2.Why it happens
3.What to do about it
Slide 25
Slide 25 text
let middleBricks = bricks[2..<5]
// ArraySlice
let lastThreeBricks = bricks.suffix(3)
// ArraySlice
let bricksAfterFirstTwo = bricks.dropFirst(2)
// ArraySlice
Iterator of a sequence
for brick in bricks {
print(brick)
}
// , , , , , ,
Slide 48
Slide 48 text
Iterator of a sequence
for brick in bricks {
print(brick)
}
// , , , , , ,
var iterator = bricks.makeIterator()
while let brick = iterator.next() {
print(brick)
}
// , , , , , ,
Slide 49
Slide 49 text
func createBrickPDF(_ bricks: [Brick]) -> Data {
let result = NSMutableData()
// prepare PDF context
for brick in bricks {
// generate PDF data
}
return result as Data
}
Slide 50
Slide 50 text
func createBrickPDF(_ bricks: [Brick]) -> Data {
let result = NSMutableData()
// prepare PDF context
for brick in bricks {
// generate PDF data
}
return result as Data
}
Slide 51
Slide 51 text
func createBrickPDF(_ bricks: S) -> Data
where S.Iterator.Element == Brick
{
let result = NSMutableData()
// prepare PDF context
for brick in bricks {
// generate PDF data
}
return result as Data
}
Slide 52
Slide 52 text
func createBrickPDF(_ bricks: S) -> Data
where S.Iterator.Element == Brick
{
let result = NSMutableData()
// prepare PDF context
for brick in bricks {
// generate PDF data
}
return result as Data
}
Slide 53
Slide 53 text
func createBrickPDF(_ bricks: S) -> Data
where S.Iterator.Element == Brick
{
let result = NSMutableData()
// prepare PDF context
for brick in bricks {
// generate PDF data
}
return result as Data
}
Slide 54
Slide 54 text
Value of type ’S’ has no member ‘count’
!
func createBrickPDF(_ bricks: S) -> Data
where S.Iterator.Element == Brick
{
let result = NSMutableData()
// prepare PDF context
let renderer = BrickPDFRenderer(count: bricks.count)
for brick in bricks {
// generate PDF data
}
return result as Data
}
Slide 55
Slide 55 text
func createBrickPDF(_ bricks: C) -> Data
where C.Iterator.Element == Brick
{
let result = NSMutableData()
// prepare PDF context
let renderer = BrickPDFRenderer(count: bricks.count)
for brick in bricks {
// generate PDF data
}
return result as Data
}
Slide 56
Slide 56 text
func createBrickPDF(_ bricks: S) -> Data
where S.Iterator.Element == Brick
{ ... }
let bricks = [ , , , , , , ]
let firstFiveBricks = bricks.prefix(5)
let pdfData = createBrickPDF(firstFiveBricks)
// Success!!
Slide 57
Slide 57 text
!"#❤*✨!"
❤*✨!"#❤*
✨!"#❤*✨!
"#❤*✨!"#
Slide 58
Slide 58 text
Storing generic
collections
Slide 59
Slide 59 text
Generic type
class BrickRenderer
where C.Iterator.Element == Brick
{
let bricks: C
init(_ bricks: C) {
self.bricks = bricks
}
}
Slide 60
Slide 60 text
Type erasure
class BrickRenderer {
let bricks: AnyCollection
init(_ bricks: AnyCollection) {
self.bricks = bricks
}
}
Slide 61
Slide 61 text
Type erasure
class BrickRenderer {
let bricks: AnyCollection
init(_ bricks: AnyCollection) {
self.bricks = bricks
}
}
let renderer = BrickRenderer(AnyCollection(bricks))
let renderer =
BrickRenderer(AnyCollection(firstFiveBricks))
Slide 62
Slide 62 text
Type-specific
extensions
Slide 63
Slide 63 text
extension Array where Element == Bool {
func allTrue() -> Bool {
for x in self {
if !x {
return false
}
}
return true
}
}
Slide 64
Slide 64 text
extension Array where Element == Bool {
func allTrue() -> Bool {
for x in self {
if !x {
return false
}
}
return true
}
}
Same-type requirement makes generic parameter 'Element' non-generic
!
Slide 65
Slide 65 text
extension Sequence where Iterator.Element == Bool {
func allTrue() -> Bool {
for x in self {
if !x {
return false
}
}
return true
}
}
Slide 66
Slide 66 text
Syntax & Naming
Slide 67
Slide 67 text
func createBrickPDF(_ bricks: S) -> Data
where S.Iterator.Element == Brick
Swift 3
func createBrickPDF
(_ bricks: S) -> NSData
Swift 2