(참고사항 https://medium.com/@abhimuralidharan/all-about-protocols-in-swift-11a72d6ea354

tumblr #swift #protocol )

Protocols

A protocol defines a blueprint of methods, properties, and other requirements. The protocol can then be adopted by a class, structure, or enumeration to provide an actual implementation of those requirements. Any type that satisfies the requirements of a protocol is said to conform to that protocol.

In addition to specifying requirements that conforming types must implement, you can extend a protocol to implement some of these requirements or to implement additional functionality that conforming types can take advantage of.

Protocol Syntax

define protocols

protocol SomeProtocol {
   // protocol definition goes here
}

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

If a class has a superclass, list the superclass name before any protocols it adopts, followed by a comma:

class SomeClass: SomeSuperclass, FirstProtocol, AnotherProtocol {
   // class definition goes here
}

Property Requirements

A protocol can require any conforming type to provide an instance property or type property with a particular name and type. The protocol doesn’t specify whether the property should be a stored property or a computed property—it only specifies the required property name and type. The protocol also specifies whether each property must be gettable or gettable and settable.

If a protocol requires a property to be gettable and settable, that property requirement can’t be fulfilled by a constant stored property or a read-only computed property. If the protocol only requires a property to be gettable, the requirement can be satisfied by any kind of property, and it’s valid for the property to be also settable if this is useful for your own code.

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 }
}

Always prefix type property requirements with the static keyword when you define them in a protocol. This rule pertains even though type property requirements can be prefixed with the class or static keyword when implemented by a class(하부 implementing class , structure, enumeration에서 수행될때는 class, static 사용가능하다는 이야기):

protocol FullyNamed {
   var fullName: String { get }
}

struct Person: FullyNamed {
   var fullName: String
}
let john = Person(fullName: “John Appleseed”)
// john.fullName is “John Appleseed”

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”)
// ncc1701.fullName is “USS Enterprise”

Method Requirements

These methods are written as part of the protocol’s definition in exactly the same way as for normal instance and type methods, but without curly braces or a method body. Variadic parameters are allowed, subject to the same rules as for normal methods. Default values, however, can’t be specified for method parameters within a protocol’s definition.

As with type property requirements, you always prefix type method requirements with the static keyword when they’re defined in a protocol. This is true even though type method requirements are prefixed with the class or static keyword when implemented by a class:

protocol SomeProtocol {

   // type method
   static 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).truncatingRemainder(dividingBy:m))
       return lastRandom / m
   }
}
let generator = LinearCongruentialGenerator()
print(“Here’s a random number: (generator.random())”)
// Prints “Here’s a random number: 0.37464991998171”
print(“And another one: (generator.random())”)
// Prints “And another one: 0.729023776863283”

Mutating Method Requirements

It’s sometimes necessary for a method to modify (or mutate) the instance it belongs to. For instance methods on value types (that is, structures and enumerations) you place the mutating keyword before a method’s func keyword to indicate that the method is allowed to modify the instance it belongs to and any properties of that instance. This process is described in Modifying Value Types from Within Instance Methods.

If you define a protocol instance method requirement that is intended to mutate instances of any type that adopts the protocol, mark the method with the mutating keyword as part of the protocol’s definition. This enables structures and enumerations to adopt the protocol and satisfy that method requirement.

NOTE

