Ios开发swift

Swift4 基础部分: Protocols(协议)

2017-12-09  本文已影响94人  Arnold134777

本文是学习《The Swift Programming Language》整理的相关随笔,基本的语法不作介绍,主要介绍Swift中的一些特性或者与OC差异点。

系列文章:

Protocol Syntax(协议语法)

struct SomeStructure: FirstProtocol, AnotherProtocol {
    // structure definition goes here
}

// 如果是存在继承关系,父类放在第
class SomeClass: SomeSuperclass, FirstProtocol, AnotherProtocol {
    // class definition goes here
}

Property Requirements(属性要求)

Property requirements are always declared as variable 
properties, prefixed with the var keyword. Gettable and 
settable properties are indicated by writing { get set } 
after their type declaration, and gettable properties are 
indicated by writing { get }.

例子:

protocol SomeProtocol {
    var mustBeSettable: Int { get set }
    var doesNotNeedToBeSettable: Int { get }
}

完整例子:

protocol FullyNamed {
    var fullName:String {get}
}

class Starship:FullyNamed {
    var prefix: String?;
    var name:String;
    init(name:String, prefix:String? = nil){
        self.name = name;
        self.prefix = prefix;
    }
    
    var fullName: String{
        return (prefix != nil ? prefix! + " " : "") + name;
    }
}

var ncc1701 = Starship(name:"Enterprise", prefix:"USS");
print("\(ncc1701.fullName)");

执行结果:

USS Enterprise

Method Requirements(方法要求)

协议支持类方法与实例方法。

例子:

protocol RandomNumberGenerator {
    static func factor() -> Double;
    func random() -> Double;
}

class LinearCongruentialGenerator: RandomNumberGenerator {
    var lastRandom = 42.0;
    let m = 139968.0;
    let a = 3877.0;
    let c = 29573.0;
    
    static func factor() -> Double {
        return 0.5;
    }
    
    func random() -> Double {
        lastRandom = ((lastRandom * a + c).truncatingRemainder(dividingBy:m));
        return lastRandom / m * LinearCongruentialGenerator.factor();
    }
}

let generator = LinearCongruentialGenerator();
print("Here's a random number: \(generator.random())");

执行结果:

Here's a random number: 0.187324959990855

Mutating Method Requirements(Mutating 方法要求)

针对枚举或者结构体中的方法需要修改其中的实例时。

例子:

protocol Togglable {
    mutating func toggle();
}

enum OnOffSwitch:Togglable {
    case off, on
    mutating func toggle() {
        switch self {
        case .off:
            self = .on;
        case .on:
            self = .off;
        }
    }
}

var lightSwitch = OnOffSwitch.off;
lightSwitch.toggle();

Initializer Requirements (构造器要求)

You can implement a protocol initializer requirement on a conforming 
class as either a designated initializer or a convenience 
initializer. In both cases, you must mark the initializer 
implementation with the required modifier.

例子:

protocol SomeProtocol {
    init(someParameter:Int);
}

class SomeClass :SomeProtocol {
    init(someParameter: Int) {
        
    }
}

报错信息:


error: SwfitStudy.playground:436:5: error: initializer requirement 'init(someParameter:)' can only be satisfied by a `required` initializer in non-final class 'SomeClass'
    init(someParameter: Int) {
    ^
    required 

正确处理:

protocol SomeProtocol {
    init(someParameter:Int);
}

class SomeClass :SomeProtocol {
    required init(someParameter: Int) {
        
    }
}
If a subclass overrides a designated initializer from a superclass, 
and also implements a matching initializer requirement from a 
protocol, mark the initializer implementation with both the required 
and override modifiers

例子:

protocol SomeProtocol {
    init();
}

class SomeSuperClass {
    init() {
        
    }
}

class SomeSubClass:SomeSuperClass,SomeProtocol {
    required override init() {
        
    }
}

Protocols as Types(协议作为类型)

与OC中类似,不展开说明。

例子:

protocol RandomNumberGenerator {
    static func factor() -> Double;
    func random() -> Double;
}

class LinearCongruentialGenerator: RandomNumberGenerator {
    var lastRandom = 42.0;
    let m = 139968.0;
    let a = 3877.0;
    let c = 29573.0;
    
    static func factor() -> Double {
        return 0.5;
    }
    
    func random() -> Double {
        lastRandom = ((lastRandom * a + c).truncatingRemainder(dividingBy:m));
        return lastRandom / m * LinearCongruentialGenerator.factor();
    }
}

class Dice {
    let sides:Int;
    let generator:RandomNumberGenerator;
    
    init(sides: Int, generator: RandomNumberGenerator) {
        self.sides = sides;
        self.generator = generator;
    }
    
    func roll() -> Int {
        return Int(generator.random() * Double(sides)) + 1;
    }
}

var d6 = Dice(sides: 6, generator: LinearCongruentialGenerator())
for _ in 1...5 {
    print("Random dice roll is \(d6.roll())");
}

执行结果:

Random dice roll is 2
Random dice roll is 3
Random dice roll is 2
Random dice roll is 3
Random dice roll is 2

Delegation (代理)

代理与OC中的类似,不展开说明。

例子:

protocol DiceGame {
    var dice: Dice { get }
    func play();
}
protocol DiceGameDelegate {
    func gameDidStart(_ game: DiceGame);
    func game(_ game: DiceGame, didStartNewTurnWithDiceRoll diceRoll: Int);
    func gameDidEnd(_ game: DiceGame);
}

class SnakesAndLadders: DiceGame {
    let finalSquare = 25;
    let dice = Dice(sides: 6, generator: LinearCongruentialGenerator());
    var square = 0;
    var board: [Int];
    init() {
        board = Array(repeating: 0, count: finalSquare + 1);
        board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02;
        board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08;
    }
    var delegate: DiceGameDelegate?;
    func play() {
        square = 0;
        delegate?.gameDidStart(self);
        gameLoop: while square != finalSquare {
            let diceRoll = dice.roll();
            delegate?.game(self, didStartNewTurnWithDiceRoll: diceRoll);
            switch square + diceRoll {
            case finalSquare:
                break gameLoop;
            case let newSquare where newSquare > finalSquare:
                continue gameLoop;
            default:
                square += diceRoll;
                square += board[square];
            }
        }
        delegate?.gameDidEnd(self);
    }
}

class DiceGameTracker: DiceGameDelegate {
    var numberOfTurns = 0;
    func gameDidStart(_ game: DiceGame) {
        numberOfTurns = 0;
        if game is SnakesAndLadders {
            print("Started a new game of Snakes and Ladders");
        }
        print("The game is using a \(game.dice.sides)-sided dice");
    }
    func game(_ game: DiceGame, didStartNewTurnWithDiceRoll diceRoll: Int) {
        numberOfTurns += 1;
        print("Rolled a \(diceRoll)");
    }
    func gameDidEnd(_ game: DiceGame) {
        print("The game lasted for \(numberOfTurns) turns");
    }
}

let tracker = DiceGameTracker();
let game = SnakesAndLadders();
game.delegate = tracker;
game.play();

执行结果:

Started a new game of Snakes and Ladders
The game is using a 6-sided dice
Rolled a 2
Rolled a 3
Rolled a 2
Rolled a 3
Rolled a 2
Rolled a 1
Rolled a 2
Rolled a 1
Rolled a 1
Rolled a 2
Rolled a 1
Rolled a 3
Rolled a 2
Rolled a 1
Rolled a 2
Rolled a 1
Rolled a 3
Rolled a 2
Rolled a 2
Rolled a 3
Rolled a 2
The game lasted for 21 turns

Adding Protocol Conformance with an Extension (通过扩展添加协议一致性)

You can extend an existing type to adopt and conform to a new 
protocol, even if you do not have access to the source code for the 
existing type. 

例子:

protocol TextRepresentable {
    var textualDescription: String { get }
}

extension Dice: TextRepresentable {
    var textualDescription: String {
        return "A \(sides)-sided dice";
    }
}

let d12 = Dice(sides: 12, generator: LinearCongruentialGenerator());
print(d12.textualDescription);

执行结果:

A 12-sided dice

Declaring Protocol Adoption with an Extension(通过扩展遵循协议)

If a type already conforms to all of the requirements of a protocol, 
but has not yet stated that it adopts that protocol, you can make it 
adopt the protocol with an empty extension.

例子:

struct Hamster {
    var name: String;
    var textualDescription: String {
        return "A hamster named \(name)";
    }
}
extension Hamster: TextRepresentable {}

let simonTheHamster = Hamster(name: "Simon");
let somethingTextRepresentable: TextRepresentable = simonTheHamster;
print(somethingTextRepresentable.textualDescription);

执行结果:

A hamster named Simon

Collections of Protocol Types(协议类型的集合) 与 Protocol Inheritance(协议继承)

与OC中类似,不扩展。

Class-Only Protocols(类类型协议)

You can limit protocol adoption to class types (and not structures 
or enumerations) by adding the AnyObject protocol to a protocol’s 
inheritance list.
protocol SomeClassOnlyProtocol: AnyObject, SomeInheritedProtocol {
    // class-only protocol definition goes here
}

Protocol Composition (协议合成)

It can be useful to require a type to conform to multiple protocols 
at once. You can combine multiple protocols into a single 
requirement with a protocol composition. Protocol compositions 
behave like you defined a temporary local protocol that has the 
combined requirements of all protocols in the composition. Protocol 
compositions don’t define any new protocol types.

Protocol compositions have the form SomeProtocol & AnotherProtocol. 
You can list as many protocols as you need to, separating them by 
ampersands (&). In addition to its list of protocols, a protocol 
composition can also contain one class type, which lets you specify a required superclass.

例子:

protocol Named {
    var name:String {get}
}

protocol Aged {
    var age:Int {get}
}

struct Person:Named,Aged {
    var name:String;
    var age:Int;
}

func wishHappyBirthday(to celebrator:Named & Aged) {
    print("Happy birthday, \(celebrator.name), you're \(celebrator.age)!")
}

let birthdayPerson = Person(name:"Malcolm", age:21);
wishHappyBirthday(to: birthdayPerson);

执行结果:

Happy birthday, Malcolm, you're 21!

Checking for Protocol Conformance (检查协议一致性)

You can use the is and as operators described in Type Casting to 
check for protocol conformance, and to cast to a specific protocol. 

OC中则是利用如下的方式,以下两者都可以:

+ (BOOL)conformsToProtocol:(Protocol *)protocol;
- (BOOL)conformsToProtocol:(Protocol *)protocol;

例子:

protocol HasArea {
    var area: Double {get}
}

class Circle:HasArea {
    let pi = 3.1415927;
    var radius:Double;
    var area: Double {
        return pi * radius * radius;
    }
    init(radius:Double) {
        self.radius = radius;
    }
}

class Country:HasArea {
    var area:Double;
    init(area:Double) {
        self.area = area;
    }
}

class Animal {
    var legs:Int;
    init(legs:Int) {
        self.legs = legs;
    }
}

let objects:[AnyObject] = [
    Circle(radius:2.0),
    Country(area:243_610),
    Animal(legs:4)
];

for object in objects {
    if object is HasArea {
        let objectWithArea = object as? HasArea;
        print("Area is \(objectWithArea?.area)");
    }else{
        print("Something that doesn't have an area");
    }
}

执行结果:

Area is 12.5663708
Area is 243610.0
Something that doesn't have an area

Optional Protocol Re quirements(可选的协议要求)

You can define optional requirements for protocols, These 
requirements do not have to be implemented by types that conform to 
the protocol. Optional requirements are prefixed by the optional 
modifier as part of the protocol’s definition. Optional requirements 
are available so that you can write code that interoperates with 
Objective-C. Both the protocol and the optional requirement must be 
marked with the @objc attribute. 

例子:

import Foundation

@objc protocol CounterDataSource {
    @objc optional func increment(forCount count: Int) -> Int;
    @objc optional var fixedIncrement: Int { get }
}

class Counter {
    var count = 0;
    var dataSource: CounterDataSource?;
    func increment() {
        if let amount = dataSource?.increment?(forCount: count) {
            count += amount;
        } else if let amount = dataSource?.fixedIncrement {
            count += amount;
        }
    }
}


var counter = Counter();
class TowardsZeroSource:CounterDataSource {
    func increment(forCount count: Int) -> Int {
        if count == 0 {
            return 0;
        } else if count < 0 {
            return 1;
        } else {
            return -1;
        }
    }
}

counter.count = -4;
counter.dataSource = TowardsZeroSource();
for _ in 1...5 {
    counter.increment();
    print(counter.count);
}

执行结果:

-3
-2
-1
0
0

Protocol Extensions (协议扩展)

Protocols can be extended to provide method and property 
implementations to conforming types.

例子:

protocol RandomNumberGenerator {
    static func factor() -> Double;
    func random() -> Double;
}

extension RandomNumberGenerator {
    func randomBool() -> Bool {
        return random() > 0.5
    }
}

class LinearCongruentialGenerator: RandomNumberGenerator {
    var lastRandom = 42.0;
    let m = 139968.0;
    let a = 3877.0;
    let c = 29573.0;

    static func factor() -> Double {
        return 0.5;
    }

    func random() -> Double {
        lastRandom = ((lastRandom * a + c).truncatingRemainder(dividingBy:m));
        return lastRandom / m * LinearCongruentialGenerator.factor();
    }
}


let generator = LinearCongruentialGenerator();
print("Here's a random number: \(generator.random())");
print("And here's a random Boolean: \(generator.randomBool())");

执行结果:

Here's a random number: 0.187324959990855
And here's a random Boolean: false

Providing Default Implementations(提供默认的实现)

You can use protocol extensions to provide a default implementation 
to any method or computed property requirement of that protocol.

例子:

protocol RandomNumberGenerator {
    static func factor() -> Double;
    func random() -> Double;
}

extension RandomNumberGenerator {
    func randomBool() -> Bool {
        return random() > 0.5
    }
    
    // 默认的实现
    static func factor() -> Double {
        return 0.5;
    }
}

class LinearCongruentialGenerator: RandomNumberGenerator {
    var lastRandom = 42.0;
    let m = 139968.0;
    let a = 3877.0;
    let c = 29573.0;

    func random() -> Double {
        lastRandom = ((lastRandom * a + c).truncatingRemainder(dividingBy:m));
        return lastRandom / m * LinearCongruentialGenerator.factor();
    }
}


let generator = LinearCongruentialGenerator();
print("Here's a random number: \(generator.random())");
print("And here's a random Boolean: \(generator.randomBool())");

执行结果:

Here's a random number: 0.187324959990855
And here's a random Boolean: false

Adding Constraints to Protocol Extensions (为协议扩展添加限制条件)

例子:


struct Hamster {
    var name: String;
    var textualDescription: String {
        return "A hamster named \(name)";
    }
}

protocol TextRepresentable {
    var textualDescription: String { get }
}

extension Hamster: TextRepresentable {}

extension Collection where Iterator.Element: TextRepresentable {
    var textualDescription: String {
        let itemsAsText = self.map { $0.textualDescription }
        return "[" + itemsAsText.joined(separator: ", ") + "]"
    }
}

let murrayTheHamster = Hamster(name: "Murray");
let morganTheHamster = Hamster(name: "Morgan");
let mauriceTheHamster = Hamster(name: "Maurice");
let hamsters = [murrayTheHamster, morganTheHamster, mauriceTheHamster];
print(hamsters.textualDescription)

执行结果:

[A hamster named Murray, A hamster named Morgan, A hamster named Maurice]
上一篇下一篇

猜你喜欢

热点阅读