class Counter {
var count = 0
func increment() {
count += 1
}
func increment(by amount: Int) {
count += amount
}
func reset() {
count = 0
}
}
Класс Counter
определяет три метода объекта:
Counter
также определяет переменное свойство, count
, для отслеживания текущего значения счётчика.
let counter = Counter()
// начальное значение счётчика равно 0
counter.increment()
// значение счэтчика теперь равно 1
counter.increment(by: 5)
// значение счэтчика теперь равно 6
counter.reset()
// значение счэтчика теперь равно 0
Параметры функции имеют как имя (для использования внутри тела функции), так и ярлык аргумента (для использования при вызове функции). То же верно и для параметров методов, так как методы это просто функции, ассоциированные с типом.
self
, которое является на деле эквивалентом для самого этого экземпляра. Вы можете использовать свойство self
для ссылки на текущий объект ищ его собственных методов.
increment()
в примере выше может быть переписан так:
class Counter {
var count = 0
func increment() {
self.count += 1
}
func increment(by amount: Int) {
count += amount
}
func reset() {
count = 0
}
}
На практике Вам не нужно писать self
в Вашем коде слишком часто. Если Вы не напишите явно self
, то Swift примет, что Вы ссылаетесь на свойство или метод текущего объекта, когда вы используете известное имя свойства или метода внутри метода. Это демонстрируется с помощью использования count
(вместо self.count
) внутри трёх методов экземпляра для Counter
.
self
, чтобы разбить неопределённость между именем параметра и именем свойства.
struct Point {
var x = 0.0, y = 0.0
func isToTheRightOfX(x: Double) -> Bool {
return self.x > x
}
}
let somePoint = Point(x: 4.0, y: 5.0)
if somePoint.isToTheRightOfX(x: 1.0) {
print("This point is to the right of the line where x == 1.0")
}
// Выведет print("This point is to the right of the line where x == 1.0")
Здесь self
снимает неопределённость между параметром метода с названием x и свойством объекта с таким же именем x.
self
Swift может принять, что оба использования x ссылаются на параметр метода x.
self
, и этот новый экземпляр заменит существующий, когда метод завершит свою работу.
mutating
перед ключевым словом func
для этого метода:
struct Point {
var x = 0.0, y = 0.0
mutating func moveBy(x deltaX: Double, y deltaY: Double) {
x += deltaX
y += deltaY
}
}
var somePoint = Point(x: 1.0, y: 1.0)
somePoint.moveBy(x: 2.0, y: 3.0)
print("The point is now at (\(somePoint.x), \(somePoint.y))")
// Выведет "The point is now at (3.0, 4.0)
Структура Point
выше определяет мутирующий метод moveBy(x:y:)
, который перемещает объект типа Point
на указанное расстояние. Вместо возвращения новой точки этот метод на деле модифицирует точку, на которой он вызван. Ключевое слово mutating
добавлено в определение для включения возможности модифицировать свойства.
let fixedPoint = Point(x: 3.0, y: 3.0)
fixedPoint.moveBy(x: 2.0, y: 3.0)
// это вызовет ошибку
self
. Пример Point
, данный выше, может быть записан в следующем виде:
struct Point {
var x = 0.0, y = 0.0
mutating func moveBy(x deltaX: Double, y deltaY: Double) {
self = Point(x: x + deltaX, y: y + deltaY)
}
}
Эта версия мутирующего метода moveBy(x:y:)
создаёт полностью новую структуру, чьи значения x и y устанавливаются в целевую локацию. Конечный результат вызова альтернативной версии этого метода будет таким же, как и вызов ранней версии.
self
быть другим кейсом для того же перечисления:
enum TriStateSwitch {
case off, low, high
mutating func next() {
switch self {
case .off:
self = .low
case .low:
self = .high
case .high:
self = .off
}
}
}
var ovenLight = TriStateSwitch.low
ovenLight.next()
// ovenLight теперь равен .high
ovenLight.next()
// ovenLight теперь равен .off
Этот пример определяет перечисление для трёхшагового переключателя. Переключатель циркулирует между трёх разных состояний энергии (off, low и high) всякий раз, когда вызывается метод next()
.
static
перед ключевым словом метода func
.
SomeClass
:
class SomeClass {
class func someTypeMethod() {
// здесь располагается реализация метода типа
}
}
SomeClass.someTypeMethod()
Внутри тела метода типа неявно свойство self
ссылается на тип в общем, а не на отдельный экземпляр этого типа. Это означает, что Вы можете использовать self
для снятия неопределённости между свойствами типа и параметрами метода типа, как если бы Вы работали со свойствами объекта и параметрами метода объекта.
LevelTracker
, которая отслеживает прогресс игрока между разными уровнями или стадиями игры. Это синглплеерная игра, но может хранить информацию для нескольких игроков на одном устройстве.
LevelTracker
использует свойства и методы типа для отслеживания того, какие уровни в игре были разблокированы. Она также отслеживает текущий уровень для отдельного игрока.
struct LevelTracker {
static var highestUnlockedLevel = 1
var currentLevel = 1
static func unlock(_ level: Int) {
if level > highestUnlockedLevel { highestUnlockedLevel = level }
}
static func isUnlocked(_ level: Int) -> Bool {
return level <= highestUnlockedLevel
}
@discardableResult
mutating func advance(to level: Int) -> Bool {
if LevelTracker.isUnlocked(level) {
currentLevel = level
return true
} else {
return false
}
}
}
Структура LevelTracker
отслеживает наивысший уровень, который был разблокирован игроком. Это значение хранится в свойстве типа с названием highestUnlockedLevel
.
LevelTracker
также определяет две функции типа для работы со свойством highestUnlockedLevel
. Первая имеет название unlock(_:)
и обновляет значение highestUnlockedLevel
, всякий раз при разблокировке нового уровня. Вторая - это удобная функция типа с названием isUnlocked(_:)
, которая возвращает true
, если номер заданного уровня уже разблокирован. (Обратите внимание, что эти методы типа могут получить доступ к свойству типа highestUnlockedLevel
без необходимости записывать его в виде LevelTracker.highestUnlockedLevel
.)
LevelTracker
отслеживает прогресс отдельного игрока через игру. Он использует свойство объекта с названием currentLevel
для отслеживания текущего уровня игрока.
currentLevel
, LevelTracker
определяет метод объекта с названием advance(to:)
. Прежде, чем обновить currentLevel
, этот метод проверяет, разблокирован ли уже новый запрашиваемый уровень. Метод advance(to:)
возвращает Булево значение для указания того, можно ли или нет установить currentLevel
. Так как это не необходимо, ошибка для кода, что вызывает advance(to:)
метод, игнорировать возвращаемое значение, то функция помечена атрибутом @discardableResult
.
LevelTracker
испольузется в классе Player
, данном ниже, для отслеживания и обновления прогресса отдельного игрока:
class Player {
var tracker = LevelTracker()
let playerName: String
func complete(level: Int) {
LevelTracker.unlock(level + 1)
tracker.advance(to: level + 1)
}
init(name: String) {
playerName = name
}
}
Класс Player
создаёт новый объект типа LevelTracker
для отслеживания прогресса игрока. Он также предоставляет метод с именем complete(level:)
, который вызывается, как только игрок завершает определённый уровень. Этот метод разблокирует следующий уровень для всех игроков и обновляет прогресс игрока для пресыщения их к новому уровню. (Булево возвращаемое значение advance(to:)
игнорируется, такая уровень известен, что он разблокирован вызовом LevelTracker.unlock(_:)
на предыдущей строке.)
Player
для нового игрока и увидеть, что происходит, когда игрок завершает уровень один:
var player = Player(name: "Argyrios")
player.complete(level: 1)
print("highest unlocked level is now \(LevelTracker.highestUnlockedLevel)")
// Выведет "highest unlocked level is now 2"
player = Player(name: "Beto")
if player.tracker.advance(to: 6) {
print("player is now on level 6")
} else {
print("level 6 has not yet been unlocked")
}
// Выведет "level 6 has not yet been unlocked"