If you mark a protocol instance method requirement as mutating, you don’t need to write the mutatingkeyword when writing an implementation of that method for a class. The mutating keyword is only used by structures and enumerations.(class에서는 본래 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()
// lightSwitch is now equal to .on

Initializer Requirements

Protocols can require specific initializers to be implemented by conforming types. You write these initializers as part of the protocol’s definition in exactly the same way as for normal initializers, but without curly braces or an initializer body:

protocol SomeProtocol {
   init(someParameter: Int)
}

Class Implementations of Protocol 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:

class SomeClass: SomeProtocol {
   required init(someParameter: Int) {
       // initializer implementation goes here
   }
}

The use of the required modifier ensures that you provide an explicit or inherited implementation of the initializer requirement on all subclasses of the conforming class, such that they also conform to the protocol.

For more information on required initializers, see Required Initializers.

NOTE

You don’t need to mark protocol initializer implementations with the required modifier on classes that are marked with the final modifier, because final classes can’t subclassed. For more on the final modifier, see Preventing Overrides.

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 overridemodifiers:

protocol SomeProtocol {
   init()
}
class SomeSuperClass {
   init() {
       // initializer implementation goes here
   }
}
class SomeSubClass: SomeSuperClass, SomeProtocol {
   // “required” from SomeProtocol conformance; “override” from SomeSuperClass
   required override init() {
       // initializer implementation goes here
   }
}

Failable Initializer Requirements

Protocols can define failable initializer requirements for conforming types, as defined in Failable Initializers.

A failable initializer requirement can be satisfied by a failable or nonfailable initializer on a conforming type. A nonfailable initializer requirement can be satisfied by a nonfailable initializer or an implicitly unwrapped failable initializer.

Protocols as Types

protocol is a type, you can use a protocol in many places where other types are allowed, including:

  • As a parameter type or return type in a function, method, or initializer
  • As the type of a constant, variable, or property
  • As the type of items in an array, dictionary, or other container

NOTE

Because protocols are types, begin their names with a capital letter 

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
   }
}

This example defines a new class called Dice, which represents an n-sided dice for use in a board game. Dice instances have an integer property called sides, which represents how many sides they have, and a property called generator, which provides a random number generator from which to create dice roll values.

The generator property is of type RandomNumberGenerator. Therefore, you can set it to an instance of any type that adopts the RandomNumberGenerator protocol. Nothing else is required of the instance you assign to this property, except that the instance must adopt the RandomNumberGenerator protocol.

Here’s how the Dice class can be used to create a six-sided dice with a LinearCongruentialGeneratorinstance as its random number generator:

var d6 = Dice(sides: 6, generator: LinearCongruentialGenerator())
for _ in 1…5 {
   print(“Random dice roll is (d6.roll())”)
}
// Random dice roll is 3
// Random dice roll is 5
// Random dice roll is 4
// Random dice roll is 5
// Random dice roll is 4

Delegation

Delegation is a design pattern that enables a class or structure to hand off (or delegate) some of its responsibilities to an instance of another type. This design pattern is implemented by defining a protocol that encapsulates the delegated responsibilities, such that a conforming type (known as a delegate) is guaranteed to provide the functionality that has been delegated. Delegation can be used to respond to a particular action, or to retrieve data from an external source without needing to know the underlying type of that source.

The example below defines two protocols for use with dice-based board games:

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 3
// Rolled a 5
// Rolled a 4
// Rolled a 5
// The game lasted for 4 turns

Adding Protocol Conformance with an Extension

You can extend an existing type to adopt and conform to a new protocol, even if you don’t have access to the source code for the existing type. Extensions can add new properties, methods, and subscripts to an existing type, and are therefore able to add any requirements that a protocol may demand. For more about extensions, see Extensions.

NOTE

Existing instances of a type automatically adopt and conform to a protocol when that conformance is added to the instance’s type in an extension.

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)
// Prints “A 12-sided dice”

extension SnakesAndLadders: TextRepresentable {
   var textualDescription: String {
       return “A game of Snakes and Ladders with (finalSquare) squares”
   }
}
print(game.textualDescription)
// Prints “A game of Snakes and Ladders with 25 squares”

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 {}

Instances of Hamster can now be used wherever TextRepresentable is the required type:

let simonTheHamster = Hamster(name: “Simon”)
let somethingTextRepresentable: TextRepresentable = simonTheHamster
print(somethingTextRepresentable.textualDescription)
// Prints “A hamster named Simon”

NOTE

Types don’t automatically adopt a protocol just by satisfying its requirements. They must always explicitly declare their adoption of the protocol.

Collections of Protocol Types

A protocol can be used as the type to be stored in a collection such as an array or a dictionary, as mentioned in Protocols as Types. This example creates an array of TextRepresentable things:

let things: [TextRepresentable] = [game, d12, simonTheHamster]

for thing in things {
   print(thing.textualDescription)
}
// A game of Snakes and Ladders with 25 squares
// A 12-sided dice
// A hamster named Simon

Note that the thing constant is of type TextRepresentable. It’s not of type Dice, or DiceGame, or Hamster.

Protocol Inheritance

