Swift язык программирования для чего. Swift

, watchOS , tvOS , Linux

Swift - (произносится [ swɪft ])мультипарадигменный объектно-ориентированный язык программирования, созданный компанией Apple для разработчиков iOS , OS X , watchOS и tvOS . Swift работает с фреймворками Cocoa и Cocoa Touch и совместим с основной кодовой базой Apple, написанной на Objective-C .

История

8 июня 2015 года компания Apple объявила о выпуске новой версии Swift 2.0, которая получила более высокую производительность, новое API обработки ошибок, улучшения синтаксиса языка, а также функцию проверки доступности функций Swift для целевых ОС. Новый улучшенный компилятор и стандартные библиотеки будут выпущены под операционные системы OS X, iOS и Linux и приобретут статус Open Source

Описание

Swift берет довольно многое из Objective-C , однако он определяется не указателями, а типами переменных, которые обрабатывает компилятор. По аналогичному принципу работают многие скриптовые языки. В то же время, он предоставляет разработчикам многие функции, которые прежде были доступны в C++ и Java , такие как определяемые наименования, так называемые обобщения и перегрузка операторов.

Часть функций языка выполняется быстрее по сравнению с другими подобными языками. Например, сортировка комплексных объектов выполняется в 3,9 раз быстрее, чем в Python , и почти в 1,5 раза быстрее, чем в Objective-C .

Код, написанный на Swift, может работать вместе с кодом, написанном на языках программирования , C++ и Objective-C в рамках одного и того же проекта.

Типы, переменные, области видимости

Пример кода, выполняющего конкатенацию 2-х строк.

var str = "hello," str += " world"

Swift поддерживает 3 уровня доступа: public, internal и private.

Опциональные типы и цепочки вызовов

Важной особенностью в Swift являются опциональные типы, которые позволяют обрабатывать ссылки и значения по образцу, сходному в , в котором указатель может ссылаться на значение или иметь значение null. Это означает, что неопциональные типы не могут выдать ошибку "указатель на null", поскольку компилятор устраняет такую возможность.

Сущность цепочки вызовов заключается в вызове нескольких связанных методов. Например:

let aTenant = aBuilding . TenantList [ 5 ] let theirLease = aTenant . leaseDetails let leaseStart = theirLease . startDate

Можно сократить:

let leaseStart = aBuilding . TenantList [ 5 ] ? . leaseDetails ? . startDate

Типы значений

В отличии от большинства объектно-ориентированных языков, Swift предлагает встроенную поддержку по передаче данных, и по ссылке, и по значению. В случае ссылки используются классы, в случае со значением используются структуры. При этом структур имеют всё те же программные механизмы, такие как методы, реализации протоколов. Тем не менее, структуры не допускают наследование.

Программист имеет право выбрать любую из этих двух семантик при реализации структур данных. Например при выборе больших структур программист может их реализовать как классы. А маленькие структуры данных (например 2D точка) можно реализовать в виде структуры, передаваемой по значению, таким образом получая данные без перехода по указателю. Преимущество Swift заключается в том, что по умолчанию он передаёт такие типы данных как Int и Double по значению, а такие как String и Array по ссылке. Такой подход может дать сильный выигрыш в производительности приложений.

Протокол-ориентированное программирование

Swift использует протоколы, которые в общем случае известны как интерфейсы.

Например можно объявить протокол SupportsToString, который будет гарантировать, что объекты, соответствующие этому протоколу, будут реализовывать метод toString. Код протокола будет выглядеть:

protocol SupportsToString { func toString () -> String }

Теперь можно реализовать этот протокол по отношению к классу String без доступа к базовому классу:

extension String : SupportsToString { func toString () -> String { return self } }

Библиотеки, разработка и выполнение

Swift использует ту же среду исполнения что и Objective-C , однако требует iOS 7 / OS X 10.9 или выше. Код Swift может быть использован вместе с кодом Objective-C , а при наличии расширений и с и C++ .

Чтобы помочь разработчикам при повторном использовании уже существующего кода, Xcode 6 предлагает полуавтоматическую систему которая привязку заголовочных файлов "bridging header" чтобы предоставить коду Swift доступ к коду Objective-C .

Управление памятью

Swift использует автоматический подсчёт ссылок (АПС) для управления памятью. Apple потребовалось ручное управление при использовании Objective-C , однако представленный в 2011 году АПС обеспечил более простое выделение и очищение памяти.

Отладка и прочее

Ключевым элементом системы Swift является возможность отчётливо отлаживать и выполнять код с помощью среды разработки, используя принцип Read-eval-print loop (REPL). Согласно этому принципу пользователь вводит выражение (read), система его вычисляет (eval) и выводит пользователю (print), а затем всё повторяется (loop). Таким образом REPL действует согласно принципу "песочницы". "Песочницы" - это интерактивные представления, выполняемые в среде Xcode, которые отвечают на запросы "на лету". Если время запроса превысит время ожидания по отношению к текущему запросу, то можно использовать график для демонстрации результата.

Сходства с C

  • Большинство операторов в Swift пришли из C, несмотря на несколько новых.
  • Фигурные скобки группируют выражения.
  • Переменные присваивают значение по знаку равенства а сравниваются по двойному знаку равенства. Новый оператор === проверяет указывают ли 2 ссылки на один и тот же объект.
  • Операторы for, while, if, switch используются похожим образом, однако новые операторы вроде for in итерирует только по коллекциям, а switch может брать нецелые значения.

Сходства с Objective-C

  • Основные численные типы (Int, UInt, Float, Double).
  • Квадратные скобки используются в массивах и для объявления и для получения элемента по индексу.
  • Методы классов наследуются как и методы экземпляров. Ссылка self в методах класса указывает на класс, в котором был вызван метод.

