Swift 3.0 面向协议开发解析

https://developer.apple.com/videos/play/wwdc2015/408/?time=2295

protocol Ordered {
    func precedes(other: Self) -> Bool
}

// Protocol 'Ordered' can only be used as a generic constraint 
// because it has Self or associated type requirements
func binarySearch(_ sortedKeys: [T], forKey k: T) -> Int {
    
    var lo = 0
    var hi = sortedKeys.count
    while hi > lo {
        let mid = lo + (hi - lo) / 2
        if sortedKeys[mid].precedes(other: k) { lo = mid + 1 }
        else { hi = mid }
    }
    return lo
}

extension Ordered where Self: Comparable {
    func precedes(other: Self) -> Bool {
        return self < other
    }
}

extension Int: Ordered { }
extension String: Ordered { }

let array = [1, 2, 3, 4, 5, 6, 7]
print(binarySearch(array, forKey: 4)) // 3

1.Ordered协议中precedes方法other的类型Self,这是一种Self-requirement 用法,Int类型遵守了Ordered协议,在调用precedes方法是,Self自动变为Int,String类型同理

2.使用Self-requirement 后,Ordered只能用于泛型约束

3.使用Self-requirement,模型在交互上自由性更高,静态分配,优化性更好

// 渲染 可以看做是一种能力
protocol Renderer {
    func moveTo(_ p: CGPoint)
    func lineTo(_ p: CGPoint)
    func arcAt(center: CGPoint, radius: CGFloat,
               startAngle: CGFloat, endAngle: CGFloat)
}

// CGContext遵守了Renderer协议,就拥有了描绘的能力,
extension CGContext : Renderer {
    func moveTo(_ p: CGPoint) {
        moveTo(p)
    }
    func lineTo(_ p: CGPoint) {
        addLine(to: p)
    }
    func arcAt(center: CGPoint, radius: CGFloat,
               startAngle: CGFloat, endAngle: CGFloat) {
        let arc = CGMutablePath()
        addArc(center: center, radius: radius, startAngle: startAngle, endAngle: endAngle, clockwise: true)
        self.addPath(arc)
    }
}

struct TestRenderer : Renderer {
    func moveTo(_ p: CGPoint) { print("moveTo(\(p.x), \(p.y))") }
    
    func lineTo(_ p: CGPoint) { print("lineTo(\(p.x), \(p.y))") }
    
    func arcAt(center: CGPoint, radius: CGFloat, startAngle: CGFloat, endAngle: CGFloat) {
        print("arcAt(\(center), radius: \(radius)," + " startAngle: \(startAngle), endAngle: \(endAngle))")
    }
}

// 比例渲染
struct ScaledRenderer: Renderer {
    let base: Renderer
    let scale: CGFloat
    
    func moveTo(_ p: CGPoint) {
        base.moveTo(CGPoint(x: p.x * scale, y: p.y * scale))
    }
    
    func lineTo(_ p: CGPoint) {
        base.lineTo(CGPoint(x: p.x * scale, y: p.y * scale))
    }
    
    func arcAt(center: CGPoint, radius: CGFloat, startAngle: CGFloat, endAngle: CGFloat) {
        // 拦截arcAt方法,修改center,调用base协议的方法
        let scaledCenter = CGPoint(x: center.x * scale, y: center.y * scale)
        base.arcAt(center: scaledCenter, radius: radius * scale, startAngle: startAngle, endAngle: endAngle)
    }
}

// 比例
struct Scaled : Drawable {
    var scale: CGFloat
    var subject: Base
    
    func draw(renderer: Renderer) {
        subject.draw(renderer: ScaledRenderer(base: renderer, scale: scale))
    }
}

// 绘画能力
protocol Drawable {
    func draw(renderer: Renderer)
}

// 多边形
struct Polygon : Drawable {
    var corners: [CGPoint] = []
    
    func draw(renderer: Renderer) {
        renderer.moveTo(corners.last!)
        for p in corners {
            renderer.lineTo(p)
        }
    }
}