A protocol can inherit one or more other protocols and can add further requirements on top of the requirements it inherits. The syntax for protocol inheritance is similar to the syntax for class inheritance, but with the option to list multiple inherited protocols, separated by commas: (class의 경우는 하나의 super class만을 inheriting할수있지만 protocol은 여러개의 protocol을 inherit 할수있다.)

protocol InheritingProtocol: SomeProtocol, AnotherProtocol {
   // protocol definition goes here
}

protocol PrettyTextRepresentable: TextRepresentable {
   var prettyTextualDescription: String { get }
}

This example defines a new protocol, PrettyTextRepresentable, which inherits from TextRepresentable. Anything that adopts PrettyTextRepresentable must satisfy all of the requirements enforced by TextRepresentable, plus the additional requirements enforced by PrettyTextRepresentable. In this example, PrettyTextRepresentable adds a single requirement to provide a gettable property called prettyTextualDescription that returns a String.

extension SnakesAndLadders: PrettyTextRepresentable {
   var prettyTextualDescription: String {
       var output = textualDescription + “: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.prettyTextualDescription)
// A game of Snakes and Ladders with 25 squares:
// ○ ○ ▲ ○ ○ ▲ ○ ○ ▲ ▲ ○ ○ ○ ▼ ○ ○ ○ ○ ▼ ○ ○ ▼ ○ ▼ ○

Class-Only Protocols

(structure,enumeration에서는 conform하지 못하고 class에서만 

conform할수 잇게 만드는 방법)

You can limit protocol adoption to class types (and not structures or enumerations) by adding the AnyObjectprotocol to a protocol’s inheritance list.

protocol SomeClassOnlyProtocol: AnyObject, SomeInheritedProtocol {
   // class-only protocol definition goes here
}

In the example above, SomeClassOnlyProtocol can only be adopted by class types. It’s a compile-time error to write a structure or enumeration definition that tries to adopt SomeClassOnlyProtocol.

NOTE

Use a class-only protocol when the behavior defined by that protocol’s requirements assumes or requires that a conforming type has reference semantics rather than value semantics. For more on reference and value semantics, see Structures and Enumerations Are Value Types and Classes Are Reference Types.

Protocol Composition

(두개이상의  protocol을 수행하는 어떤 타입을 표현한다.  예를 들어 a & b는 a와 b protocol을 conform하는 어떤 type 을 의미)

It can be useful to require a type to conform to multiple protocols at the same time. You can combine multiple protocols into a single requirement with a protocol composition. Protocol compositions behave as if 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, separating them with ampersands (&). In addition to its list of protocols, a protocol composition can also contain one class type, which you can use to 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)
// Prints “Happy birthday, Malcolm, you’re 21!”

In this example, the Named protocol has a single requirement for a gettable String property called name. The Aged protocol has a single requirement for a gettable Int property called age. Both protocols are adopted by a structure called Person.

The example also defines a wishHappyBirthday(to:) function. The type of the celebrator parameter is Named & Aged, which means “any type that conforms to both the Named and Aged protocols.” It doesn’t matter which specific type is passed to the function, as long as it conforms to both of the required protocols.

class Location {
   var latitude: Double
   var longitude: Double
   init(latitude: Double, longitude: Double) {
       self.latitude = latitude
       self.longitude = longitude
   }
}
class City: Location, Named {
   var name: String
   init(name: String, latitude: Double, longitude: Double) {
       self.name = name
       super.init(latitude: latitude, longitude: longitude)
   }
}
func beginConcert(in location: Location & Named) {
   print(“Hello, (location.name)!”)
}
let seattle = City(name: “Seattle”, latitude: 47.6, longitude: -122.3)
beginConcert(in: seattle)
// Prints “Hello, Seattle!”

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. Checking for and casting to a protocol follows exactly the same syntax as checking for and casting to a type:

  • The is operator returns true if an instance conforms to a protocol and returns false if it doesn’t.
  • The as? version of the downcast operator returns an optional value of the protocol’s type, and this value is nil if the instance doesn’t conform to that protocol.
  • The as! version of the downcast operator forces the downcast to the protocol type and triggers a runtime error if the downcast doesn’t succeed.

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

Protocol Extensions

(protocol을 extension해서 이 protocol을 conform하는 모든 class,structure,enumeration이 특정 functions, properties를 기본적으로 가지게 하는 방법)

Protocols can be extended to provide method and property implementations to conforming types. This allows you to define behavior on protocols themselves, rather than in each type’s individual conformance or in a global function.

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

