swift協議

/**

1.協議的語法

2.屬性要求

3.方法要求

4.突變方法要求

5.協議類型

6.委託代理模式

7.在擴展中添加協議成員

8.通過延展補充協議聲明

9.集合中的協議類型

10.協議的繼承

11.協議合成

12.檢驗協議的一致性

13.可選協議要求

Protocol(協議)用於統一方法和屬性的名稱,而不實現任何功能。協議能夠被類、枚舉、結構體實現,滿足協議要求的類,枚舉,結構體被稱爲協議的遵循者

遵循者需要提供協議指定的成員,如屬性,方法,操作符,下標等

*/



//協議語法

/**

協議的定義與類、結構體、枚舉的定義非常相似

protocol SomeProtocol { 

    // 協議內容

}

在類,結構體,枚舉的名稱後加上協議名稱,中間以冒號(:)分隔即可實現協議;實現多個協議是,各協議之間用逗號(,)分隔

struct SomeStructure: FirstProtocol, AnotherProtocol

{

    // 結構體內容

}

當某個類含有父類的同時並實現了協議,應當把父類放在所有的協議之前

class SomeClass: SomeSuperClass, FirstProtocol,

AnotherProtocol {

    // 類的內容

}

*/



//屬性要求

/**

協議能夠要求其遵循者必須含有一些特定名稱和類型的實例屬性(instance property)或類屬性(type property),也能夠要求屬性的(設置權限)settable(訪問權限)gettable,但它不要求屬性是存儲型屬性(stored property)還是計算屬性(calculate property)

通常前置var關鍵字將屬性聲明爲變量。在屬性聲明後寫上{get set}表示屬性爲可讀寫的。{get}用來表示屬性爲可讀的。即使你爲可讀屬性實現了setter方法,它也不會出錯

protocol SomeProtocol {

    var musBeSettable : Int { get set }

    var doesNotNeedToBeSettable: Int { get }

}

用類來實現協議時,使用class關鍵字來表示該屬性爲類成員,用結構體或枚舉實現協議時,則使用static關鍵字來表示

protocol AnotherProtocol {

    class var someTypeProperty: Int { get set }

}

*/

protocol FullyNamed {

    var fullName: String { get };

}

struct Person: FullyNamed {

    var fullName: String;

}

let john = Person(fullName: "john mike");

/**

FullyNamed協議含有fullName屬性,因此其遵循者必須有一個名爲fullName,類型爲String的可讀屬性

*/

print(john.fullName);



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");

/**

Starship類將fullName實現爲可讀的計算型屬性。它的每一個實例都有一個名爲name的必備屬性和一個名爲prefix的可選屬性。當prefix存在時,將prefix插入到name之前來爲Starship構建fullName

*/

print(ncc1701.fullName);



//方法要求

/**

協議能夠要求其遵循着必備某些特定的實例方法和類方法。協議方法的聲明與普通方法聲明相似,但它不需要方法內容

協議方法支持變長參數(variadic parameter),不支持默認參數(default parameter)

前置class關鍵字表示協議中的成員爲類成員,當協議用於被枚舉或結構體遵循時,則使用static關鍵字

protocol SomeProtocol {

    class func someTypeMethod()

}

*/

protocol RandomNumberGenerator {

    func random() -> Double;

}

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) % m);

        return lastRandom / m;

    }

}

let generator = LinearCongruentialGenerator();

print(generator.random());

print(generator.random());



//突變方法要求

/**

能在方法或函數內部改變實例類型的方法稱爲突變方法。在值類型中的函數前綴加上mutating關鍵字來表示該函數允許改變該實例和其屬性的類型。

類中的成員爲引用類型,可以方便修改實例及其屬性的值而無需改變類型,而結構體和枚舉中的成員爲值類型,修改變量的值就相當於修改變量的類型,而swift默認不允許修改類型,因此需要前置mutating關鍵字用來表示該函數中能夠修改類型

class實現協議中的mutating方法時,不用寫mutating關鍵字,用結構體,枚舉實現協議中的mutating方法時,必須寫mnutating關鍵字

*/

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();

print(lightSwitch.hashValue);



//協議類型

/**

協議本身不實現任何功能,但可以將它當做類型來使用

    1.作爲函數,方法或構造器中的參數類型,返回值類型

    2.作爲常量,變量,屬性的類型

    3.作爲數組,字典或其他容器中的元素類型

協議類型應與其他類型(Int, Double, String)的寫法相同,使用駝峯式

*/

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())");

//}



//委託是一種設計模式,它允許類或結構體將一些需要他們負責的功能交由(委託)給其他的類型

/**

委託模式的實現很簡單,定義協議來封裝那些需要被委託的函數和方法,使其遵循者擁有這些被委託的函數方法

委託模式可以用來響應特定的動作或接受外部數據源提供的數據,而無需要知道外部數據源的類型

*/

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 = [Int](count: finalSquare + 1, repeatedValue: 0);

            board[3] = 8;

            board[6] = 11;

            board[9] = 9;

            board[10] = 2;

            board[14] = -10;

            board[19] = -11;

            board[22] = -2;

            board[24] = -8;

        }

        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++;

            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();


//擴展中添加協議成員

/**

即便無法修改源代碼,依然可以通過擴展(Extension)來擴充已存在類型。擴展可以爲已存在的類型添加屬性,方法,下標,協議等成員

通過擴展爲已存在的類型遵循協議時,該類型的所有實例也會隨之添加協議中的方法

*/

protocol TextRepresenTable {

