protocol SomeProtocol {
// здесь будет реализация протокола
}
struct SomeStructure: FirstProtocol, AnotherProtocol {
// здесь будет определение структуры
}
class SomeClass: SomeSuperclass, FirstProtocol, AnotherProtocol {
// здесь идёт определение класса
}
var
. Получаемые и задаваемые свойства указываются с помощью { get set }
после объявления их типа, а получаемые свойства указываются написанием {get}
.
protocol SomeProtocol {
var mustBeSettable: Int { get set }
var doesNotNeedToBeSettable: Int { get }
}
static
, когда определяйте его в протоколе. Это правило работает даже для требований типов, которые могут быть предварены ключевыми словами class
или static
, когда они реализуются классом:
protocol AnotherProtocol {
static var someTypeProperty: Int { get set }
}
protocol FullyNamed {
var fullName: String { get }
}
Протокол FullyNamed
требует у соответствующего типа предоставляет полностью-квалифированное имя. Протокол не определяет ничего больше о природе подходящего типа: он только указывает, что тип должен предоставлять полное имя для себя. Протокол постановляет, что любой тип FullyNamed
должен иметь задаваемое свойство объекта с названием fullName
, которое имеет тип String
.
FullyNamed
:
struct Person: FullyNamed {
var fullName: String
}
let john = Person(fullName: "John Appleseed")
// john.fullName равен "John Appleseed"
Этот пример определяет структуру с названием Person
, которая представляет конкретного человека с именем. Она утверждает, что адаптирует протокол FullyNamed
в качестве первой сроке определения.
Person
имеет единственное хранимое свойство с названием fullName
, чей тип - String
. Это совпадает с единственным требованием FullyNamed-протокола и означает, что Person
корректно соответствует протоколу. (Swift выдаст ошибку времени компиляции, если требование протокола не удовлетворено.)
FullyNamed
:
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 равен "USS Enterprise"
Этот класс реализует требуемое свойство fullName
в качестве вычисляемого свойства только-для-чтения для звездолёта. Каждый объект класса Starship
хранит обязательное name и опциональное prefix
. Свойство fullName
использует значение prefix
, если оно существует и дополняет его в начало name для создания полного имени звездолёта.
static
, когда они определяются в протоколе. Это верно, даже если требования метода типа префиксируются ключевыми словами class
или static
, когда они реализуются классом:
protocol SomeProtocol {
static func someTypeMethod()
}
protocol RandomNumberGenerator {
func random() -> Double
}
Протокол RandomNumberGenerator
требует от любого подходящего типа иметь метод объекта с названием random
, который возвращает значение Double
при всяком своём вызове. И хотя это не определено в протоколе, но принимается, что это значение будет числом от 0.0 до (невключительно) 1.0.
RandomNumberGenerator
не делает никаких предположений о том, как каждое случайное число генерируется, он просто требует от генератора предоставить стандартный способ для генерации нового случайного числа.
RandomNumberGenerator
. Этот класс реализует псевдослучайный генератор чисел с алгоритмом, известным как линейный конгруэнтный генератор:
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())")
// Выведет "Here's a random number: 0.37464991998171"
print("And another one: \(generator.random())")
// Выведет "And another one: 0.729023776863283"
mutating
перед ключевым словом метода func
для указания на то, что ему разрешено изменять объект, которому он принадлежит, и любые его свойства.
mutating
в качестве части определения протокола. Это позволит структурам и перечислениям адаптировать протокол и удовлетворять этому требованию метода.
mutating
, то Вам не нужно писать ключевое слово mutating
при записи реализации этого метода для класса. Ключевое слово mutating
используется только структурами и перечислениями.
Togglable
, который определяет единственный метод объекта с названием toogle()
. Как ясно из его имени, метод toogle()
должен переключать или инвертировать состояние любого удовлетворяющего типа, обычно изменяя свойство этого типа.
mutatuing
как часть определения протокола Togglable
для указания на то, что метод должен скорее всего изменять состояние подходящего объекта, когда он вызывается:
protocol Togglable {
mutating func toggle()
}
Если Вы реализуете протокол Togglable
для структуры или перечисления, то эти структура или перечисление смогут удовлетворять протоколу, предоставляя реализацию метода toogle()
, который так же помечен как mutating
.
OnOffSwitch
. Это перечисление переключает между двумя состояниями, соответствующими кейсам перечисления on
и off
. Реализация перечисления toogle
помечена как mutating
для соответствия требованиям протокола Togglable
:
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 теперь равен .on
protocol SomeProtocol {
init(someParameter: Int)
}
required
:
class SomeClass: SomeProtocol {
required init(someParameter: Int) {
// реализация конструктора идёт здесь
}
}
Использование модификатора required
гарантирует, что Вы предоставите явную или унаследованную реализацию требуемого конструктора для всех подклассов соответствующего класса, так чтобы они тоже удовлетворяли протоколу.
required
для классов с модификатором final
, так как финальные классы не могут быть унаследованы.
required
и override
:
protocol SomeProtocol {
init()
}
class SomeSuperClass {
init() {
// реализация конструктора идёт здесь
}
}
class SomeSubClass: SomeSuperClass, SomeProtocol {
// "required" from SomeProtocol conformance; "override" from SomeSuperClass
required override init() {
// реализация конструктора идёт здесь
}
}