Отличия от Objective-C

  • Выражения не нуждаются в терминирующем символе (;), хотя они нужны при записи нескольких выражений на одной строке.
  • Нет необходимости в заголовочных файлах.
  • Использование вывода типов.
  • Обобщённое программирование.
  • Функции являются объектами первого класса.
  • Перечисление пунктов может включать алгебраический тип данных.
  • Операторы могут быть переопределены для классов, а также можно создать новые операторы.
  • Строки полностью поддерживают Unicode . Большинство символов Unicode могут быть использованы в идентификаторах и операторах.
  • До Swift 2.0 отсутствовала обработка исключений (хотя оно могла быть эмулирована замыканий).
  • Поведение нескольких известных потенциальных ошибок изменено:
    • Указатели по умолчанию не являются открытыми. Программисту не нужно отслеживать и помечать имена для ссылки или перехода по ссылке.
    • Присвоения не возвращают значения. Это предотвращает известную ошибку написания i=0 вместо i == 0 при компиляции.
    • Не нужно использовать break в конце блоков switch . В общем случае нет перехода к следующему блоку за исключением случая с использованием fallthrough .
    • Переменные и константы всегда инициализированы и границы массивов всегда проверяются.
    • Переполнения целого, вызывающие неопределённое поведение отслеживаются во время исполнения кода в Swift. Программист может разрешить переполнение с помощью операторов &+ , &- , &* , &/ или &% . Свойства min и max определены для всех типов и могут быть использованы для проверки потенциальных переполнений вместо того чтобы использовать константы из внешних библиотек.

Пример кода

// this is a single line comment using two slashes. /* this is also a comment, but written over multiple lines */ /* multiline comments /* can be nested! */ Therefore you can block out code containing multiline comments */ // Swift variables are declared with "var" // this is followed by a name, a type, and a value var explicitDouble : Double = 70 // If the type is omitted, Swift will infer it from // the variable"s initial value var implicitInteger = 70 var implicitDouble = 70.0 var 國 = "美國" // Swift constants are declared with "let" // followed by a name, a type, and a value let numberOfBananas : Int = 10 // Like variables, if the type of a constant is omitted, // Swift will infer it from the constant"s value let numberOfApples = 3 let numberOfOranges = 5 // Values of variables and constants can both be // interpolated in strings as follows let appleSummary = "I have \(numberOfApples) apples." let fruitSummary = "I have \(numberOfApples + numberOfOranges) pieces of fruit." // In "playgrounds", code can be placed in the global scope print ("Hello, world" ) // This is an array variable var fruits = [ "mango" , "kiwi" , "avocado" ] // Example of an if statement; .isEmpty, .count if fruits . isEmpty { print ("No fruits in my array." ) } else { print ("There are \(fruits.count) items in my array" ) } // Define a dictionary with four items: // Each item has a person"s name and age let people = [ "Anna" : 67 , "Beto" : 8 , "Jack" : 33 , "Sam" : 25 ] // Now we use Swift"s flexible enumerator system // to extract both values in a single loop for (name , age ) in people { print ("\(name) is \(age) years old." ) } // Functions and methods are both declared with the // "func" syntax, and the return type is specified with -> func sayHello (personName : String ) -> String { let greeting = "Hello, \(personName)!" return greeting } // prints "Hello, Dilan!" print (sayHello ("Dilan" )) // Parameter names can be made external and required // for calling. // The external name can be the same as the parameter // name by prefixing with an octothorpe (#) // - or it can be defined separately. func sayAge(#personName: String, personAge age: Int) -> String { let result = "\(personName) is \(age) years old." return result } // We can also specify the name of the parameter print(sayAge(personName: "Dilan", personAge: 42))

miden16 10 июня 2014 в 13:06

Язык программирования Swift. Русская версия

  • Разработка под iOS ,
  • Swift

Привет, Хабр! 2 июня все мы воочию могли наблюдать, как компания Apple начала творить революцию в стане Objective-C разработчиков, представив миру свой новый язык программирования – Swift. Вместе с этим, она выложила в открытый доступ небольшую документацию по языку, которую мы решили перевести, если на то будет спрос. Предлагаем вашему вниманию перевод первой главы. Если тема будет интересна, то мы продолжим публиковать перевод каждую неделю.

Language guide
The Basics
Basic Operators
String and Characters
Collection Types
Control Flow
Functions
Closures
Enumerations
Classes and Structures
Properties
Methods
Subscripts
Inheritance
Initialization
Deinitialization
Automatic Reference Counting
Optional Chaining
Type Casting
Nested Types
Extensions
Protocols
Generics
Advanced Operators

Language Reference
About the Language Reference
Lexical Structure
Types
Expressions
Statements
Declarations
Attributes
Patterns
Generic Parameters and Arguments
Summary of the Grammar
Trademarks

Добро пожаловать в Swift

О языке Swift
Swift – это новый язык программирования для разработки iOS и OS X приложений, который сочетает в себе все лучшее от C и Objective-C, но лишен ограничений, накладываемых в угоду совместимости с C. В Swift используются паттерны безопасного программирования и добавлены современные функции, превращающие создание приложения в простой, более гибкий и увлекательный процесс. Swift, созданый нами с чистого листа, – это возможность заново представить себе, как разрабатываются приложения.

Swift разрабатывался нами несколько лет. Основой нового языка программирования послужили существующие компилятор, отладчик и фреймворки. Мы упростили процесс управления памятью с помощью механизма автоматического подсчета ссылок – Automatic Reference Counting (ARC). Наши фреймворки также подверглись серьезной модернизации. Objective-C начал поддерживать блоки, литералы и модули – все это создало благоприятные условия для внедрения современных технологий. Именно эта подготовительная работа послужила фундаментом для нового языка программирования, который будет применяться для разработки будущих программных продуктов для Apple.

Разработчикам Objective-C Swift покажется знакомым. Он сочетает в себе читабельность именованных параметров и мощь динамической объектной модели Objective-C. Он открывает доступ к уже существующим фреймворкам Cocoa и совместим с кодом, написанным на Objective-C. Построенный на этой общей основе язык предлагает множество новых возможностей и унифицирует процедурные и объектно-ориентированные аспекты языка программирования.

Swift не отпугнет и начинающих программистов. Это первый мощный язык программирования, такой же понятный и увлекательный, как скриптовый язык. Он поддерживает так называемые playground-ы, которые позволяют программистам экспериментировать с кодом, видя результат в режиме реального времени без необходимости компилировать и запускать приложение.

Swift вобрал в себя все лучшее от современных языков и разработан с учетом обширного опыта компании Apple. Наш компилятор – синоним производительности, наш язык оптимизирован для разработки без оглядки на компромиссы. Он спроектирован таким образом, чтобы вы смогли легко разработать и ваше первое приложение «hello, world!», и даже целую операционную систему. Все это делает Swift важным инструментом для разработчиков и для самой компании Apple.