    func asText() -> String;

}


extension Dice: TextRepresenTable {

    func asText() -> String {

        return "A \(sides)-sided dice";

    }

}

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

print(d12.asText());


extension SnakesAndLadders: TextRepresenTable {

    func asText() -> String {

        return "A game of Snakes and Ladders with \(finalSquare) square";

    }

}

print(game.asText());



//通過延展補充協議聲明

/**

當一個類型已經實現了協議中的所有要求,卻沒有聲明時,可以通過擴展來補充協議聲明

即使滿足了協議的所有要求,類型也不會自動轉變,因此必須爲它做出明顯的協議聲明

*/

struct Hamster {

    var name: String;

    func asText() -> String {

        return "A hamster named \(name)";

    }

}

extension Hamster: TextRepresenTable {};

let simonTheHamster = Hamster(name: "Simon");

let somethingTextRepresentable: TextRepresenTable = simonTheHamster;

print(somethingTextRepresentable.asText());



//集合中的協議類型

/**

協議類型可以被集合使用,表示集合中的元素均爲協議類型

*/

let things: [TextRepresenTable] = [game,d12,simonTheHamster];

for thing in things {

    //thing被當做TextRepresenTable類型而不是Dice,DiceGame,Hamster等類型,因此只能調用asText()方法

    print("===\(thing.asText())===");

}




//協議的繼承

/**

協議能夠繼承一到多個其他協議。語法與類的繼承相似,多個協議間用逗號(,)分隔

protocol InheritingProtocol: SomeProtocol,

AnotherProtocol {

    // 協議定義

}

*/

protocol PrettyTextRepresentable: TextRepresenTable {

    func asPrettyText() -> String;

}

//遵循PrettyTextRepresentable協議的同時,也需要遵循TextRepresenTable的協議

extension SnakesAndLadders: PrettyTextRepresentable {

    func asPrettyText() -> String {

    var output = asText() + ":\n";

    for index in 1...finalSquare {

    switch board[index] {

        case let ladder where ladder > 0:

            output += "正三角";

        case let snake where snake < 0:

            output += "倒三角";

        default:

            output += "圓圈";

    }

    }

    return output;

    }

}


print(game.asPrettyText());



//協議合成

/**

一個協議可由多個協議採用protocol<SomeProtocol,AnptherProtocol>這樣的格式進行組合,稱爲協議合成(protocol composition)

*/

protocol Named {

    var name: String { get };

}

protocol Aged {

    var age: Int { get };

}

struct Person2: Named, Aged {

    var name: String;

    var age: Int;

}

/**

 Named協議包含string類型的name屬性,Aged協議包含Int類型的age屬性,person2結構體遵循了這兩個協議。

 wishHappyBirthday函數的形參celebrator的類型爲protocol<Named,Aged>。可以傳入任意遵循這兩個協議的類型的實例

 協議合成並不會生成一個新協議類型,而是將多個協議合成爲一個臨時的協議,超出範圍後立即失效

*/

func wishHappyBirthday(celebrator: protocol<Named,Aged>) {

    print("Happy birthday \(celebrator.name), you're \(celebrator.age)!");

}

let birthdayPerson = Person2(name: "SB", age: 20);

wishHappyBirthday(birthdayPerson);




//檢驗協議的一致性

/**

使用is檢驗協議一致性,使用as將協議類型向下轉換(downcast)爲的其他協議類型。檢驗與轉換的語法和之前相同

1.is操作符用來檢查視力是否遵循了某個協議

2.as?返回一個值,當實例遵循協議時,返回該協議類型;否則返回nil

3.as用以強制向下轉換型

@objc用來表示協議是可選的,也可以用來表示暴露給OC的代碼,此外,@objc型協議只有對類有效,因此只能在類中檢查協議的一致性

*/

protocol HasArea {

    var area: Double { get };

}

class Circle: HasArea {

    let pi = 3.1415927;

    var radius: Double;

    var area: Double = 0;

    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: 343.23), Animal(legs: 4)];

for obj in objects {

/**

當數組中的元素遵循HasArea協議時,通過as?操作符將其可選綁定(optional binding)objectWithArea常量上

            objects數組中元素的類型並不會因爲向下轉型而改變,當它們被賦值給objectWithArea時只被視爲HasArea類型,因此只有area屬性能夠被訪問

*/

            if let objectWithArea = obj as? HasArea {

                print("Area is \(objectWithArea.area)");

            }else{

                print("Something that doesn't have an area");

            }

}



//可選協議要求

/**

可選協議含有可選成員,其遵循者可以選擇是否實現這些成員。在協議中使用@optional關鍵字作爲前綴來定義可選成員

可選協議在調用時使用可選鏈

可選協議只能在含有@objc前綴的協議中生效

*/

@objc protocol CounterDataSource {

    optional func incrementForCount(count: Int) -> Int;

    optional var fixedIncrement: Int { get };

}

class Counter {

    var count = 0;

    var dataSource: CounterDataSource?;

    func increment() {

        if let amount = dataSource?.incrementForCount?(count) {

            count += amount;

        }else if let amount = dataSource?.fixedIncrement {

           count += amount;

        }

    }

}

class ThreeSource: CounterDataSource {

    @objc let fixedIncrement = 3;

}

var counter = Counter();

counter.dataSource = ThreeSource();

for _ in 1...4 {

    counter.increment();

    print(counter.count);

}



class TowardsZeroSource: CounterDataSource {

        @objc func incrementForCount(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);

}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章