By creating an extension on the protocol, all conforming types automatically gain this method implementation without any additional modification.

let generator = LinearCongruentialGenerator()
print(“Here’s a random number: (generator.random())”)
// Prints “Here’s a random number: 0.37464991998171”
print(“And here’s a random Boolean: (generator.randomBool())”)
// Prints “And here’s a random Boolean: true”

Providing Default Implementations

You can use protocol extensions to provide a default implementation to any method or computed property requirement of that protocol. If a conforming type provides its own implementation of a required method or property, that implementation will be used instead of the one provided by the extension.

NOTE

Protocol requirements with default implementations provided by extensions are distinct from optional protocol requirements. Although conforming types don’t have to provide their own implementation of either, requirements with default implementations can be called without optional chaining.

Adding Constraints to Protocol Extensions

When you define a protocol extension, you can specify constraints that conforming types must satisfy before the methods and properties of the extension are available. You write these constraints after the name of the protocol you’re extending using a generic where clause, as described in Generic Where Clauses.

For instance, you can define an extension to the Collection protocol that applies to any collection whose elements conform to the TextRepresentable protocol from the example above.

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

The textualDescription property returns the textual description of the entire collection by concatenating the textual representation of each element in the collection into a comma-separated list, enclosed in brackets.

Consider the Hamster structure from before, which conforms to the TextRepresentable protocol, and an array of Hamster values:

let murrayTheHamster = Hamster(name: “Murray”)
let morganTheHamster = Hamster(name: “Morgan”)
let mauriceTheHamster = Hamster(name: “Maurice”)
let hamsters = [murrayTheHamster, morganTheHamster, mauriceTheHamster]

Because Array conforms to Collection and the array’s elements conform to the TextRepresentable protocol, the array can use the textualDescription property to get a textual representation of its contents:

print(hamsters.textualDescription)
// Prints “[A hamster named Murray, A hamster named Morgan, A hamster named Maurice]”

NOTE

If a conforming type satisfies the requirements for multiple constrained extensions that provide implementations for the same method or property, Swift will use the implementation corresponding to the most specialized constraints.

(참고사항 https://medium.com/@abhimuralidharan/all-about-protocols-in-swift-11a72d6ea354

tumblr #swift #protocol )

Protocols

A protocol defines a blueprint of methods, properties, and other requirements. The protocol can then be adopted by a class, structure, or enumeration to provide an actual implementation of those requirements. Any type that satisfies the requirements of a protocol is said to conform to that protocol.

In addition to specifying requirements that conforming types must implement, you can extend a protocol to implement some of these requirements or to implement additional functionality that conforming types can take advantage of.

Protocol Syntax

define protocols

protocol SomeProtocol {
   // protocol definition goes here
}

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

If a class has a superclass, list the superclass name before any protocols it adopts, followed by a comma:

class SomeClass: SomeSuperclass, FirstProtocol, AnotherProtocol {
   // class definition goes here
}

Property Requirements

A protocol can require any conforming type to provide an instance property or type property with a particular name and type. The protocol doesn’t specify whether the property should be a stored property or a computed property—it only specifies the required property name and type. The protocol also specifies whether each property must be gettable or gettable and settable.

If a protocol requires a property to be gettable and settable, that property requirement can’t be fulfilled by a constant stored property or a read-only computed property. If the protocol only requires a property to be gettable, the requirement can be satisfied by any kind of property, and it’s valid for the property to be also settable if this is useful for your own code.

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 }
}

Always prefix type property requirements with the static keyword when you define them in a protocol. This rule pertains even though type property requirements can be prefixed with the class or static keyword when implemented by a class(하부 implementing class , structure, enumeration에서 수행될때는 class, static 사용가능하다는 이야기):

protocol FullyNamed {
   var fullName: String { get }
}

struct Person: FullyNamed {
   var fullName: String
}
let john = Person(fullName: “John Appleseed”)
// john.fullName is “John Appleseed”

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”)
// ncc1701.fullName is “USS Enterprise”

Method Requirements

These methods are written as part of the protocol’s definition in exactly the same way as for normal instance and type methods, but without curly braces or a method body. Variadic parameters are allowed, subject to the same rules as for normal methods. Default values, however, can’t be specified for method parameters within a protocol’s definition.

