Методы
Методы являются функциями, связанными с определенным типом. Классы, структуры и перечисления могут все определить методы экземпляра, инкапсулирующие определенные задачи и функциональность для работы с экземпляром данного типа. Классы, структуры и перечисления могут также определить методы типа, связанные с самим типом. Методы типа подобны методам класса в Objective C.
Факт, что структуры и перечисления могут определить методы в Swift, является существенным различием от C и Objective C. В Objective C классы являются единственными типами, которые могут определить методы. В Swift можно выбрать, определить ли класс, структуру или перечисление, и все еще иметь гибкость для определения методов на типе, который Вы создаете.
Методы экземпляра
Методы экземпляра являются функциями, принадлежащими экземплярам определенного класса, структуры или перечисления. Они поддерживают функциональность тех экземпляров, или путем обеспечения способов получить доступ и изменить свойства экземпляра, или путем обеспечения функциональности, связанной с целью экземпляра. Методы экземпляра имеют точно тот же синтаксис как функции, как описано в Функциях.
Вы пишете метод экземпляра в открытии и закрывающих фигурных скобках типа, которому оно принадлежит. Метод экземпляра имеет неявный доступ ко всем другим методам экземпляра и свойствам того типа. Метод экземпляра можно вызвать только на определенном экземпляре типа, которому он принадлежит. Это нельзя вызвать в изоляции без существующего экземпляра.
Вот пример, определяющий простое Counter
класс, который может использоваться для подсчета числа раз действием, происходит:
class Counter {
var count = 0
func increment() {
count++
}
func incrementBy(amount: Int) {
count += amount
}
func reset() {
count = 0
}
}
Counter
класс определяет три метода экземпляра:
increment
постепенно увеличивает счетчик1
.incrementBy(amount: Int)
постепенно увеличивает счетчик указанной целочисленной суммой.reset
сбрасывает в противоречии с нулем.
Counter
класс также объявляет переменное свойство, count
, отслеживать текущее встречное значение.
Вы вызываете методы экземпляра с тем же точечным синтаксисом как свойства:
let counter = Counter()
// the initial counter value is 0
counter.increment()
// the counter's value is now 1
counter.incrementBy(5)
// the counter's value is now 6
counter.reset()
// the counter's value is now 0
Локальные и внешние названия параметра для методов
Параметры функции могут иметь обоих локальное имя (для использования в организации функции) и внешнее имя (для использования при вызывании функции), как описано на Внешние Названия параметра. То же является истиной для параметров метода, потому что методы являются просто функциями, связанными с типом. Однако поведение по умолчанию локальных имен и внешних имен отличается для функций и методов.
Методы в Swift очень подобны их дубликатам в Objective C. Как в Objective C, имя метода в Swift обычно относится к первому параметру метода с помощью предлога такой как with
, for
, или by
, как замечено в incrementBy(_:)
метод от предыдущего Counter
пример класса. Использование предлога позволяет методу быть считанным как предложение, когда это вызывают. Swift делает это установленное соглашение о присвоении имен метода простым записать при помощи различного подхода по умолчанию для параметров метода, чем это использует для параметров функции.
В частности Swift дает первое название параметра в методе локальное название параметра по умолчанию и дает вторым и последующим названиям параметра и локальные и внешние названия параметра по умолчанию. Это соглашение соответствует типичное соглашение о присвоении имен и соглашение о вызовах, с которым Вы будете знакомы от записи методов Objective C и делаете для выразительных вызовов метода без потребности квалифицировать Ваши названия параметра.
Рассмотрите эту альтернативную версию Counter
класс, определяющий более сложную форму incrementBy(_:)
метод:
class Counter {
var count: Int = 0
func incrementBy(amount: Int, numberOfTimes: Int) {
count += amount * numberOfTimes
}
}
Это incrementBy(_:numberOfTimes:)
метод имеет два параметра —amount
и numberOfTimes
. По умолчанию, обработки Swift amount
как локальное имя только, но обработки numberOfTimes
и как локальная переменная и как внешнее имя. Вы вызываете метод следующим образом:
let counter = Counter()
counter.incrementBy(5, numberOfTimes: 3)
// counter value is now 15
Вы не должны определять внешнее название параметра для первого значения аргумента, потому что его цель ясна из имени функции incrementBy
. Когда метод вызывают, второй параметр, однако, квалифицирован внешним названием параметра, чтобы ясно дать понять его цель.
Это поведение по умолчанию эффективно обрабатывает метод, как будто Вы записали символ хеша (#
) перед numberOfTimes
параметр:
func incrementBy(amount: Int, #numberOfTimes: Int) {
count += amount * numberOfTimes
}
Поведение по умолчанию описало выше средних значений, что определения метода в Swift пишут с тем же грамматическим стилем как Objective C и вызывают естественным, выразительным способом.
Изменение внешнего поведения названия параметра для методов
Иногда полезно обеспечить внешнее название параметра для первого параметра метода, даже при том, что это не поведение по умолчанию. Можно или добавить явное внешнее имя сами, или можно снабдить префиксом имя первого параметра символ хеша для использования локального имени в качестве внешнего имени также.
С другой стороны, если Вы не хотите обеспечивать внешнее имя для второго или последующего параметра метода, переопределите поведение по умолчанию при помощи символа подчеркивания (_
) как явное внешнее название параметра для того параметра.
Сам Свойство
Каждому экземпляру типа вызвали неявное свойство self
, который точно эквивалентен самому экземпляру. Вы используете self
свойство для обращения к текущему экземпляру в его собственных методах экземпляра.
increment()
метод в примере выше, возможно, был записан как это:
func increment() {
self.count++
}
На практике Вы не должны писать self
в Вашем коде очень часто. Если Вы явно не пишете self
, Swift предполагает, что Вы обращаетесь к свойству или методу текущего экземпляра каждый раз, когда Вы используете известное свойство или имя метода в методе. Это предположение продемонстрировано при помощи count
(а не self.count
) в этих трех методах экземпляра для Counter
.
Когда название параметра для метода экземпляра имеет то же имя как свойство того экземпляра, основное исключение к этому правилу происходит. В этой ситуации имеет приоритет название параметра, и становится необходимо относиться к свойству более квалифицированным способом. Вы используете self
свойство для различения название параметра и имя свойства.
Здесь, self
снимает неоднозначность между вызванным параметром метода x
и свойство экземпляра, которое также вызывают x
:
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(1.0) {
println("This point is to the right of the line where x == 1.0")
}
// prints "This point is to the right of the line where x == 1.0"
Без self
префикс, Swift принял бы это оба использования x
именуемый параметр метода вызывают x
.
Изменение типов значения из методов экземпляра
Структуры и перечисления являются типами значения. По умолчанию свойства типа значения не могут быть изменены из его методов экземпляра.
Однако, если необходимо изменить свойства структуры или перечисления в определенном методе, можно выбрать в к видоизменяющемуся поведению для того метода. Метод может тогда видоизменить (т.е. изменение) свои свойства из метода, и любые изменения, которые это вносит, записываются обратно к исходной структуре, когда заканчивается метод. Метод может также присвоить абсолютно новый экземпляр своему неявному self
когда метод закончится, свойство, и этот новый экземпляр заменят существующий.
Можно выбрать в к этому поведению путем размещения mutating
ключевое слово перед func
ключевое слово для того метода:
struct Point {
var x = 0.0, y = 0.0
mutating func moveByX(deltaX: Double, y deltaY: Double) {
x += deltaX
y += deltaY
}
}
var somePoint = Point(x: 1.0, y: 1.0)
somePoint.moveByX(2.0, y: 3.0)
println("The point is now at (\(somePoint.x), \(somePoint.y))")
// prints "The point is now at (3.0, 4.0)"
Point
структура выше определяет видоизменение moveByX(_:y:)
метод, перемещающий a Point
экземпляр определенной суммой. Вместо того, чтобы возвратить новую точку, этот метод фактически изменяет точку, на которой его вызывают. mutating
ключевое слово добавляется к его определению, чтобы позволить ему изменить свои свойства.
Обратите внимание на то, что Вы не можете вызвать метод видоизменения на константе типа структуры, потому что его свойства не могут быть изменены, даже если они - переменные свойства, как описано в Сохраненных Свойствах Постоянных Экземпляров Структуры:
let fixedPoint = Point(x: 3.0, y: 3.0)
fixedPoint.moveByX(2.0, y: 3.0)
// this will report an error
Присвоение сам В Методе Видоизменения
Видоизменение методов может присвоить полностью новый экземпляр неявному self
свойство. Point
пример, показанный выше, возможно, был записан следующим образом вместо этого:
struct Point {
var x = 0.0, y = 0.0
mutating func moveByX(deltaX: Double, y deltaY: Double) {
self = Point(x: x + deltaX, y: y + deltaY)
}
}
Эта версия видоизменения moveByX(_: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 is now equal to .High
ovenLight.next()
// ovenLight is now equal to .Off
Этот пример определяет перечисление для переключателя с тремя состояниями. Циклы коммутации между тремя различными состояниями электропитания (Off
, Low
и High
) каждый раз next()
метод вызывают.
Введите методы
Методы экземпляра, как описано выше, являются методами, которые вызывают на экземпляре определенного типа. Можно также определить методы, которые вызывают на самом типе. Эти виды методов вызывают методами типа. Вы указываете методы типа путем записи ключевого слова static
перед методом func
ключевое слово. Классы могут также использовать class
ключевое слово, чтобы позволить подклассам переопределять реализацию суперкласса того метода.
Методы типа вызывают с точечным синтаксисом, как методы экземпляра. Однако Вы методы типа вызова на типе, не на экземпляре того типа. Вот то, как Вы вызываете метод типа на вызванном классе SomeClass
:
class SomeClass {
class func someTypeMethod() {
// type method implementation goes here
}
}
SomeClass.someTypeMethod()
В организации метода типа, неявного self
свойство относится к самому типу, а не экземпляру того типа. Для структур и перечислений, это означает, что можно использовать self
снять неоднозначность между свойствами типа и параметрами метода типа, так же, как Вы делаете, например, параметры метода экземпляра и свойства.
Более широко любой неполный метод и имена свойства, которые Вы используете в организации метода типа, будут относиться к другим методам уровня типа и свойствам. Метод типа может вызвать другой метод типа с именем другого метода, не будучи должен снабдить префиксом его имя типа. Точно так же введите методы на структурах, и перечисления могут свойства типа доступа при помощи имени свойства типа без префикса имени типа.
Пример ниже определяет вызванную структуру LevelTracker
, который отслеживает прогресс проигрывателя через разные уровни или этапы игры. Это - игра сингла, но может хранить информацию для многократных проигрывателей на едином устройстве.
Когда в игру сначала играют, все уровни игры (кроме уровня один) заблокированы. Каждый раз, когда проигрыватель заканчивает уровень, тот уровень разблокирован для всех проигрывателей на устройстве. LevelTracker
структура использует свойства типа и методы для отслеживания, которых были разблокированы уровни игры. Это также отслеживает текущий уровень для индивидуального игрока.
struct LevelTracker {
static var highestUnlockedLevel = 1
static func unlockLevel(level: Int) {
if level > highestUnlockedLevel { highestUnlockedLevel = level }
}
static func levelIsUnlocked(level: Int) -> Bool {
return level <= highestUnlockedLevel
}
var currentLevel = 1
mutating func advanceToLevel(level: Int) -> Bool {
if LevelTracker.levelIsUnlocked(level) {
currentLevel = level
return true
} else {
return false
}
}
}
LevelTracker
структура отслеживает высший уровень, который разблокировал любой проигрыватель. Это значение сохранено в вызванном свойстве типа highestUnlockedLevel
.
LevelTracker
также определяет две функции типа для работы с highestUnlockedLevel
свойство. Первой является вызванная функция типа unlockLevel
, который обновляет значение highestUnlockedLevel
каждый раз, когда разблокирован новый уровень. Второй является вызванная функция типа удобства levelIsUnlocked
, который возвращается true
если уже разблокировано определенное число уровня. (Обратите внимание на то, что эти методы типа могут получить доступ highestUnlockedLevel
введите свойство без своей необходимости записать его как LevelTracker.highestUnlockedLevel
.)
В дополнение к его свойству типа и методам типа, LevelTracker
отслеживает прогресс индивидуального игрока через игру. Это использует вызванное свойство экземпляра currentLevel
отслеживать уровень, который в настоящее время играет проигрыватель.
Помочь управлять currentLevel
свойство, LevelTracker
определяет вызванный метод экземпляра advanceToLevel
. Перед обновлением currentLevel
, этот метод проверяет, разблокирован ли уже требуемый новый уровень. advanceToLevel(_:)
метод возвращает булево значение, чтобы указать, смог ли он фактически установить currentLevel
.
LevelTracker
структура используется с Player
класс, показанный ниже, чтобы отследить и обновить прогресс индивидуального игрока:
class Player {
var tracker = LevelTracker()
let playerName: String
func completedLevel(level: Int) {
LevelTracker.unlockLevel(level + 1)
tracker.advanceToLevel(level + 1)
}
init(name: String) {
playerName = name
}
}
Player
класс создает новый экземпляр LevelTracker
отслеживать прогресс того проигрывателя. Это также обеспечивает вызванный метод completedLevel
, который вызывают каждый раз, когда проигрыватель завершает определенный уровень. Этот метод разблокировал следующий уровень для всех проигрывателей и обновляет прогресс проигрывателя для перемещения их в следующий уровень. (Булево возвращаемое значение advanceToLevel
проигнорирован, потому что уровень, как известно, был разблокирован вызовом к LevelTracker.unlockLevel
на предыдущей строке.)
Можно создать экземпляр Player
класс для нового проигрывателя, и видит то, что происходит, когда проигрыватель завершает уровень один:
var player = Player(name: "Argyrios")
player.completedLevel(1)
println("highest unlocked level is now \(LevelTracker.highestUnlockedLevel)")
// prints "highest unlocked level is now 2"
При создании второго проигрывателя кого Вы пытаетесь переместить в уровень, еще не разблокированный никаким проигрывателем в игре, попытка установить сбои текущего уровня проигрывателя:
player = Player(name: "Beto")
if player.tracker.advanceToLevel(6) {
println("player is now on level 6")
} else {
println("level 6 has not yet been unlocked")
}
// prints "level 6 has not yet been unlocked"