Swift – это новый фантастический способ создавать приложения для iOS и OS X, и мы продолжим развивать его, добавляя новый функционал и представляя новые возможности. Наша цель – амбициозна. И мы с нетерпением ждем, чтобы увидеть, что вы сумеете создать при помощи него.

Введение в Swift
По давней традиции первая программа на новом языке должна выводить на экран слова “Hello, world” . С помощью Swift это делается так:

Println("Hello, world")
Если вы когда-нибудь разрабатывали на C или Objective-C этот синтаксис должен казаться вам до боли знакомым – в Swift эта строчка кода является законченной программой. Вам больше не нужно импортировать отдельные библиотеки для обеспечения базового функционала вроде ввода/вывода в консоль или работы со строками. Код, написанный в глобальной области видимости, является точкой входа в программу, таким образом функция main больше не нужна. Также обратите внимание на отсутствие точки с запятой в конце каждой строки.

Это введение содержит достаточно информации, чтобы начать писать код на Swift. Не переживайте, если вам будет что-то непонятно – мы все детально объясним в последующих главах.

Замечание
Для лучшего понимания материала мы рекомендуем использовать режим playground в Xcode. Playground позволяет вам видеть результат сразу в процессе редактирования кода без необходимости компилировать и запускать приложение.
Простые типы данных
Используйте let для создания константы и var для создания переменной. Тип константы указывать не нужно, вы можете присвоить ей значение лишь единожды.

Var myVariable = 42 myVariable = 50 let myConstant = 42
Типы константы и переменной должны совпадать с типами присваиваемых им соответствующих значений. Однако это не означает, что вы должны напрямую указывать их тип. Компилятор автоматически определит тип константы и переменной при присваивании им значения. Так, в приведенном примере компилятор определит, что myVariable имеет целочисленный тип.

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

Let implicitInteger = 70 let inplicitDouble = 70.0 let inplicitDouble: Double = 70

Давайте поэкспериментируем
Создайте константу с типом Float и проинициализируйте ее числом 4.

Значения никогда не конвертируются в другой тип неявно. Если вам необходимо конвертировать значение в другой тип, делайте это явно:
let label = "The width is " let width = 94 let widthLabel = label + String(width)
Давайте поэкспериментируем
Попробуйте удалить явное преобразование к типу String в последней строке. Какую ошибку вы получите?

Имеется более простой способ включения значений в строки: для этого заключите выражение в скобки и поставьте перед ними обратный слэш (\). Пример:

Let apples = 3 let oranges = 5 let appleSummary = "I have \(apples) apples." let fruitSummary = "I have \(apples + oranges) pieces of fruit."

Давайте поэкспериментируем
Попробуйте использовать конструкцию \() и выведите на экран строку, включающую результат суммы двух целочисленных переменных и чье-нибудь имя.

При работе с массивами и ассоциативными массивами (словарями, dictionary) используются квадратные скобки ():

Var shoppingList = ["catfish", "water", "tulips", "blue paint"] shoppingList = "bottle of water" var occupations = [ "Malcolm": "Captain", "Kaylee": "Mechanic", ] occupations["Jayne"] = "Public Relations"
Чтобы создать пустой массив или dictionary, используйте следующий синтаксис:

Let emptyArray = String() let emptyDictionary = Dictionary()
Для создания пустых массивов и словарей используйте и [:] соответственно, – например, когда вы присваиваете новое значение переменной или передаете аргумент в функцию.

ShoppingList = // Went shopping and bought everything.

Условия и циклы
Для создания условий используются операторы if и switch , для создания циклов – for-in , for , while и do-while . При этом выделять круглыми скобками условия и инициализирующие выражения необязательно, тогда как фигурные скобки обязательны.

Let individualScores = var teamScore = 0 for score in individualScores { if score > 50 { teamScore += 3 } else { teamScore += 1 } } teamScore
Условие внутри оператора if должно быть логическим, это в частности означает, что выражение if score {…} является ошибочным, поскольку здесь нет явного сравнения (например, с нулем).

Условный оператор if можно использовать совместно с let и var для работы с константами и переменными, которые могут иметь значение nil . Такие константы и переменные называются опциональными (то есть они могут либо принимать какое-либо значение, либо быть равны nil). Чтобы создать опциональную переменную или константу добавьте знак вопроса (?) после указания типа.

Var optionalString: String? = "Hello" optionalString == nil var optionalName: String? = "John Appleseed" var greeting = "Hello!" if let name = optionalName { greeting = "Hello, \(name)" }

Давайте поэкспериментируем
Измените optionalName на nil . Что вы видите на экране? Добавьте блок else для обработки случая, когда optionalName равен nil .

Если опциональное значение равно nil , условие будет ложным и код в фигурных скобках после if выполнен не будет. В противном случае переменной greeting будет присвоено новое значение.

Оператор множественного выбора switch поддерживает внутри себя множество других операторов сравнения и не ограничен лишь простыми сравнениями:

Let vegetable = "red pepper" switch vegetable { case "celery": let vegetableComment = "Add some raisins and make ants on a log." case "cucumber", "watercress": let vegetableComment = "That would make a good tea sandwich." case let x where x.hasSuffix("pepper"): let vegetableComment = "Is it a spicy \(x)?" default: let vegetableComment = "Everything tastes good in soup." }

Давайте поэкспериментируем
Попробуйте удалить условие по умолчанию. Какую ошибку вы получите?

После выполнения подходящего блока кода, программа покидает оператор switch , не проверяя последующие условия. Таким образом вам не нужно вручную добавлять операторы прерывания (break) в конце каждого блока case .

Для перебирания элементов ассоциативного массива используйте оператор for-in совместно с указанием пары имен для каждой пары ключ-значение.

Let interestingNumbers = [ "Prime": , "Fibonacci": , "Square": , ] var largest = 0 for (kind, numbers) in interestingNumbers { for number in numbers { if number > largest { largest = number } } } largest

Давайте поэкспериментируем
Добавьте еще одну переменную, которая позволит выяснить, к какому из трех типов относится найденное максимальное число.

Оператор цикла while позволяет выполнять блок кода внутри него до тех пор, пока условие не станет ложным. Условие также может быть указано после блока, который в таком случае будет выполнен по крайней мере один раз.

Var n = 2 while n < 100 { n = n * 2 } n var m = 2 do { m = m * 2 } while m < 100 m
Оператор for можно использовать для перебора последовательности чисел с помощью двух точек (..) или с помощью инициализатора, условия и инкремента. Посмотрите, эти два цикла делают одно и то же:

Var firstForLoop = 0 for i in 0..3 { firstForLoop += i } firstForLoop var secondForLoop = 0 for var i = 0; i < 3; ++i { secondForLoop += 1 } secondForLoop
При создании цикла используйте две точки (..), если не хотите включать большее значение в диапазон, и три точки (…), чтобы включить как меньшее, так и большее значения.

Функции и замыкания.
Для объявления функций используйте ключевое слово func . Вызов функции производится через указание ее имени и списка аргументов в круглых скобках. Возвращаемый тип следует отделить от перечня формальных аргументов с помощью -> .

Func greet(name: String, day: String) -> String { return "Hello \(name), today is \(day)." } greet("Bob", "Tuesday")

Давайте поэкспериментируем
Удалите параметр day. Вместо него добавьте переменную, обозначающую наименование подаваемого на обед блюда.

Если функция возвращает множество значений, следует использовать кортеж:

Func getGasPrices() -> (Double, Double, Double) { return (3.59, 3.69, 3.79) } getGasPrices()
Функции также могут иметь неопределенное число аргументов:

Func sumOf(numbers: Int...) -> Int { var sum = 0 for number in numbers { sum += number } return sum } sumOf() sumOf(42, 597, 12)

Давайте поэкспериментируем
Напишите функцию, позволяющую находить среднее арифметическое произвольного числа своих аргументов.

Функции могут вкладываться друг в друга. Вложенная функция может обращаться к переменным, объявленным во внешней функции. Используйте вложенные функции, чтобы привести в порядок код сложной или большой функции.

Func returnFifteen() -> Int { var y = 10 func add() { y += 5 } add() return y } returnFifteen()
Функции являются объектами первого класса (first-class type), иными словами, функция в качестве свого результата может возвращать другую функцию.

Func makeIncrementer() -> (Int -> Int) { func addOne(number: Int) -> Int { return 1 + number } return addOne } var increment = makeIncrementer() increment(7)
Функция также может принимать другую функцию в качестве одного из аргументов.

Func hasAnyMatches(list: Int, condition: Int -> Bool) -> Bool { for item in list { if condition(item) { return true } } return false } func lessThanTen(number: Int) -> Bool { return number < 10 } var numbers = hasAnyMatches(numbers, lessThanTen)
Функции являются частным случаем замыканий. Вы можете создать замыкание, не указывая его имени и окружив тело замыкания фигурными скобками ({}). Для отделения аргументов и типа возвращаемого значения от тела замыкания используйте оператор in .

Numbers.map({ (number: Int) -> Int in let result = 3 * number return result })

Давайте поэкспериментируем
Перепишите замыкание таким образом, чтобы оно возвращало ноль для всех лишних чисел.

Существует несколько техник, позволяющих делать замыкания более лаконичными. Если тип замыкания априори известен (например, это callback делегата), можно опустить указание типа его параметров и/или типа возвращаемого значения. Замыкания, состоящие из единственного выражения, неявно возвращают результат этого выражения.

Numbers.map({ number in 3 * number })
В замыкании вместо указания имени переменной, вы можете использовать ее порядковый номер – это особенно полезно при написании коротких замыканий. Замыкание, являющееся последним аргументом функции, может быть передано в нее сразу после круглых скобок с перечнем остальных параметров.

Sort() { $0 > $1 }

Объекты и классы
Для создания класса используется зарезервированное слово class . Члены класса объявляются точно так же, как и обычные константы и переменные. Более того, методы класса объявляются как обычные функции.

