Расширения
Расширения добавляют новую функциональность к существующему классу, структуре или типу перечисления. Это включает возможность расширить типы, для которых у Вас нет доступа к коду первоисточника (известным как моделирование обратной силы). Расширения подобны категориям в Objective C. (В отличие от категорий Objective C, расширения Swift не имеют имен.)
Расширения в Swift могут:
Добавьте вычисленные свойства и вычисленные свойства типа
Определите методы экземпляра и введите методы
Обеспечьте новые инициализаторы
Определите нижние индексы
Определите и используйте новые вложенные типы
Заставьте существующий тип соответствовать протоколу
Дополнительный синтаксис
Объявите расширения с extension
ключевое слово:
extension SomeType {
// new functionality to add to SomeType goes here
}
Расширение может расширить существующий тип, чтобы заставить его принять один или несколько протоколов. Где дело обстоит так, имена протокола написаны точно таким же образом что касается класса или структуры:
extension SomeType: SomeProtocol, AnotherProtocol {
// implementation of protocol requirements goes here
}
Добавление соответствия протокола таким образом описано в Добавляющем Соответствии Протокола с Расширением.
Вычисленные свойства
Расширения могут добавить вычисленные свойства экземпляра и вычисленные свойства типа к существующим типам. Этот пример добавляет пять вычисленных свойств экземпляра к встроенному Swift Double
введите, для оказания основной поддержки для работы с единицами расстояния:
extension Double {
var km: Double { return self * 1_000.0 }
var m: Double { return self }
var cm: Double { return self / 100.0 }
var mm: Double { return self / 1_000.0 }
var ft: Double { return self / 3.28084 }
}
let oneInch = 25.4.mm
println("One inch is \(oneInch) meters")
// prints "One inch is 0.0254 meters"
let threeFeet = 3.ft
println("Three feet is \(threeFeet) meters")
// prints "Three feet is 0.914399970739201 meters"
Эти вычисленные свойства экспресс это a Double
значение нужно рассмотреть как определенный модуль длины. Несмотря на то, что они реализованы как вычисленные свойства, имена этих свойств могут быть добавлены к литеральному значению с плавающей точкой с точечным синтаксисом как способ использовать то литеральное значение для выполнения преобразований расстояния.
В этом примере, a Double
значение 1.0
как полагают, представляет «один метр». Это то, почему m
вычисленные возвраты свойства self
— выражение 1.m
как полагают, вычисляет a Double
значение 1.0
.
Другие модули требуют, чтобы некоторое преобразование было выражено как значение, измеренное в метрах. Один километр совпадает с 1 000 метров, таким образом, km
вычисленное свойство умножает значение на 1_000.00
преобразовать в число, выраженное в метрах. Точно так же существует 3,28024 футов в метре, и таким образом, ft
вычисленное свойство делит базовое Double
значение 3.28024
, преобразовать его от футов до метров.
Эти свойства являются вычисленными свойствами только для чтения, и таким образом, они выражены без get
ключевое слово, для краткости. Их возвращаемое значение имеет тип Double
, и может использоваться в математических вычислениях везде, где a Double
принят:
let aMarathon = 42.km + 195.m
println("A marathon is \(aMarathon) meters long")
// prints "A marathon is 42195.0 meters long"
Инициализаторы
Расширения могут добавить новые инициализаторы к существующим типам. Это позволяет Вам расширить другие типы, чтобы принять Ваши собственные типы как параметры инициализатора или предоставить дополнительные возможности инициализации, не включенные как часть исходной реализации типа.
Расширения могут добавить новые инициализаторы удобства к классу, но они не могут добавить новые определяемые инициализаторы или deinitializers к классу. Определяемые инициализаторы и deinitializers должны всегда быть предоставлены исходной реализацией класса.
Пример ниже определяет пользовательское Rect
структура для представления геометрического прямоугольника. Пример также определяет две вызванные опорных конструкции Size
и Point
, оба из которых обеспечивают значения по умолчанию 0.0
для всех их свойств:
struct Size {
var width = 0.0, height = 0.0
}
struct Point {
var x = 0.0, y = 0.0
}
struct Rect {
var origin = Point()
var size = Size()
}
Поскольку Rect
структура обеспечивает значения по умолчанию для всех ее свойств, она получает инициализатор по умолчанию и memberwise инициализатор автоматически, как описано в Инициализаторах По умолчанию. Эти инициализаторы могут использоваться для создания новый Rect
экземпляры:
let defaultRect = Rect()
let memberwiseRect = Rect(origin: Point(x: 2.0, y: 2.0),
size: Size(width: 5.0, height: 5.0))
Можно расшириться Rect
структура для обеспечения дополнительного инициализатора, берущего определенную центральную точку и размер:
extension Rect {
init(center: Point, size: Size) {
let originX = center.x - (size.width / 2)
let originY = center.y - (size.height / 2)
self.init(origin: Point(x: originX, y: originY), size: size)
}
}
Этот новый инициализатор запускается путем вычисления надлежащей точки источника на основе предоставленного center
точка и size
значение. Инициализатор тогда вызывает автоматический memberwise инициализатор структуры init(origin:size:)
, который хранит новый источник и значения размера в надлежащих свойствах:
let centerRect = Rect(center: Point(x: 4.0, y: 4.0),
size: Size(width: 3.0, height: 3.0))
// centerRect's origin is (2.5, 2.5) and its size is (3.0, 3.0)
Методы
Расширения могут добавить новые методы экземпляра и ввести методы к существующим типам. Следующий пример добавляет новый вызванный метод экземпляра repetitions
к Int
тип:
extension Int {
func repetitions(task: () -> ()) {
for _ in 0..<self {
task()
}
}
}
repetitions(_:)
метод берет отдельный аргумент типа () -> ()
, который указывает функцию, не имеющую никаких параметров и не возвращающую значение.
После определения этого расширения можно вызвать repetitions(_:)
метод на любом целом числе для выполнения задачи, что многие число раз:
3.repetitions({
println("Hello!")
})
// Hello!
// Hello!
// Hello!
Используйте запаздывание синтаксиса закрытия для совершения более сжатого вызова:
3.repetitions {
println("Goodbye!")
}
// Goodbye!
// Goodbye!
// Goodbye!
Видоизменение методов экземпляра
Методы экземпляра, добавленные с расширением, могут также изменить (или видоизмениться), сам экземпляр. Изменяющие структура и методы перечисления self
или его свойства должны отметить метод экземпляра как mutating
, точно так же, как видоизменяющиеся методы от исходной реализации.
Пример ниже добавляет новый вызванный метод видоизменения square
к Swift Int
введите, который придает исходному значению квадратную форму:
extension Int {
mutating func square() {
self = self * self
}
}
var someInt = 3
someInt.square()
// someInt is now 9
Нижние индексы
Расширения могут добавить новые нижние индексы к существующему типу. Этот пример добавляет целочисленный нижний индекс к встроенному Swift Int
ввести. Этот нижний индекс [n]
возвращает десятичную цифру n
места в от права на число:
123456789[0]
возвраты9
123456789[1]
возвраты8
… и т.д.:
extension Int {
subscript(var digitIndex: Int) -> Int {
var decimalBase = 1
while digitIndex > 0 {
decimalBase *= 10
--digitIndex
}
return (self / decimalBase) % 10
}
}
746381295[0]
// returns 5
746381295[1]
// returns 9
746381295[2]
// returns 2
746381295[8]
// returns 7
Если Int
значение не имеет достаточного количества цифр для требуемого индекса, нижних возвратов реализации 0
, как будто число было дополнено, обнуляет налево:
746381295[9]
// returns 0, as if you had requested:
0746381295[9]
Вложенные типы
Расширения могут добавить новые вложенные типы к существующим классам, структурам и перечислениям:
extension Int {
enum Kind {
case Negative, Zero, Positive
}
var kind: Kind {
switch self {
case 0:
return .Zero
case let x where x > 0:
return .Positive
default:
return .Negative
}
}
}
Этот пример добавляет новое вложенное перечисление к Int
. Это перечисление, вызванное Kind
, выражает вид числа, которое представляет определенное целое число. В частности это выражает, отрицательно ли число, нуль, или положительно.
Этот пример также добавляет новое вычисленное свойство экземпляра к Int
, вызванный kind
, который возвращает надлежащее Kind
элемент перечисления для того целого числа.
Вложенное перечисление может теперь использоваться с любым Int
значение:
func printIntegerKinds(numbers: [Int]) {
for number in numbers {
switch number.kind {
case .Negative:
print("- ")
case .Zero:
print("0 ")
case .Positive:
print("+ ")
}
}
print("\n")
}
printIntegerKinds([3, 19, -27, 0, -6, 0, 7])
// prints "+ + - 0 - 0 +"
Эта функция, printIntegerKinds
, берет входной массив Int
значения и выполняют итерации по тем значениям поочередно. Для каждого целого числа в массиве функция рассматривает kind
вычисленное свойство для того целого числа и печать надлежащее описание.