Видеокурсы по изучению языка программирования Swift. Подробнее

Методы типа

Если вы нашли опечатку в тексте, выделите ее и нажмите CTRL + ENTER.

Методы экземпляра, которые описаны выше, являются методами, которые вызываются экземпляром конкретного типа. Вы так же можете определить методы, которые вызываются самим типом. Такие методы зовутся методами типа. Индикатор такого метода - ключевое слово class, которое ставится до ключевого слова метода func, в случае классов, ну а в случае структур или перечислений ставится ключевое слово static, перед ключевым словом func.

Заметка

В Objective-C определять методы типов можно только для классов. В Swift вы можете создавать методы типа не только для классов, но и для структур и перечислений. Метод каждого типа ограничен самим типом, который он поддерживает.

Такие методы так же используют точечный синтаксис, как и методы экземпляра. Однако эти методы вы вызываете самим типом, а не экземпляром этого типа. Вот как вы можете вызвать метод самим классом 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("Самый последний доступный уровень сейчас равен \(LevelTracker.highestUnlockedLevel)")
//Выведет "Самый последний доступный уровень сейчас равен 2"

Если вы создадите второго игрока, и попробуете им начать прохождение уровня, который не был разблокирован ни одним игроком в игре, то вы увидите, что эта попытка будет неудачной:

player = Player(name: "Beto")
if player.tracker.advance(to: 6) {
    print("Игрок на уровне 6")
} else {
    print("Уровень 6 еще не разблокирован")
}
// Выведет "Уровень 6 еще не разблокирован"

 

Swift: 
4.0