// 圆形
struct Circle : Drawable {
    var center: CGPoint
    var radius: CGFloat
    
    func draw(renderer: Renderer) {
        renderer.arcAt(center: center, radius: radius,
                       startAngle: 0.0, endAngle: CGFloat(2 * M_PI))
    }
}

// 图表
struct Diagram : Drawable {
    var elements: [Drawable] = []
    func draw(renderer: Renderer) {
        for f in elements {
            f.draw(renderer: renderer)
        } }
    
}

------测试------
let circle = Circle(center:CGPoint(x: 187.5, y: 333.5),radius: 93.75)
let triangle = Polygon(corners: [CGPoint(x: 187.5, y: 427.25),CGPoint(x: 268.69, y: 286.625),CGPoint(x: 106.31, y: 286.625)])
var diagram = Diagram(elements: [circle, triangle])
diagram.elements.append(Scaled(scale: 0.3, subject: diagram))
diagram.draw(renderer: TestRenderer())
------输出------
arcAt((187.5, 333.5), radius: 93.75, startAngle: 0.0, endAngle: 6.28318530717959)
moveTo(106.31, 286.625)
lineTo(187.5, 427.25)
lineTo(268.69, 286.625)
lineTo(106.31, 286.625)
arcAt((56.25, 100.05), radius: 28.125, startAngle: 0.0, endAngle: 6.28318530717959)
moveTo(31.893, 85.9875)
lineTo(56.25, 128.175)
lineTo(80.607, 85.9875)
lineTo(31.893, 85.9875)

1️⃣.系统的CGContext类型可以通过协议扩展,拥有Renderer的能力,实现其中的方法,成为自己的方法。
2️⃣.struct Scaled : Drawable,首先Scaled结构体本身遵守了Drawable协议,因此可以实现draw方法,其次Base表示一种遵守Drawable协议的通用类型,var subject: Base,意思就是subject可以为任意类型,只要这个类型遵守了Drawable协议,就可以了。

3️⃣. Diagram的elements属性表示为一个遵守Drawable协议的数组,可以向数组中添加任意遵守Drawable协议的对象

补充1:
“The word static refers to things that happen at compile time and link time when the program is constructed—as opposed to load time or run time when the program is actually started.”

“The term dynamic refers to things that take place when a program is loaded and executed. ”

static dispatch 静态分配发生在程序的编译和链接的时候,

dynamic dispatch 动态分配发生在程序的加载和执行的时候

堆是动态分配的,栈既有动态分配又有静态分配,静态分配由编译器完成,动态分配由alloca进行分配,用完后马上就释放,无需程序员手动管理。
补充2:
关于self-requirement的资料
http://stackoverflow.com/questions/35270120/swift-overriding-self-requirement-is-allowed-but-causes-runtime-error-why

补充3:
generics 泛型

let animalAges: Array = [2,5,7,9]
let intNames: Dictionary = [42: "forty-two"]

此时animalAges的类型是Array,这就是一个泛型,表示一个数组,其中元素为Int类型。Array就是一种特殊的泛型,Array表示一个数组,其中元素为String类型。Dictionary也是一种特殊的泛型,Dictionary表示为一个字典,key类型为Int,value类型为String。
由于Swift自带类型推断,在声明属性的时候,省略了类型,上面数组推断为[Int],字典推断为[Int, String],但这不影响他们是一种特殊的泛型。

灵活使用泛型,可以使得代码简化,扩展性高。
例如,动物园中有很多种动物,每一种动物需要一个饲养员

class Cat {}
class Dog {}
class Keeper {} // 一个通用的饲养员类
let keeperCat = Keeper() // 创建了一个针对Cat的饲养员
let keeperDog = Keeper() // 创建了一个针对Dog的饲养员
// 在Keeper中添加各种方法,用Animal表示通用的类型,他会在在实际用的时候转化为Cat或者Dog类型
// 这样就可以添加更多种动物

泛型的用法还有很多,在代码中可以理解为一种类型站位符号或者一种类型约束符号。

你可能感兴趣的:(Swift 3.0 面向协议开发解析)