As with type property requirements, you always prefix type method requirements with the static keyword when they’re defined in a protocol. This is true even though type method requirements are prefixed with the class or static keyword when implemented by a class:

protocol SomeProtocol {

   // type method
   static 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).truncatingRemainder(dividingBy:m))
       return lastRandom / m
   }
}
let generator = LinearCongruentialGenerator()
print(“Here’s a random number: (generator.random())”)
// Prints “Here’s a random number: 0.37464991998171”
print(“And another one: (generator.random())”)
// Prints “And another one: 0.729023776863283”

Mutating Method Requirements

It’s sometimes necessary for a method to modify (or mutate) the instance it belongs to. For instance methods on value types (that is, structures and enumerations) you place the mutating keyword before a method’s func keyword to indicate that the method is allowed to modify the instance it belongs to and any properties of that instance. This process is described in Modifying Value Types from Within Instance Methods.

If you define a protocol instance method requirement that is intended to mutate instances of any type that adopts the protocol, mark the method with the mutating keyword as part of the protocol’s definition. This enables structures and enumerations to adopt the protocol and satisfy that method requirement.

NOTE

If you mark a protocol instance method requirement as mutating, you don’t need to write the mutatingkeyword when writing an implementation of that method for a class. The mutating keyword is only used by structures and enumerations.(class에서는 본래 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()
// lightSwitch is now equal to .on

Initializer Requirements

Protocols can require specific initializers to be implemented by conforming types. You write these initializers as part of the protocol’s definition in exactly the same way as for normal initializers, but without curly braces or an initializer body:

protocol SomeProtocol {
   init(someParameter: Int)
}

Class Implementations of Protocol 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:

class SomeClass: SomeProtocol {
   required init(someParameter: Int) {
       // initializer implementation goes here
   }
}

The use of the required modifier ensures that you provide an explicit or inherited implementation of the initializer requirement on all subclasses of the conforming class, such that they also conform to the protocol.

For more information on required initializers, see Required Initializers.

NOTE

You don’t need to mark protocol initializer implementations with the required modifier on classes that are marked with the final modifier, because final classes can’t subclassed. For more on the final modifier, see Preventing Overrides.

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 overridemodifiers:

protocol SomeProtocol {
   init()
}
class SomeSuperClass {
   init() {
       // initializer implementation goes here
   }
}
class SomeSubClass: SomeSuperClass, SomeProtocol {
   // “required” from SomeProtocol conformance; “override” from SomeSuperClass
   required override init() {
       // initializer implementation goes here
   }
}

Failable Initializer Requirements

Protocols can define failable initializer requirements for conforming types, as defined in Failable Initializers.

A failable initializer requirement can be satisfied by a failable or nonfailable initializer on a conforming type. A nonfailable initializer requirement can be satisfied by a nonfailable initializer or an implicitly unwrapped failable initializer.

Protocols as Types

protocol is a type, you can use a protocol in many places where other types are allowed, including:

  • As a parameter type or return type in a function, method, or initializer
  • As the type of a constant, variable, or property
  • As the type of items in an array, dictionary, or other container

NOTE

Because protocols are types, begin their names with a capital letter 

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
   }
}

This example defines a new class called Dice, which represents an n-sided dice for use in a board game. Dice instances have an integer property called sides, which represents how many sides they have, and a property called generator, which provides a random number generator from which to create dice roll values.

The generator property is of type RandomNumberGenerator. Therefore, you can set it to an instance of any type that adopts the RandomNumberGenerator protocol. Nothing else is required of the instance you assign to this property, except that the instance must adopt the RandomNumberGenerator protocol.

Here’s how the Dice class can be used to create a six-sided dice with a LinearCongruentialGeneratorinstance as its random number generator:

var d6 = Dice(sides: 6, generator: LinearCongruentialGenerator())
for _ in 1…5 {
   print(“Random dice roll is (d6.roll())”)
}
// Random dice roll is 3
// Random dice roll is 5
// Random dice roll is 4
// Random dice roll is 5
// Random dice roll is 4

Delegation

Delegation is a design pattern that enables a class or structure to hand off (or delegate) some of its responsibilities to an instance of another type. This design pattern is implemented by defining a protocol that encapsulates the delegated responsibilities, such that a conforming type (known as a delegate) is guaranteed to provide the functionality that has been delegated. Delegation can be used to respond to a particular action, or to retrieve data from an external source without needing to know the underlying type of that source.