Class Shape { var numberOfSides = 0 func simpleDescription() ->

Давайте поэкспериментируем
Добавьте константу-член класса и метод класса, принимающую ее в качестве своего аргумента.

Чтобы создать экземпляр (объект) класса, достаточно добавить круглые скобки после названия класса. Доступ к методам и членам класса осуществляется через точку.

Var shape = Shape() shape.numberOfSides = 7 var shapeDescription = shape.simpleDescription()
В этом примере мы упустили одну важную деталь – конструктор класса, метод init .

Class NamedShape { var numberOfSides: Int = 0 var name: String init(name: String) { self.name = name } func simpleDescription() -> String { return "A shape with \(numberOfSides) sides." } }
Обратите внимание, как член класса name при помощи self отделен от аргумента конструктора name . Аргументы передаются в конструктор обычным образом, как и в любой другой метод класса. Обратите внимание на то, что каждый член класса должен быть проинициализирован – либо при объявлении (как, например, numberOfSides), либо в конструкторе (как name).

Деструктор класса – метод deinit , который можно переписать в случае необходимости.

Чтобы наследовать класс от уже существующего класса, после указания имени дочернего класса следует поставить двоеточие и указать название родительского. В Swift нет никаких ограничений по обязательному наследованию какого-либо стандартного класса.

Переопределенные дочерним классом методы должны быть помечены ключевым словом override – переопределение методов без override приведет к ошибке. Компилятор также выявляет методы, маркированные override , но не переопределяющие какие-либо методы своего родительского класса.
class Square: NamedShape { var sideLength: Double init(sideLength: Double, name: String) { self.sideLength = sideLength super.init(name: name) numberOfSides = 4 } func area() -> Double { return sideLength * sideLength } override func simpleDescription() -> String { return "A square with sides of length \(sideLength)." } } let test = Square(sideLength: 5.2, name: "my test square") test.area() test.simpleDescription()

Давайте поэкспериментируем
Создайте класс Circle и наследуйте его от класса NamedShape . Конструктор класса Circle принимает два аргумента – радиус и название. Переопределите методы area и describe этого класса.

Члены класса могут также иметь собственные getter и setter .

Class EquilateralTriangle: NamedShape { var sideLength: Double = 0.0 init(sideLength: Double, name: String) { self.sideLength = sideLength super.init(name: name) numberOfSides = 3 } var perimeter: Double { get { return 3.0 * sideLength } set { sideLength = newValue / 3.0 } } override func simpleDescription() -> String { return "An equilateral triagle with sides of length \(sideLength)." } } var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle") triangle.perimeter triangle.perimeter = 9.9 triangle.sideLength
В setter -е переменной perimeter новое присваиваемое значение неявно называется newValue . Вы можете изменить название этой переменной, указав его в скобках сразу после set .

Обратите внимание на структуру конструктора класса EquilateralTriangle . Этот метод включает в себя три последовательных шага:

  1. инициализация членов дочернего класса;
  2. вызов конструктора родительского класса;
  3. изменение значений членов родительского класса.
Если вам необходимо выполнить определенный код до или после присваивания нового значения переменной, вы можете переопределить методы willSet и didSet нужным вам образом. Например, в приведенном ниже классе гарантируется, что длина стороны треугольника всегда будет равна длине стороны квадрата.

Class TriangleAndSquare { var triangle: EquilateralTriangle { willSet { square.sideLength = newValue.sideLength } } var square: Square { willSet { triangle.sideLength = newValue.sideLength } } init(size: Double, name: String) { square = Square(sideLength: size, name: name) triangle = EquilateralTriangle(sideLength: size, name: name) } } var triangleAndSquare = TriangleAndSquare(size: 10, name: "another test shape") triangleAndSquare.square.sideLength triangleAndSquare.triangle.sideLength triangleAndSquare.square = Square(sideLength: 50, name: "larger square") triangleAndSquare.triangle.sideLength
У методов классов имеется одно важное отличие от функций. Названия аргументов функции используются только в пределах этой функции, тогда как в методе класса параметры также используются при вызове этого метода (кроме первого параметра). По умолчанию метод класса имеет одинаковые названия параметров как при вызове, так и внутри себя. Однако вы можете указать другое название (в примере ниже – times), которое будет использовано только внутри этого метода. При этом для вызова этого метода необходимо использовать первое название (numberOfTimes).

Class Counter { var count: Int = 0 func incrementBy(amount: Int, numberOfTimes times: Int) { count += amount * times } } var counter = Counter() counter.incrementBy(2, numberOfTimes: 7)
При работе с опциональными значениями добавьте знак вопроса (?) перед методами, членами класса и т.д. Если значение перед знаком вопроса равно nil , все, что следует после (?) игнорируется и значение всего выражения равно nil . В противном случае выражение вычисляется обычным образом. В обоих случаях результатом всего выражения будет опциональное значение.

Let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square") let sideLength = optionalSquare?.sideLength

Перечисления и Структуры
Для создания перечислений используется ключевое слово enum . Отметим, что перечисления также могут иметь в своем составе методы.

Enum Rank: Int { case Ace = 1 case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten case Jack, Queen, King func simpleDescription() -> String { switch self { case .Ace: return "ace" case .Jack: return "jack" case .Queen: return "queen" case .King: return "king" default: return String(self.toRaw()) } } } let ace = Rank.Ace let aceRawValue = ace.toRaw()

Давайте поэкспериментируем
Напишите функцию, которая сравнивает 2 перечисления типа Rank по их значениям.

В вышеприведенном примере элементы перечисления первоначально имеют целочисленный тип, и вам достаточно указать значение только первого элемента – значения остальных элементов будут определены в соответствии с порядком их следования. В качестве исходного типа (raw value) значений элементов вы также можете выбрать строковый или вещественные типы.

Для преобразования исходного типа значения в тип перечисления используйте функции toRaw и fromRaw .

If let convertedRank = Rank.fromRaw(3) { let threeDescription = convertedRank.simpleDescription() }
Отметим, что значения элементов перечисления являются фактическими, а не просто иной записью своих исходных значений. Вообще говоря, вы можете и не указывать их исходные значения.

Enum Suit { case Spades, Hearts, Diamonds, Clubs func simpleDescription() -> String { switch self { case .Spades: return "spades" case .Hearts: return "hearts" case .Diamonds: return "diamonds" case .Clubs: return "clubs" } } } let hearts = Suit.Hearts let heartsDescription = hearts.simpleDescription()

Давайте поэкспериментируем
Добавьте метод Color , возвращающий строку “black” для Spades и Clubs и “red” для Hearts и Diamonds .

Обратите внимание на то, как осуществляется доступ к члену Hearts перечисления Suit . При присваивании значения константе hearts используется полное имя Suit.Hearts , поскольку мы явно не указываем тип этой константы. А в switch мы используем сокращенную форму.Hearts , поскольку тип значения self априори известен. Вы можете использовать сокращенную форму повсеместно, если тип переменной явно указан.

Для создания структур используется ключевое слово struct . Структуры имеют множество схожих черт с классами, включая методы и конструкторы. Одним из наиболее существенных отличий структур от классов является то, что экземпляры структур, в отличие от экземпляров классов, передаются в функции по значению (то есть предварительно создается их локальная копия), тогда как экземпляры классов передаются по ссылке.

Struct Card { var rank: Rank var suit: Suit func simpleDescription() -> String { return "The \(rank.simpleDescription()) of \(suit.simpleDescription())" } } let threeOfSpades = Card(rank: .Three, suit: .Spades) let threeOfSpadesDescription = threeOfSpades.simpleDescription()

Давайте поэкспериментируем
Добавьте в структуру Card метод, который создает полную колоду карт.

Экземпляр члена перечисления может иметь собственные значения и они могут быть разными. Вы присваиваете эти значения при создании экземпляра перечисления (константа success в примере). Связанные и исходные значения это разные вещи: исходное значение члена перечисления всегда постоянно для всех экземпляров перечисления и указывается при его объявлении.

Рассмотрим пример получения с сервера времени восхода и заката Солнца. Сервер отправляет в ответ либо соответствующую информацию, либо сообщение об ошибке.

Enum ServerResponse { case Result(String, String) case Error(String) } let success = ServerResponse.Result("6:00 am", "8:09 pm") let failure = ServerResponse.Error("Out of cheese.") switch success { case let .Result(sunrise, sunset): let serverResponse = "Sunrise is at \(sunrise) and sunset is at \(sunset)." case let .Error(error): let serverResponse = "Failure... \(error)" }

Давайте поэкспериментируем
Добавьте третий вариант в оператор множественного выбора switch

Обратите внимание, каким образом из объекта ServerResponse “вытаскиваются” время восхода и заката.
Протоколы и Расширения.
Для объявления протокола используйте ключевое слово protocol .

Protocol ExampleProtocol { var simpleDescription: String { get } mutating func adjust() }
Протоколы могут поддерживаться классами, перечислениями и структурами.

Class SimpleClass: ExampleProtocol { var simpleDescription: String = "A very simple class." var anotherProperty: Int = 69105 func adjust() { simpleDescription += " Now 100% adjusted." } } var a = SimpleClass() a.adjust() let aDescription = a.simpleDescription struct SimpleStructure: ExampleProtocol { var simpleDescription: String = "A simple structure" mutating func adjust() { simpleDescription += " (adjusted)" } } var b = SimpleStructure() b.adjust() let bDescription = b.simpleDescription

Давайте поэкспериментируем
Создайте перечисление, которое будет реализовывать этот протокол.

Обратите внимание на ключевое слово mutating в определении структуры SimpleStructure , которое информирует компилятор о том, что соответствующий метод подвергает структуру изменениям. В противовес этому методы класса SimpleClass не нужно маркировать как mutating , поскольку методы класса всегда могут беспрепятственно его изменять.

Для добавления новых методов или членов класса в уже существующий тип необходимо использовать расширения – extensions . Вы также можете использовать расширения для реализации протокола уже существующим типом, даже если он импортирован из какой-либо библиотеки или фреймворка.

Extension Int: ExampleProtocol { var simpleDescription: String { return "The number \(self)" } mutating func adjust() { self += 42 } } 7.simpleDescription

Давайте поэкспериментируем
Создайте расширение типа Double с переменной-членом absoluteValue .

Вы можете использовать название протокола как и любой другой тип – например, чтобы создать массив объектов разного типа, но реализующих общий протокол. Заметьте, что при работе с объектами такого типа методы, объявленные вне протокола, будут недоступны.

Let protocolValue: ExampleProtocol = a protocolValue.simpleDescription // protocolValue.anotherProperty // Uncomment to see the error
Несмотря на то, что во время выполнения программы переменная protocolValue имеет тип SimpleClass , компилятор считает, что ее тип – ExampleProtocol . Это означает, что вы не сможете случайно получить доступ к методам или членам класса, которые реализуются вне протокола ExampleProtocol .

Обобщенные типы (generics)
Для создания обобщенного типа, заключите имя в угловые скобки (<>).

Func repeat(item: ItemType, times: Int) -> ItemType { var result = ItemType() for i in 0..times { result += item } return result } repeat("knock", 4)
Создавайте обобщенные функции, классы, перечисления и структуры.

// Reimplement the Swift standard library"s optional type enum OptionalValue { case None case Some(T) } var possibleInteger: OptionalValue = .None possibleInteger = .Some(100)
Если вы хотите задать обобщенные типу определенные требования, такие, как, например, реализация протокола или требование быть наследованным от определенного класса, используйте where .

Func anyCommonElements (lhs: T, rhs: U) -> Bool { for lhsItem in lhs { for rhsItem in rhs { if lhsItem == rhsItem { return true } } } return false } anyCommonElements(, )

Давайте поэкспериментируем
Измените функцию anyCommonElements таким образом, чтобы она возвращала массив общих элементов.

В простых случаях вы можете опустить where и написать имя протокола или класса после двоеточия. Выражение эквивалентно выражению .

Последнее обновление: 25.12.2017

Устройства компании Apple являются признанным лидером в сфере информационных технологий. По последним данным доля iOS среди других мобильных операционных систем колеблется в районе 15-20%, а доля Mac OSX среди настольных систем составляет по разным данным 15-20%. Подобное широкое распространение устройств от компании Apple рождает потребность в программном обеспечении для этих устройств.

Традиционно основным языком программирования под iOS и MacOS был Objective-C, однако 2 июня 2014 года на конференции разработчиков Apple WWDC 2014 был представлен новый и более удобный язык программирования - Swift. По сравнению с Objective-C Swift обладает следующими особенностями:

    Swift является чистым объектно-ориентированным языком программирования

    Простота, ясный и четкий синтаксис

    Строгая типизированность. Каждая переменная имеет определенный тип

    Автоматическое управление памятью

Однако при этом Swift полностью совместим с ранее написанными прикладными интерфейсами Cocoa API, для которых использовались C и Objective-C.

При этом Swift продолжает развиваться. 19 сентября 2017 года вышла версия 4.0, которая добавила новые возможности для разработки под iOS и Mac OS. В принципе каждый год выходят новые версии.

Swift является компилируемым языком программирования. То есть разработчик пишет исходный код и затем, используя компилятор, компилирует этот код в управляющую программу. Затем этот файл программы можно загрузить в AppStore и распространять среди других пользователей.

Что нужно для разработки для iOS?

В первую очередь необходима соответствующая операционная система Mac OS 10.12 Yosemite или выше. Без Mac OS практически невозможно скомпилировать программу. Данное обстоятельство сильно ограничивает возможности разработки, учитывая тот факт, что Mac OS может гарантированно работать лишь на компьютерах самой компании Apple (iMac, MacBook, MacBook Air, MacBook Pro), а также учитывая высокую стоимость этих самых компьютеров. Однако на обычном PC под управлением ОС Windows или ОС на базе Linux создавать приложения под iOS и Mac OS практически невозможно.

Существуют также варианты с виртуальными машинами, на которые установлена Mac OS, либо использование Хакинтош, однако работоспособность подобных вариантов не гарантирована.

Есть и еще один вариант - написание кода в любой доступной операционной системе и компиляция его с помощью специальных сервисов за определенную плату иди бесплатно. Но, понятное дело, что комфортабельность подобного подхода очень низка.

Непосредственно для самой разработки нам потребуются инструменты языка Swift, текстовый редактор для написания кода, симуляторы iPhone и iPad для отладки приложения. Для всех этих и многих других функций разработки Apple предоставляет бесплатную среду разработки XCode.

Нужны ли реальные устройства iPhone или iPad для тестирования разрабатываемых приложений? По большому счету нет, так как XCode предоставляет симуляторы для тестирования, однако в некоторых отдельных случаях предпочтительнее тестировать на реальном смартфоне.

Регистрация разработчика

И также непосредственно перед тем, как приступить к созданию приложений, необходимо зарегистрироваться в центре Apple для разработчиков. Для этого надо пройти по ссылке https://developer.apple.com/register/ :

Для регистрации надо будет войти на сайт с помощью своего идентификатора Apple ID и пароля. Если вдруг такого идентификатора у вас нет, то можно создать новую учетную запись, перейдя по ссылке Create Apple ID . После регистрации сайт перенаправит на страницу , где можно найти различные материалы по разработке для самых разных аспектов.

Swift - это невероятно мощный и простой язык программирования, представленный Apple в 2014 году, благодаря которому для многих программистов открывается возможность создания приложений для iOS, MacOS, Apple TV и Apple Watch. Данный язык унаследовал идеи от Objective-C, Rust, Haskell, Ruby, Python, C# и CLU. Он использует паттерны безопасного программирования и содержит новые функции, что позволяет сделать процесс программирования увлекательным и интересным. Созданный Крисом Латтнером, он вышел надежным, быстрым и открытым языком, благодаря чему стало еще проще создавать приложения для самого популярного телефона в мире.

Swift - это современный язык программирования со стабильной релизной версией, который достаточно прост в освоении, даже если учесть, что это ваш первый язык. Он предотвращает массу ошибок на этапе компиляции, ускоряет процесс разработки и повышает качество кода.

Философия Swift

Основной философией языка является его простота, быстродействие и защищенность. Порог вхождения изменился в большую сторону, по сравнению с тем же Objective C - даже не зная каких либо других языков программирования или основ, можно смело приступать к изучению языка.

Apple максимально упростила язык для разработчиков: синтаксис стал чище, что повышает читаемость кода как опытного, так и начинающего программиста. Общее количество кода уменьшилось, в следствии чего повысилась производительность. Были полностью переработаны, переосмыслены и переписаны все методы, которые использовались в Objective C. Swift постоянно развивается и обновляется, что говорит о его надежности и нацеленности на будущее.

Где применяется Swift

Данный язык программирования разработчики используют для написания мобильных приложений для телефонов, умных часов и компьютеров компании Apple. Ходил даже слух, что Google хочет перенести Android полностью на Swift, всякое может быть. Это универсальный язык, который можно использовать в любой платформе от компании из Купертино.

Важным моментом является то, что осенью 2016 года Apple способствовала открытию центра обучения студентов, где каждый может учиться программированию приложений для iOS. Но это еще не все, в штатах Swift уже включен в учебную программу многих ведущих учебных учреждений. У этого языка программирования огромный потенциал.

Сложность обучения Swift

Swift является безопасным языком, который позволит огородить вас от большинства ошибок в процессе программирования. Он подскажет, где находится ошибка и почему не компилируется программа. Но с другой стороны, тут кроется жесткая типизация. Язык от Apple не прощает ошибок.

На данный момент существует небольшое количество документации, по сравнению с другими языками. Но это можно обусловить тем, что язык совсем недавно увидел свет и стал Open Source проектом, ведь на момент релиза его могли использовать только те разработчики, у которых была активная подписка Apple Developer Program.

Еще раньше можно было сказать, что Swift не очень популярен и для него существует малое количество сторонних библиотек и расширений, но сейчас это совершенно не так. На GitHub и просторах интернета находятся десятки отличных решений от сторонних разработчиков, которые помогут усовершенствовать Ваш проект.

Плюсы/минусы Swift

У этого современного и мощного языка программирования есть ряд преимуществ, которые выделяют его на фоне других или того же Objective-C. И это новые мощные языковые возможности, предельно строгая типизация данных, более лаконичный синтаксис, существенно более высокая производительность в операциях доступа к коллекциям (сортировка и поиск), поддержка определенного большинства современных синтаксических конструкций, существующих в других высокоуровневых языках программирования. И одной из главных особенностей Swift является то, что он имеет полную обратную совместимость с Objective-C. Таким образом это позволяет постепенно переписывать проекты с одного языка на другой, к тому же дает возможность использовать функционал Objective-C внутри самого Swift.

Одним из приятных моментов является Playground - это своего рода интерактивная песочница, где разработчик может написать код и сразу увидеть результат своих трудов. Это позволяет в несколько раз увеличить скорость написания основного когда, ведь написание отдельных кусков кода или алгоритмов теперь можно проводить в плейграунде с визуальной обратной связью, без рисков совершения ошибок в основном проекте.

Apple переработала множество вещей, благодаря чему мы получили практически новую развитую систему перечисления, эффективное управление аксессорами и оптимизированную автоматическую сборку мусора.

Темной стороной языка является его небольшая популярность и небольшая распространённость. Большинство текущих проектов написаны на Objective-C и их придется поддерживать, да и многие компании не переписывают свои большие проекты только потому, что это огромный и невероятно трудоемкий процесс.

Сопутствующие технологии

Apple совершила переход от использования статических библиотек к динамическим и добавила этот функционал в свой язык программирования, что означает его более быстрое развитие, чем самой iOS. Теперь разработчики с легкостью могут представить свое приложение вместе с написанными ими библиотеками. Раньше требовалось ждать нового релиза iOS, но теперь ситуация изменилась. Динамические библиотеки предоставляют возможность для более гибких улучшений и изменений в коде, чем когда-либо.

Swift более функциональный и доступный язык, который как и Objective-C поддерживает официальные фреймворки Cocoa и Cocoa Touch. В сети доступно множество открытых проектов, в том числе от таких крупных компаний как Airbnb, которые позволяют использовать все современные методы и решения при написании кода.

Как уже было неоднократно отмечено, в том числе и , конференция была великолепной, пусть даже на ней и не представили никакого «железа». С головой хватило одних только программных продуктов. О том, насколько общественности понравилась конференция, говорит хотя бы тот факт, что после неё не произошло традиционного для таких случаев заметного .

И в то время как большая часть из представленного была вполне ожидаема общественностью, язык программирования оказался настоящим сюрпризом. Ведь никто даже не подозревал, что Apple работает в данном направлении. Впрочем, язык программирования - это не iPad, разработки такого типа мало интересны широкой публике. А значит, соблюдать секретность было не в пример легче.

Самый секретный проект

На самом же деле работы над Swift начались ещё в 2010 году, после презентации iPad. В компании хотели создать простой, удобный и функциональный инструмент, который мог бы максимально упростить жизнь разработчикам.

Работы велись в строжайшем секрете. Более того, довольно долго над проектом трудился только один человек - Крис Латтнер (Chris Lattner), директор отдела Developer Tools. Конечно же, впоследствии штат пришлось расширить. Но всё равно, число этих людей никогда не было достаточно велико. О разработке нового языка мало кто знал даже в стенах самой Apple, хотя к 2013 году он и числился самым важным проектом Developer Tools. Важно отметить, что в компании хотели представить сразу готовый продукт, избегая всевозможных бета-версий. Поэтому работы и растянулись до 2014 года.

Тут уместно будет рассказать немного о самом Латтнере. В Apple он пришёл в 2005 году, до этого трудился на благо проекта LLVM в Университете Иллинойса, входя в число ведущих разработчиков.

LLVM (Low Level Virtual Machine) - низкоуровневая виртуальная машина, универсальная система трансформации, оптимизации и анализа программ. Проект начинался как самостоятельный, но впоследствии получил значительную поддержку со стороны. В том числе и от самой Apple, которая затем активно использовала LLVM и в собственных проектах, включая OS X и iOS. Тот же Metal разрабатывался с применением данной системы.

Не обошлось без LLVM и в случае со Swift. При помощи данной системы язык компилируется в машинный код, оптимизированный таким образом, чтобы получить максимальную отдачу, при использовании приложения на технике Apple.

В своё время переход Криса Латтнера в Apple был более чем логичным шагом. Не менее логичным было и решение доверить разработку нового языка именно ему. Пока ещё рано выносить окончательный вердикт, но, похоже, что с поставленной задачей он справился великолепно.

Особенности Swift

Детище новейших достижений, компилируемый объектно-ориентированный язык программирования Swift, опирается на такие языки, как Objective-C и C, собрав из них всё самое лучшее. Нет никаких ограничений в вопросах совместимости, языки могут прекрасно сосуществовать в одном приложении. Последнее, кстати, очень важно, поскольку уже существует огромное количество программ, написанных на Objective-C.

Интересно, что смутная идея Swift появилась ещё во времена NeXT, когда только-только начал разрабатываться Objective-C. Тогда уже родилась мысль о создании языка, который мог бы сделать процесс программирования более простым и увлекательным занятием. Но, как видим, на реализацию этой идеи потребовалось немало времени.

На самом деле, не так то легко найти ту грань, когда код будет достаточно простым для набора, но при этом достаточно читабельным для того, чтобы сторонний разработчик мог без комментариев разобраться в кусках чужой программы. Например, в программе, написанной на Pascal легко разобраться, но код получается слишком длинным. PERL позволяет записать всё в несколько строк, но отличается крайней нечитабельностью кода.

Тем временем некоторые разработчики, которые уже успели опробовать Swift на практике, утверждают, что Apple удалось максимально близко подойти к идеалу, найти ту самую золотую середину между читабельностью и простотой набора.

Как сразу же становится ясно из названия нового языка («swift» - англ. «быстрый, стремительный» ), основной упор при его создании делался на скорость. В частности заявлено, что программа на Swift будет выполняться в 1,3 раза быстрее, по сравнению с аналогичной, но написанной на Objective-C.

Также при разработке Swift учитывались такие важные параметры, как простота, безопасность и гибкость. Этот язык исключает целые классы небезопасного кода и способен автоматически управлять памятью. Swift исключает саму возможность допущения целого ряда ошибок, столь распространённых в среде начинающих программистов. Что же касается простоты, то её хорошо подтверждает тот факт, что в течение 24 часов с момента , на нём уже .

Создатели приложили немало усилий к тому, чтобы сделать код Swift более выразительным и простым для понимания. Разработчик может сразу же отслеживать результаты своего творчества, просматривая отдельные части кода в т. н. «интерактивных игровых площадках» (Interactive Playgrounds). Если же для выполнения кода требуется довольно много времени, то за процессом можно следить на специально появляющейся для этого строке обратного отчёта. После того как код был усовершенствован, а алгоритм доведён до ума, разработчик просто перемещает его в свой проект. «Игровые площадки» могут быть полезны не только с точки зрения упрощения процедуры разработки, но и для оттачивания навыков использования Swift.

Традиционное приложение «Hello, World» выглядит в Swift следующим образом:

println("Hello, world")

А вот и ещё один пример несложного кода:

let apples = 3
let oranges = 5
let appleSummary = "I have \(apples) apples."
let fruitSummary = "I have \(apples + oranges) pieces of fruit."

Критика Swift

Тем временем в Сети появляются и откровенно негативные мнения в отношении Swift. Высказываются опасения, что это тупиковый путь развития и Swift никогда не сможет стать популярным. Ведь и до этого существовало немало языков программирования, создававшихся именно с целью облегчения жизни программистов и упрощения процесса обучения. И ни один из них так до конца и не справился с возложенными на него задачами. Всё чего удалось достигнуть их создателям - просто увеличить и без того немалое количество языков программирования.

Поступает критика действий Apple, которой «лучше было бы заняться развитием таких языков, как Python или Ruby, вместо того, чтобы создавать ещё один». Такие слова подкрепляются мнением, что эти инструменты уже активно используются разработчиками со всего мира. Также мне довелось найти мнение, согласно которому Apple напрасно делает основную ставку на скорость. Мол, при современных уровнях развития железа это не так уж и важно.

Но больше всего раздражения вызывает тот факт (впрочем, как и всегда в подобных случаях), что Apple создала нечто только для себя, по своим стандартам и на своих основах. Причём заявляется, что хотя Swift и не слишком-то отличается от множества других языков, компания вновь заявляет о создании принципиально нового продукта.

Вместо послесловия

Можно критиковать Apple за чрезмерную закрытость и самонадеянность. Можно восхищаться простотой Swift и чистотой его кода. Но факт остаётся фактом - будущее нового языка программирования пока неясно. И возможны два сценария развития.

Сценарий первый. Swift так и остаётся просто интересной разработкой. Его используют, но не слишком активно, предпочитая продолжать работать с проверенным и привычным Objective-C. Разработчики же под другие платформы вообще не замечают появления нового языка.

Сценарий второй. Подходы, применённые в Swift, становятся нормой в мире программирования. Apple снова удаётся повлиять на весь мир, изменив общепринятые среди разработчиков нормы. Идея «игровых площадок», вкупе с прозрачностью кода нового языка вполне могут совершить настоящий переворот в деле изучения программирования. А это позволит полностью пересмотреть весь процесс образования и спровоцировать появление программистов нового поколения.

Кстати, я не буду удивлён, если через несколько лет, тщательно «отполировав» Swift, доведя его до совершенства, Apple заявит, что вообще намерена отказаться от Objective-C и сделать ставку на новый язык.

Пользуюсь техникой Apple еще с «классической эры», с 1995 года. За этот период застал не одну внезапную и значительную (а порой и откровенно шокирующую) «революцию» в развитии компании. Которая, несмотря ни на что не утрачивала своего очарования. Верю, что так оно будет и впредь.