summaryrefslogtreecommitdiffhomepage
path: root/ru-ru/swift-ru.html.markdown
diff options
context:
space:
mode:
Diffstat (limited to 'ru-ru/swift-ru.html.markdown')
-rw-r--r--ru-ru/swift-ru.html.markdown699
1 files changed, 699 insertions, 0 deletions
diff --git a/ru-ru/swift-ru.html.markdown b/ru-ru/swift-ru.html.markdown
new file mode 100644
index 00000000..f2b1fd36
--- /dev/null
+++ b/ru-ru/swift-ru.html.markdown
@@ -0,0 +1,699 @@
+---
+language: swift
+contributors:
+ - ["Grant Timmerman", "http://github.com/grant"]
+ - ["Christopher Bess", "http://github.com/cbess"]
+ - ["Joey Huang", "http://github.com/kamidox"]
+ - ["Alexey Nazaroff", "http://github.com/rogaven"]
+filename: learnswift-ru.swift
+translators:
+ - ["Dmitry Bessonov", "https://github.com/TheDmitry"]
+ - ["Alexey Nazaroff", "https://github.com/rogaven"]
+lang: ru-ru
+---
+
+Swift - это язык программирования, созданный компанией Apple, для приложений
+под iOS и OS X. Разработанный, чтобы сосуществовать с Objective-C и
+быть более устойчивым к ошибочному коду, Swift был представлен в 2014 году на
+конференции разработчиков Apple, WWDC. Приложения на Swift собираются
+с помощью LLVM-компилятора, включенного в Xcode 6+.
+
+Официальная книга по [языку программирования Swift](https://itunes.apple.com/us/book/swift-programming-language/id881256329) от Apple доступна в iBooks.
+
+Смотрите еще [начальное руководство](https://developer.apple.com/library/prerelease/ios/referencelibrary/GettingStarted/RoadMapiOS/index.html) Apple, которое содержит полное учебное пособие по Swift.
+
+```swift
+// Версия Swift: 3.0
+
+// импорт модуля
+import UIKit
+
+//
+// MARK: Основы
+//
+
+// Xcode поддерживает маркеры, чтобы давать примечания своему коду
+// и вносить их в список обозревателя (Jump Bar)
+// MARK: Метка раздела
+// MARK: - Метка с разделителем
+// TODO: Сделайте что-нибудь вскоре
+// FIXME: Исправьте этот код
+
+// Начиная со второй версии Swift, println и print объединены в методе print.
+// Перенос строки теперь добавляется в конец автоматически.
+print("Привет, мир!") // println – теперь просто print
+print("Привет, мир!", terminator: "") // вывод текста без переноса строки
+
+// переменные (var), значение которых можно изменить после инициализации
+// константы (let), значение которых нельзя изменить после инициализации
+
+var myVariable = 42
+let øπΩ = "значение" // именование переменной символами unicode
+let π = 3.1415926
+let convenience = "Ключевое слово" // контекстное имя переменной
+let weak = "Ключевое слово"; let override = "еще ключевое слово" // операторы
+ // могут быть отделены точкой с запятой
+let `class` = "Ключевое слово" // обратные апострофы позволяют использовать
+ // ключевые слова в именовании переменных
+let explicitDouble: Double = 70
+let intValue = 0007 // 7
+let largeIntValue = 77_000 // 77000
+let label = "некоторый текст " + String(myVariable) // Приведение типа
+let piText = "Pi = \(π), Pi 2 = \(π * 2)" // Вставка переменных в строку
+
+// Сборка особых значений
+// используя ключ -D сборки конфигурации
+#if false
+ print("Не печатается")
+ let buildValue = 3
+#else
+ let buildValue = 7
+#endif
+print("Значение сборки: \(buildValue)") // Значение сборки: 7
+
+/*
+ Опционалы - это особенность языка Swift, которая допускает вам сохранять
+ `некоторое` или `никакое` значения.
+
+ Язык Swift требует, чтобы каждое свойство имело значение, поэтому даже nil
+ должен быть явно сохранен как опциональное значение.
+
+ Optional<T> является перечислением.
+*/
+var someOptionalString: String? = "опционал" // Может быть nil
+// как и выше, только ? - это постфиксный оператор (синтаксический сахар)
+var someOptionalString2: Optional<String> = "опционал"
+
+if someOptionalString != nil {
+ // я не nil
+ if someOptionalString!.hasPrefix("opt") {
+ print("содержит префикс")
+ }
+
+ let empty = someOptionalString?.isEmpty
+}
+someOptionalString = nil
+
+/*
+Использование ! для доступа к несуществующему опциональному значению генерирует
+рантайм ошибку. Всегда проверяйте, что опционал содержит не пустое значение,
+перед тем как раскрывать его через !.
+*/
+
+// неявная развертка опциональной переменной
+var unwrappedString: String! = "Ожидаемое значение."
+// как и выше, только ! - постфиксный оператор (с еще одним синтаксическим сахаром)
+var unwrappedString2: ImplicitlyUnwrappedOptional<String> = "Ожидаемое значение."
+
+// If let конструкции -
+// If let это специальная конструкция в Swift, которая позволяет проверить Optional
+// справа от `=` непустой, и если это так - разворачивает его и присваивает левой части.
+if let someOptionalStringConstant = someOptionalString {
+ // имеется некоторое (`Some`) значение, не `nil`
+ if !someOptionalStringConstant.hasPrefix("ok") {
+ // нет такого префикса
+ }
+}
+
+// Swift поддерживает сохранение значения любого типа
+// Для этих целей есть два ключевых слова `Any` и `AnyObject`
+// AnyObject == id
+// `Any` же, в отличие от `id` в Objective-C, `Any` работает с любым значением (Class, Int, struct и т.д.)
+var anyVar: Any = 7
+anyVar = "Изменять значение на строку не является хорошей практикой, но возможно."
+let anyObjectVar: AnyObject = Int(1) as NSNumber
+
+/*
+ Комментируйте здесь
+
+ /*
+ Вложенные комментарии тоже поддерживаются
+ */
+*/
+
+//
+// MARK: Коллекции
+//
+
+/*
+ Массив (Array) и словарь (Dictionary) являются структурами (struct). Так
+ `let` и `var` также означают, что они изменяются (var) или не изменяются (let)
+ при объявлении переменных этих типов.
+*/
+
+// Массив
+var shoppingList = ["сом", "вода", "лимоны"]
+shoppingList[1] = "бутылка воды"
+let emptyArray = [String]() // let == неизменный
+let emptyArray2 = Array<String>() // как и выше
+var emptyMutableArray = [String]() // var == изменяемый
+var explicitEmptyMutableStringArray: [String] = [] // так же как и выше
+
+
+// Словарь
+var occupations = [
+ "Malcolm": "Капитан",
+ "kaylee": "Техник"
+]
+occupations["Jayne"] = "Связи с общественностью"
+let emptyDictionary = [String: Float]() // let == неизменный
+let emptyDictionary2 = Dictionary<String, Float>() // как и выше
+var emptyMutableDictionary = [String: Float]() // var == изменяемый
+var explicitEmptyMutableDictionary: [String: Float] = [:] // то же
+
+
+//
+// MARK: Поток управления
+//
+
+// С помощью "," можно указать дополнительные условия для раскрытия
+// опциональных значений.
+let someNumber = Optional<Int>(7)
+if let num = someNumber, num > 3 {
+ print("Больше 3х")
+}
+
+// цикл for для массива
+let myArray = [1, 1, 2, 3, 5]
+for value in myArray {
+ if value == 1 {
+ print("Один!")
+ } else {
+ print("Не один!")
+ }
+}
+
+// цикл for для словаря
+var dict = ["один": 1, "два": 2]
+for (key, value) in dict {
+ print("\(key): \(value)")
+}
+
+// цикл for для диапазона чисел
+for i in -1...shoppingList.count {
+ print(i)
+}
+shoppingList[1...2] = ["бифштекс", "орехи пекан"]
+// используйте ..< для исключения последнего числа
+
+// цикл while
+var i = 1
+while i < 1000 {
+ i *= 2
+}
+
+// цикл do-while
+repeat {
+ print("привет")
+} while 1 == 2
+
+// Переключатель
+// Очень мощный оператор, представляйте себе операторы `if` с синтаксическим
+// сахаром
+// Они поддерживают строки, объекты и примитивы (Int, Double, etc)
+let vegetable = "красный перец"
+switch vegetable {
+case "сельдерей":
+ let vegetableComment = "Добавьте немного изюма, имитируя муравьев на бревнышке."
+case "огурец", "кресс-салат":
+ let vegetableComment = "Было бы неплохо сделать бутерброд с чаем."
+case let localScopeValue where localScopeValue.hasSuffix("перец"):
+ let vegetableComment = "Это острый \(localScopeValue)?"
+default: // обязательный (чтобы предусмотреть все возможные вхождения)
+ let vegetableComment = "В супе все овощи вкусные."
+}
+
+
+//
+// MARK: Функции
+//
+
+// Функции являются типом первого класса, т.е. они могут быть вложены в функциях
+// и могут передаваться между собой
+
+// Функция с документированным заголовком Swift (формат Swift-модифицированный Markdown)
+
+/**
+ Операция приветствия
+
+ - Маркер в документировании
+ - Еще один маркер в документации
+
+ - Parameter name : Это имя
+ - Parameter day : Это день
+ - Returns : Строка, содержащая значения name и day.
+*/
+func greet(name: String, day: String) -> String {
+ return "Привет \(name), сегодня \(day)."
+}
+greet(name: "Боб", day: "вторник")
+
+// как и выше, кроме обращения параметров функции
+func greet2(name: String, externalParamName localParamName: String) -> String {
+ return "Привет \(name), сегодня \(localParamName)"
+}
+greet2(name: "Иван", externalParamName: "Воскресенье")
+
+// Функция, которая возвращает множество элементов в кортеже
+func getGasPrices() -> (Double, Double, Double) {
+ return (3.59, 3.69, 3.79)
+}
+let pricesTuple = getGasPrices()
+let price = pricesTuple.2 // 3.79
+// Пропускайте значения кортежей с помощью подчеркивания _
+let (_, price1, _) = pricesTuple // price1 == 3.69
+print(price1 == pricesTuple.1) // вывод: true
+print("Цена газа: \(price)")
+
+// Именованные параметры кортежа
+func getGasPrices2() -> (lowestPrice: Double, highestPrice: Double, midPrice: Double) {
+ return (1.77, 37.70, 7.37)
+}
+let pricesTuple2 = getGasPrices2()
+let price2 = pricesTuple2.lowestPrice
+let (_, price3, _) = pricesTuple2
+print(pricesTuple2.highestPrice == pricesTuple2.1) // вывод: true
+print("Самая высокая цена за газ: \(pricesTuple2.highestPrice)")
+
+// guard утверждения
+func testGuard() {
+ // guards обеспечивают прерывание дальнейшего выполнения функции,
+ // позволяя держать обработчики ошибок рядом с проверкой условия
+ // Объявляемая переменная находится в той же области видимости, что и guard.
+ guard let aNumber = Optional<Int>(7) else {
+ return
+ }
+
+ print("число равно \(aNumber)")
+}
+testGuard()
+
+// Переменное число аргументов
+func setup(numbers: Int...) {
+ // это массив
+ let number = numbers[0]
+ let argCount = numbers.count
+}
+
+// Передача и возврат функций
+func makeIncrementer() -> ((Int) -> Int) {
+ func addOne(number: Int) -> Int {
+ return 1 + number
+ }
+ return addOne
+}
+var increment = makeIncrementer()
+increment(7)
+
+// передача по ссылке
+func swapTwoInts(a: inout Int, b: inout Int) {
+ let tempA = a
+ a = b
+ b = tempA
+}
+var someIntA = 7
+var someIntB = 3
+swapTwoInts(a: &someIntA, b: &someIntB)
+print(someIntB) // 7
+
+
+//
+// MARK: Замыкания
+//
+var numbers = [1, 2, 6]
+
+// Функции - это частный случай замыканий ({})
+
+// Пример замыкания.
+// `->` отделяет аргументы и возвращаемый тип
+// `in` отделяет заголовок замыкания от тела замыкания
+numbers.map({
+ (number: Int) -> Int in
+ let result = 3 * number
+ return result
+})
+
+// Когда тип известен, как и выше, мы можем сделать так
+numbers = numbers.map({ number in 3 * number })
+// Или даже так
+//numbers = numbers.map({ $0 * 3 })
+
+print(numbers) // [3, 6, 18]
+
+// Хвостовое замыкание
+numbers = numbers.sorted { $0 > $1 }
+
+print(numbers) // [18, 6, 3]
+
+// Суперсокращение, поскольку оператор < выполняет логический вывод типов
+
+numbers = numbers.sorted(by: <)
+
+print(numbers) // [3, 6, 18]
+
+//
+// MARK: Структуры
+//
+
+// Структуры и классы имеют очень похожие характеристики
+struct NamesTable {
+ let names: [String]
+
+ // Пользовательский индекс
+ subscript(index: Int) -> String {
+ return names[index]
+ }
+}
+
+// У структур автогенерируемый (неявно) инициализатор
+let namesTable = NamesTable(names: ["Иван", "Яков"])
+let name = namesTable[1]
+print("Имя :\(name)") // Имя: Яков
+
+//
+// MARK: Обработка ошибок
+//
+
+// Протокол `Error` используется для перехвата выбрасываемых ошибок
+enum MyError: Error {
+ case badValue(msg: String)
+ case reallyBadValue(msg: String)
+}
+
+// фунции помеченные словом `throws` должны вызываться с помощью `try`
+func fakeFetch(value: Int) throws -> String {
+ guard 7 == value else {
+ throw MyError.reallyBadValue(msg: "Действительно плохое значение")
+ }
+
+ return "тест"
+}
+
+func testTryStuff() {
+ // предполагается, что не будет выброшено никаких ошибок,
+ // в противном случае мы получим рантайм исключение
+ let _ = try! fakeFetch(value: 7)
+
+ // Если возникает ошибка, то выполнение продолжится. Но если значение равно nil,
+ // то результат будет опционалом
+ let _ = try? fakeFetch(value: 7)
+
+ do {
+ // обычно try оператор, позволяющий обработать ошибку в `catch` блоке
+ try fakeFetch(value: 1)
+ } catch MyError.badValue(let msg) {
+ print("Ошибка: \(msg)")
+ } catch {
+ // все остальное
+ }
+}
+testTryStuff()
+
+//
+// MARK: Классы
+//
+
+// Классы, структуры и их члены имеют трехуровневый контроль доступа
+// Уровни: internal (по умолчанию), public, private
+
+public class Shape {
+ public func getArea() -> Int {
+ return 0
+ }
+}
+
+// Все методы и свойства класса являются открытыми (public).
+// Если вам необходимо содержать только данные
+// в структурированном объекте, вы должны использовать `struct`
+
+internal class Rect: Shape {
+ var sideLength: Int = 1
+
+ // Пользовательский сеттер и геттер
+ private var perimeter: Int {
+ get {
+ return 4 * sideLength
+ }
+ set {
+ // `newValue` - неявная переменная, доступная в сеттере
+ sideLength = newValue / 4
+ }
+ }
+
+ // Вычисляемые свойства должны быть объявлены с помощью `var`, ведь они могут меняться
+ var smallestSideLength: Int {
+ return self.sideLength - 1
+ }
+
+ // Ленивая загрузка свойства
+ // свойство subShape остается равным nil (неинициализированным),
+ // пока не вызовется геттер
+ lazy var subShape = Rect(sideLength: 4)
+
+ // Если вам не нужны пользовательские геттеры и сеттеры,
+ // но все же хотите запустить код перед и после вызовов геттера или сеттера
+ // свойств, вы можете использовать `willSet` и `didSet`
+ var identifier: String = "defaultID" {
+ // аргумент у `willSet` будет именем переменной для нового значения
+ willSet(someIdentifier) {
+ print(someIdentifier)
+ }
+ }
+
+ init(sideLength: Int) {
+ self.sideLength = sideLength
+ // последним всегда вызывается super.init, когда init с параметрами
+ super.init()
+ }
+
+ func shrink() {
+ if sideLength > 0 {
+ sideLength -= 1
+ }
+ }
+
+ override func getArea() -> Int {
+ return sideLength * sideLength
+ }
+}
+
+// Простой класс `Square` наследует `Rect`
+class Square: Rect {
+ convenience init() {
+ self.init(sideLength: 5)
+ }
+}
+
+var mySquare = Square()
+print(mySquare.getArea()) // 25
+mySquare.shrink()
+print(mySquare.sideLength) // 4
+
+// преобразование объектов
+let aShape = mySquare as Shape
+
+// сравнение экземпляров, в отличие от ==, которая проверяет эквивалентность
+if mySquare === mySquare {
+ print("Ага, это mySquare")
+}
+
+// Опциональная инициализация (init)
+class Circle: Shape {
+ var radius: Int
+ override func getArea() -> Int {
+ return 3 * radius * radius
+ }
+
+ // Поместите постфиксный знак вопроса после `init` - это и будет опциональная инициализация,
+ // которая может вернуть nil
+ init?(radius: Int) {
+ self.radius = radius
+ super.init()
+
+ if radius <= 0 {
+ return nil
+ }
+ }
+}
+
+var myCircle = Circle(radius: 1)
+print(myCircle?.getArea()) // Optional(3)
+print(myCircle!.getArea()) // 3
+var myEmptyCircle = Circle(radius: -1)
+print(myEmptyCircle?.getArea()) // "nil"
+if let circle = myEmptyCircle {
+ // не будет выполняться, поскольку myEmptyCircle равен nil
+ print("circle не nil")
+}
+
+
+//
+// MARK: Перечисления
+//
+
+// Перечисления могут быть определенного или своего типа.
+// Они могут содержать методы подобно классам.
+
+enum Suit {
+ case spades, hearts, diamonds, clubs
+ func getIcon() -> String {
+ switch self {
+ case .spades: return "♤"
+ case .hearts: return "♡"
+ case .diamonds: return "♢"
+ case .clubs: return "♧"
+ }
+ }
+}
+
+// Значения перечислений допускают сокращенный синтаксис, нет необходимости
+// указывать тип перечисления, когда переменная объявляется явно
+var suitValue: Suit = .hearts
+
+// Значения нецелочисленных перечислений должны быть указаны явно
+// или могут выводится с помощью функции `rawValue` из имени
+enum BookName: String {
+ case john
+ case luke = "Лука"
+}
+print("Имя: \(BookName.john.rawValue)")
+
+// Перечисление (enum) со связанными значениями
+enum Furniture {
+ // Связать с типом Int
+ case desk(height: Int)
+ // Связать с типами String и Int
+ case chair(String, Int)
+
+ func description() -> String {
+ switch self {
+ case .desk(let height):
+ return "Письменный стол высотой \(height) см."
+ case .chair(let brand, let height):
+ return "Стул марки \(brand) высотой \(height) см."
+ }
+ }
+}
+
+var desk: Furniture = .desk(height: 80)
+print(desk.description()) // "Письменный стол высотой 80 см."
+var chair = Furniture.chair("Foo", 40)
+print(chair.description()) // "Стул марки Foo высотой 40 см."
+
+
+//
+// MARK: Протоколы
+//
+
+// `protocol` может потребовать, чтобы у соответствующих типов
+// были определенные свойства экземпляра, методы экземпляра, тип методов,
+// операторы и индексы.
+
+protocol ShapeGenerator {
+ var enabled: Bool { get set }
+ func buildShape() -> Shape
+}
+
+// Протоколы, объявленные с @objc, допускают необязательные функции,
+// которые позволяют вам проверять на соответствие. Для функций также необходимо указать @objc
+@objc protocol TransformShape {
+ @objc optional func reshape()
+ @objc optional func canReshape() -> Bool
+}
+
+class MyShape: Rect {
+ var delegate: TransformShape?
+
+ func grow() {
+ sideLength += 2
+
+ // Размещайте знак вопроса перед опционным свойством, методом
+ // или индексом, чтобы не учитывать nil-значение и возвратить nil
+ // вместо выбрасывания ошибки выполнения (т.н. "опционная цепочка")
+ if let reshape = self.delegate?.canReshape?(), reshape {
+ // проверка делегата на выполнение метода
+ self.delegate?.reshape?()
+ }
+ }
+}
+
+
+//
+// MARK: Прочее
+//
+
+// `extension`s: Добавляет расширенный функционал к существующему типу
+
+// Класс Square теперь "соответствует" протоколу `CustomStringConvertible`
+extension Square: CustomStringConvertible {
+ var description: String {
+ return "Площадь: \(self.getArea()) - ID: \(self.identifier)"
+ }
+}
+
+print("Объект Square: \(mySquare)")
+
+// Вы также можете расширить встроенные типы
+extension Int {
+ var customProperty: String {
+ return "Это \(self)"
+ }
+
+ func multiplyBy(num: Int) -> Int {
+ return num * self
+ }
+}
+
+print(7.customProperty) // "Это 7"
+print(14.multiplyBy(num: 3)) // 42
+
+// Обобщения: Подобно языкам Java и C#. Используйте ключевое слово `where`,
+// чтобы определить условия обобщений.
+
+func findIndex<T: Equatable>(array: [T], valueToFind: T) -> Int? {
+ for (index, value) in array.enumerated() {
+ if value == valueToFind {
+ return index
+ }
+ }
+ return nil
+}
+let foundAtIndex = findIndex(array: [1, 2, 3, 4], valueToFind: 3)
+print(foundAtIndex == 2) // вывод: true
+
+// Операторы:
+// Пользовательские операторы могут начинаться с символов:
+// / = - + * % < > ! & | ^ . ~
+// или
+// Unicode- знаков математики, символов, стрелок, декорации и линий/кубов,
+// нарисованных символов.
+prefix operator !!!
+
+// Префиксный оператор, который утраивает длину стороны, когда используется
+prefix func !!! (shape: inout Square) -> Square {
+ shape.sideLength *= 3
+ return shape
+}
+
+// текущее значение
+print(mySquare.sideLength) // 4
+
+// Используя пользовательский оператор !!!, изменится длина стороны
+// путем увеличения размера в 3 раза
+!!!mySquare
+print(mySquare.sideLength) // 12
+
+// Операторы также могут быть обобщенными
+infix operator <->
+func <-><T: Equatable> (a: inout T, b: inout T) {
+ let c = a
+ a = b
+ b = c
+}
+
+var foo: Float = 10
+var bar: Float = 20
+
+foo <-> bar
+print("foo это \(foo), bar это \(bar)") // "foo = 20.0, bar = 10.0"
+```