The example below defines two protocols for use with dice-based board games:

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 3
// Rolled a 5
// Rolled a 4
// Rolled a 5
// The game lasted for 4 turns

Adding Protocol Conformance with an Extension

You can extend an existing type to adopt and conform to a new protocol, even if you don’t have access to the source code for the existing type. Extensions can add new properties, methods, and subscripts to an existing type, and are therefore able to add any requirements that a protocol may demand. For more about extensions, see Extensions.

NOTE

Existing instances of a type automatically adopt and conform to a protocol when that conformance is added to the instance’s type in an extension.

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)
// Prints “A 12-sided dice”

extension SnakesAndLadders: TextRepresentable {
   var textualDescription: String {
       return “A game of Snakes and Ladders with (finalSquare) squares”
   }
}
print(game.textualDescription)
// Prints “A game of Snakes and Ladders with 25 squares”

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 {}

Instances of Hamster can now be used wherever TextRepresentable is the required type:

let simonTheHamster = Hamster(name: “Simon”)
let somethingTextRepresentable: TextRepresentable = simonTheHamster
print(somethingTextRepresentable.textualDescription)
// Prints “A hamster named Simon”

NOTE

Types don’t automatically adopt a protocol just by satisfying its requirements. They must always explicitly declare their adoption of the protocol.

Collections of Protocol Types

A protocol can be used as the type to be stored in a collection such as an array or a dictionary, as mentioned in Protocols as Types. This example creates an array of TextRepresentable things:

let things: [TextRepresentable] = [game, d12, simonTheHamster]

for thing in things {
   print(thing.textualDescription)
}
// A game of Snakes and Ladders with 25 squares
// A 12-sided dice
// A hamster named Simon

Note that the thing constant is of type TextRepresentable. It’s not of type Dice, or DiceGame, or Hamster.

Protocol Inheritance

A protocol can inherit one or more other protocols and can add further requirements on top of the requirements it inherits. The syntax for protocol inheritance is similar to the syntax for class inheritance, but with the option to list multiple inherited protocols, separated by commas: (class의 경우는 하나의 super class만을 inheriting할수있지만 protocol은 여러개의 protocol을 inherit 할수있다.)

protocol InheritingProtocol: SomeProtocol, AnotherProtocol {
   // protocol definition goes here
}

protocol PrettyTextRepresentable: TextRepresentable {
   var prettyTextualDescription: String { get }
}

This example defines a new protocol, PrettyTextRepresentable, which inherits from TextRepresentable. Anything that adopts PrettyTextRepresentable must satisfy all of the requirements enforced by TextRepresentable, plus the additional requirements enforced by PrettyTextRepresentable. In this example, PrettyTextRepresentable adds a single requirement to provide a gettable property called prettyTextualDescription that returns a String.

extension SnakesAndLadders: PrettyTextRepresentable {
   var prettyTextualDescription: String {
       var output = textualDescription + “: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.prettyTextualDescription)
// A game of Snakes and Ladders with 25 squares:
// ○ ○ ▲ ○ ○ ▲ ○ ○ ▲ ▲ ○ ○ ○ ▼ ○ ○ ○ ○ ▼ ○ ○ ▼ ○ ▼ ○

Class-Only Protocols

(structure,enumeration에서는 conform하지 못하고 class에서만 

conform할수 잇게 만드는 방법)

You can limit protocol adoption to class types (and not structures or enumerations) by adding the AnyObjectprotocol to a protocol’s inheritance list.

protocol SomeClassOnlyProtocol: AnyObject, SomeInheritedProtocol {
   // class-only protocol definition goes here
}

In the example above, SomeClassOnlyProtocol can only be adopted by class types. It’s a compile-time error to write a structure or enumeration definition that tries to adopt SomeClassOnlyProtocol.

NOTE

Use a class-only protocol when the behavior defined by that protocol’s requirements assumes or requires that a conforming type has reference semantics rather than value semantics. For more on reference and value semantics, see Structures and Enumerations Are Value Types and Classes Are Reference Types.

Protocol Composition

(두개이상의  protocol을 수행하는 어떤 타입을 표현한다.  예를 들어 a & b는 a와 b protocol을 conform하는 어떤 type 을 의미)

It can be useful to require a type to conform to multiple protocols at the same time. You can combine multiple protocols into a single requirement with a protocol composition. Protocol compositions behave as if 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, separating them with ampersands (&). In addition to its list of protocols, a protocol composition can also contain one class type, which you can use to 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)
// Prints “Happy birthday, Malcolm, you’re 21!”

In this example, the Named protocol has a single requirement for a gettable String property called name. The Aged protocol has a single requirement for a gettable Int property called age. Both protocols are adopted by a structure called Person.

The example also defines a wishHappyBirthday(to:) function. The type of the celebrator parameter is Named & Aged, which means “any type that conforms to both the Named and Aged protocols.” It doesn’t matter which specific type is passed to the function, as long as it conforms to both of the required protocols.

class Location {
   var latitude: Double
   var longitude: Double
   init(latitude: Double, longitude: Double) {
       self.latitude = latitude
       self.longitude = longitude
   }
}
class City: Location, Named {
   var name: String
   init(name: String, latitude: Double, longitude: Double) {
       self.name = name
       super.init(latitude: latitude, longitude: longitude)
   }
}
func beginConcert(in location: Location & Named) {
   print(“Hello, (location.name)!”)
}
let seattle = City(name: “Seattle”, latitude: 47.6, longitude: -122.3)
beginConcert(in: seattle)
// Prints “Hello, Seattle!”

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. Checking for and casting to a protocol follows exactly the same syntax as checking for and casting to a type:

  • The is operator returns true if an instance conforms to a protocol and returns false if it doesn’t.
  • The as? version of the downcast operator returns an optional value of the protocol’s type, and this value is nil if the instance doesn’t conform to that protocol.
  • The as! version of the downcast operator forces the downcast to the protocol type and triggers a runtime error if the downcast doesn’t succeed.

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

Protocol Extensions

(protocol을 extension해서 이 protocol을 conform하는 모든 class,structure,enumeration이 특정 functions, properties를 기본적으로 가지게 하는 방법)

Protocols can be extended to provide method and property implementations to conforming types. This allows you to define behavior on protocols themselves, rather than in each type’s individual conformance or in a global function.

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

By creating an extension on the protocol, all conforming types automatically gain this method implementation without any additional modification.

let generator = LinearCongruentialGenerator()
print(“Here’s a random number: (generator.random())”)
// Prints “Here’s a random number: 0.37464991998171”
print(“And here’s a random Boolean: (generator.randomBool())”)
// Prints “And here’s a random Boolean: true”

Providing Default Implementations

You can use protocol extensions to provide a default implementation to any method or computed property requirement of that protocol. If a conforming type provides its own implementation of a required method or property, that implementation will be used instead of the one provided by the extension.

NOTE

Protocol requirements with default implementations provided by extensions are distinct from optional protocol requirements. Although conforming types don’t have to provide their own implementation of either, requirements with default implementations can be called without optional chaining.

Adding Constraints to Protocol Extensions

When you define a protocol extension, you can specify constraints that conforming types must satisfy before the methods and properties of the extension are available. You write these constraints after the name of the protocol you’re extending using a generic where clause, as described in Generic Where Clauses.

For instance, you can define an extension to the Collection protocol that applies to any collection whose elements conform to the TextRepresentable protocol from the example above.

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

The textualDescription property returns the textual description of the entire collection by concatenating the textual representation of each element in the collection into a comma-separated list, enclosed in brackets.

Consider the Hamster structure from before, which conforms to the TextRepresentable protocol, and an array of Hamster values:

let murrayTheHamster = Hamster(name: “Murray”)
let morganTheHamster = Hamster(name: “Morgan”)
let mauriceTheHamster = Hamster(name: “Maurice”)
let hamsters = [murrayTheHamster, morganTheHamster, mauriceTheHamster]

Because Array conforms to Collection and the array’s elements conform to the TextRepresentable protocol, the array can use the textualDescription property to get a textual representation of its contents:

print(hamsters.textualDescription)
// Prints “[A hamster named Murray, A hamster named Morgan, A hamster named Maurice]”

NOTE

If a conforming type satisfies the requirements for multiple constrained extensions that provide implementations for the same method or property, Swift will use the implementation corresponding to the most specialized constraints.