Swift — это высокоуровневый многопарадигмальный компилируемый язык программирования общего назначения , созданный Крисом Латтнером в 2010 году для Apple Inc. и поддерживаемый сообществом разработчиков программного обеспечения с открытым исходным кодом . Swift компилируется в машинный код и использует компилятор на основе LLVM . Swift был впервые выпущен в июне 2014 года [11] , а набор инструментов Swift поставляется в Xcode с версии 6, выпущенной в 2014 году.
Apple намеревалась, чтобы Swift поддерживал многие основные концепции, связанные с Objective-C , в частности динамическую диспетчеризацию , широко распространенное позднее связывание , расширяемое программирование и подобные функции, но «более безопасным» способом, что упрощает обнаружение ошибок программного обеспечения ; Swift имеет функции, устраняющие некоторые распространенные ошибки программирования, такие как разыменование нулевого указателя , и предоставляет синтаксический сахар , помогающий избежать пирамиды гибели . Swift поддерживает концепцию расширяемости протокола , систему расширяемости, которая может применяться к типам, структурам и классам , которую Apple продвигает как реальное изменение в парадигмах программирования, которые они называют «протокольно-ориентированным программированием» [12] (аналогично признакам и классам типов ). [13]
Swift был представлен на Всемирной конференции разработчиков Apple 2014 года (WWDC). [14] Он был обновлен до версии 1.2 в 2014 году и значительно обновлен до Swift 2 на WWDC 2015. Изначально это был проприетарный язык , но версия 2.2 стала программным обеспечением с открытым исходным кодом под лицензией Apache License 2.0 3 декабря 2015 года для платформ Apple и Linux . [15] [16]
В версии 3.0 синтаксис Swift претерпел существенные изменения, и в более поздних версиях основная команда сосредоточилась на стабильности исходного кода. [17] [18] В первом квартале 2018 года Swift превзошел Objective-C по измеренной популярности. [19]
Swift 4.0, выпущенный в 2017 году, внес несколько изменений в некоторые встроенные классы и структуры. Код, написанный с помощью предыдущих версий Swift, можно обновить с помощью встроенной в Xcode функции миграции. Swift 5, выпущенный в марте 2019 года, представил стабильный двоичный интерфейс на платформах Apple, что позволило включить среду выполнения Swift в операционные системы Apple. Он совместим с исходным кодом Swift 4. [20]
Swift 5.1 был официально выпущен в сентябре 2019 года. Swift 5.1 основывается на предыдущей версии Swift 5, расширяя стабильные функции языка до времени компиляции с введением стабильности модуля. Введение стабильности модуля позволяет создавать и совместно использовать бинарные фреймворки, которые будут работать с будущими выпусками Swift. [21]
Swift 5.5, официально анонсированный Apple на WWDC 2021 года , значительно расширяет языковую поддержку параллелизма и асинхронного кода , в частности, представляя уникальную версию модели акторов . [22]
Swift 5.9 был выпущен в сентябре 2023 года и включает в себя макросистему, пакеты общих параметров и функции владения, такие как новый consume
оператор. [23]
Swift 5.10 был выпущен в марте 2024 года. Эта версия улучшает модель параллелизма языка, позволяя полностью изолировать данные для предотвращения гонок данных . Это также последний выпуск перед Swift 6. [24] Версия 5.10 в настоящее время доступна для macOS, Windows и Linux. [25]
Swift 6 был выпущен в сентябре 2024 года. [26]
Разработка Swift началась в июле 2010 года Крисом Латтнером , с последующим сотрудничеством многих других программистов Apple . Swift был мотивирован необходимостью замены более раннего языка программирования Objective-C от Apple , который в значительной степени не менялся с начала 1980-х годов и не имел современных языковых функций. Swift взял языковые идеи «из Objective-C , Rust , Haskell , Ruby , Python , C# , CLU и слишком многих других, чтобы перечислить». [7] 2 июня 2014 года приложение Apple Worldwide Developers Conference (WWDC) стало первым публично выпущенным приложением, написанным на Swift. [27] Бета -версия языка программирования была выпущена для зарегистрированных разработчиков Apple на конференции, но компания не обещала, что финальная версия Swift будет совместима по исходному коду с тестовой версией. Apple планировала сделать конвертеры исходного кода доступными, если это необходимо для полной версии. [27]
Язык программирования Swift , бесплатное руководство на 500 страниц, также было выпущено на WWDC и доступно в Apple Books Store и на официальном сайте. [28]
Swift достиг рубежа 1.0 9 сентября 2014 года с Gold Master of Xcode 6.0 для iOS . [29] Swift 1.1 был выпущен 22 октября 2014 года одновременно с запуском Xcode 6.1. [30] Swift 1.2 был выпущен 8 апреля 2015 года вместе с Xcode 6.3. [31] Swift 2.0 был анонсирован на WWDC 2015 и стал доступен для публикации приложений в App Store 21 сентября 2015 года. [32] Swift 3.0 был выпущен 13 сентября 2016 года. [33] Swift 4.0 был выпущен 19 сентября 2017 года. [34] Swift 4.1 был выпущен 29 марта 2018 года. [35]
Swift занял первое место в номинации «Самый любимый язык программирования» в опросе разработчиков Stack Overflow 2015 года [36] и второе место в 2016 году. [37]
3 декабря 2015 года язык Swift, поддерживающие библиотеки, отладчик и менеджер пакетов были открыты под лицензией Apache 2.0 с исключением Runtime Library Exception [38] , а для размещения проекта был создан Swift.org. Исходный код размещен на GitHub, где любой может легко получить код, собрать его самостоятельно и даже создать запросы на извлечение, чтобы внести код обратно в проект.
В декабре 2015 года IBM анонсировала свой веб-сайт Swift Sandbox, который позволяет разработчикам писать код Swift на одной панели и отображать вывод на другой. [39] [40] [41] Swift Sandbox был объявлен устаревшим в январе 2018 года. [42]
Во время WWDC 2016 Apple анонсировала эксклюзивное приложение для iPad под названием Swift Playgrounds , предназначенное для обучения людей программированию на Swift. Приложение представлено в виде трехмерного интерфейса, похожего на видеоигру , который обеспечивает обратную связь, когда строки кода размещаются в определенном порядке и выполняются. [43] [44] [45]
В январе 2017 года Крис Латтнер объявил о своем уходе из Apple ради новой должности в Tesla Motors , а руководителем проекта Swift стал ветеран команды Тед Кременек. [46] [47]
Во время WWDC 2019 компания Apple анонсировала SwiftUI с Xcode 11, который обеспечивает основу для декларативного проектирования структуры пользовательского интерфейса на всех платформах Apple. [48]
Официальные загрузки SDK и набора инструментов для дистрибутива Ubuntu Linux доступны с версии Swift 2.2, а с версии Swift 5.2.4, CentOS и Amazon Linux появилось больше дистрибутивов. [49] Также есть неофициальный пакет SDK и собственного набора инструментов для Android. [50] [51]
Swift поддерживает следующие платформы: операционные системы Apple ( Darwin , iOS , iPadOS , macOS , tvOS , watchOS ), Linux , Windows и Android . [52] [53]
Ключевым аспектом дизайна Swift является его способность взаимодействовать с огромным количеством существующего кода Objective-C, разработанного для продуктов Apple за предыдущие десятилетия, например, фреймворками Cocoa и Cocoa Touch . На платформах Apple [54] он связывается с библиотекой времени выполнения Objective-C , что позволяет запускать код C , Objective-C , C++ и Swift в одной программе. [55]
Swift — это язык программирования общего назначения, который использует современные концепции теории языков программирования и стремится представить простой, но мощный синтаксис. Swift включает в себя инновации и соглашения из различных языков программирования, с заметным вдохновением от Objective-C, который он заменил в качестве основного языка разработки на платформах Apple.
Swift был разработан, чтобы быть безопасным и дружелюбным к новым программистам, не жертвуя при этом скоростью. По умолчанию Swift автоматически управляет всей памятью и гарантирует, что переменные всегда инициализируются перед использованием. Доступ к массивам проверяется на наличие ошибок выхода за пределы, а целочисленные операции проверяются на наличие переполнения. Имена параметров позволяют создавать понятные API. Протоколы определяют интерфейсы, которые могут принимать типы, в то время как расширения позволяют разработчикам добавлять больше функций к существующим типам. Swift обеспечивает объектно-ориентированное программирование с поддержкой классов , подтипов и переопределения методов . Необязательные параметры позволяют явно и безопасно обрабатывать значения nil . Параллельные программы можно писать с использованием синтаксиса async/await , а акторы изолируют общее изменяемое состояние, чтобы исключить гонки данных. [72] [73]
Синтаксис Swift похож на языки в стиле C. Код начинает выполняться в глобальной области видимости по умолчанию. [74] В качестве альтернативы атрибут может быть применен к объявлению структуры, класса или перечисления, чтобы указать, что он содержит точку входа программы. [75]@main
Программа Swift «Hello, World!» выглядит так:
печать ( "Привет, мир!" )
Функция , используемая здесь, включена в стандартную библиотеку Swift, которая доступна всем программам без необходимости импортировать внешние модули. Операторы в Swift не обязательно должны заканчиваться точкой с запятой, однако точки с запятой требуются для разделения нескольких операторов, написанных на одной строке. Однострочные комментарии начинаются с и продолжаются до конца текущей строки. Многострочные комментарии содержатся в символах и . Константы объявляются с ключевым словом , а переменные — с ключевым словом . Значения должны быть инициализированы до того, как они будут прочитаны. Значения могут выводить свой тип на основе типа предоставленного начального значения. Если начальное значение установлено после объявления значения, тип должен быть объявлен явно. [74]print(_:separator:terminator:)
//
/*
*/
let
var
let highScoreThreshold = 1000 // Константа с типом Int. Тип был выведен на основе предоставленного значения.var currentScore = 980 // Переменная с типом Int.currentScore = 1200 // Значение переменных может меняться со временем.let playerMessage : String // Константа с явным типом String.если currentScore > highScoreThreshold { playerMessage = "Вы — лучший игрок!"} еще { playerMessage = "Удачи в следующий раз."}print ( playerMessage ) // Выводит "Вы лучший игрок!"
Поток управления в Swift управляется с помощью операторов if-else , guard и switch , а также циклов while и for-in . Операторы принимают логический параметр и выполняют тело оператора, если условие истинно, в противном случае выполняется необязательное тело. синтаксис предоставляет синтаксический сахар для проверки существования необязательного значения и его одновременной развертки.if
if
else
if-let
пусть someNumber = 42if someNumber % 2 == 0 { // Используйте оператор остатка, чтобы найти остаток от деления someNumber на 2. print ( " \( someNumber ) четное." )} еще { print ( " \( someNumber ) нечетное." )}// Печатает «42 — четное число».
Функции определяются с помощью
ключевого слова. Параметры функций могут иметь имена, которые позволяют вызовам функций читаться как фразы. Подчеркивание перед именем параметра позволяет опустить метку аргумента из места вызова. Кортежи могут использоваться функциями для возврата нескольких фрагментов данных одновременно.func
func constructGreeting ( для имени : String ) -> String { вернуть "Привет \( имя ) !"}пусть приветствие = constructGreeting ( для : "Крейг" )print ( greeting ) // Печатает "Привет, Крейг!"
Функции и анонимные функции, известные как замыкания , могут быть назначены свойствам и переданы по программе, как любое другое значение.
функция деления на два ( _ aNum : Int ) -> Int { вернуть aNum / 2}func MultipleByTwo ( _ aNum : Int ) -> Int { вернуть aNum * 2}пусть mathOperation = умножитьНаДваprint ( mathOperation ( 21 )) // Печатает "42"
операторы требуют, чтобы заданное условие было истинным, прежде чем продолжить после оператора, в противном случае выполняется guard
тело предоставленного предложения. Предложение должно выйти из-под контроля блока кода, в котором появляется оператор. операторы полезны для обеспечения выполнения определенных требований перед продолжением выполнения программы. В частности, их можно использовать для создания развернутой версии необязательного значения, которое гарантированно не равно нулю для оставшейся части охватывающей области действия.guard
else
else
guard
guard
функция деления ( числитель : Int ?, поЗнаменатель знаменатель : Int ) - > Int ? { защитный знаменатель != 0 иначе { print ( "Невозможно разделить на 0." ) вернуть ноль } охранник пусть числитель иначе { print ( «Предоставленный числитель равен нулю». ) вернуть ноль } вернуть числитель / знаменатель}пусть результат = деление ( числитель : 3 , на Знаменатель : 0 )print ( "Результат деления: \( результат ) " )// Печатает:// "Нельзя делить на 0."// "Результат деления: ноль."
switch
операторы сравнивают значение с несколькими потенциальными значениями, а затем выполняют связанный блок кода. switch
операторы должны быть исчерпывающими, либо путем включения случаев для всех возможных значений, либо путем включения default
случая, который выполняется, когда предоставленное значение не соответствует ни одному из других случаев. switch
случаи неявно не проваливаются, хотя они могут явно делать это с помощью fallthrough
ключевого слова. Сопоставление с образцом может использоваться различными способами внутри switch
операторов. Вот пример целого числа, сопоставляемого с рядом потенциальных диапазонов:
пусть someNumber = 42переключатель someNumber {случай ..< 0 : print ( " \( someNumber ) отрицательное." )случай 0 : print ( " \( someNumber ) равен 0." )случай 1. .. 9 : print ( " \( someNumber ) больше 0, но меньше 10." )по умолчанию : print ( " \( someNumber ) больше 9." )}// Печатает «42 больше 9».
for-in
циклы перебирают последовательность значений:
пусть имена = [ "Уилл" , "Анна" , "Барт" ]для имени в именах { печать ( имя )}// Печатает:// Воля// Анна// Барт
while
циклы повторяются до тех пор, пока заданное логическое условие оценивается как true
:
// Сложите все числа от 1 до 5.вар i = 1 результат переменной = 0while i <= 5 { // Цикл выполняет свое тело до тех пор, пока i меньше или равно 5. result += i // Добавить i к текущему результату. i += 1 // Увеличить i на 1.}print ( результат ) // Печатает "15"
Swift поддерживает замыкания , которые являются самостоятельными блоками функциональности, которые могут передаваться и использоваться в коде, [76] а также могут использоваться как анонимные функции . Вот несколько примеров:
// Тип замыкания, определяемый его входными и выходными значениями, может быть указан вне замыкания:пусть замыкание1 : ( Int , Int ) -> Int = { arg1 , arg2 in вернуть аргумент1 + аргумент2}// …или внутри него:пусть закрытие2 = { ( arg1 : Int , arg2 : Int ) -> Int в вернуть аргумент1 + аргумент2}// В большинстве случаев тип возвращаемого значения замыкания может быть автоматически выведен компилятором.пусть закрытие3 = { arg1 : Целое , arg2 : Целое в вернуть аргумент1 + аргумент2}
Замыкания могут быть назначены переменным и константам и могут быть переданы в другие функции или замыкания как параметры. Замыкания с одним выражением могут опускать return
ключевое слово.
В Swift также есть синтаксис конечного замыкания, который позволяет записывать замыкание после конца вызова функции, а не в списке параметров функции. Скобки можно вообще опустить, если замыкание является единственным параметром функции:
// Эта функция принимает замыкание, которое не получает входных параметров, и возвращает целое число,// оценивает его и использует возвращаемое значение замыкания (Int) в качестве возвращаемого значения функции.func foo ( замыкание bar : () -> Int ) -> Int { возврат бара ()}// Без завершающего синтаксиса замыкания:foo ( замыкание : { возврат 1 })// С синтаксисом конечного замыкания и неявным возвратом:фу { 1 }
Начиная с версии 5.3, Swift поддерживает множественные конечные замыкания: [77]
// Эта функция передает возврат первого замыкания как параметр второго, // и возвращает результат второго замыкания: func foo ( bar : () -> Int , baz : ( Int ) -> Int ) -> Int { return baz ( bar ()) }// Без конечных замыканий: foo ( bar : { return 1 }, baz : { x in return x + 1 })// С 1 завершающим замыканием: foo ( bar : { return 1 }) { x in return x + 1 }// С 2 конечными замыканиями (опущено только имя аргумента первого замыкания): foo { return 1 } baz : { x in return x + 1 }
Swift предоставит сокращенные имена аргументов для встроенных замыканий, устраняя необходимость явно называть все параметры замыканий. [78] Аргументы могут быть указаны с помощью имен $0, $1, $2 и т. д.:
пусть имена = [ "Жозефина" , "Стив" , "Крис" , "Барбара" ]// фильтр вызывает заданное замыкание для каждого значения в именах. // Значения с количеством символов меньше 6 сохраняются, остальные отбрасываются. let shortNames = names . filter { $0 . count < 6 }print ( shortNames ) // Выводит "["Стив", "Крис"]"
Замыкания могут захватывать значения из окружающей их области видимости. Замыкание будет ссылаться на это захваченное значение до тех пор, пока существует замыкание:
func makeMultiplier ( withMultiple multiple : Int ) -> ( Int ) -> ( Int ) { // Создает и возвращает замыкание, которое принимает Int и возвращает входные данные, умноженные на значение multiple. return { $0 * multiple } }let multiplier = makeMultiplier ( withMultiple : 3 ) print ( multiplier ( 3 )) // Печатает "9" print ( multiplier ( 10 )) // Печатает "30"
Стандартная библиотека Swift включает совместимые с Unicode типы String
и Character
. Строковые значения могут быть инициализированы строковым литералом, последовательностью символов, заключенных в двойные кавычки. Строки могут быть объединены с помощью +
оператора:
var someString = "Привет", someString += "мир!"
Интерполяция строк позволяет создавать новую строку из других значений и выражений. Значения, записанные в скобках, которым предшествует a, \
будут вставлены в окружающий строковый литерал: [79]
var currentScore = 980 print ( "Ваш счет \( currentScore ) ." )// Выводит «Ваш счет — 980».
Цикл for-in можно использовать для перебора символов, содержащихся в строке:
для символа в "Swift" { print ( character ) } // S // w // i // f // t
При импорте фреймворка Foundation Swift незаметно связывает тип String с NSString, классом String, обычно используемым в Objective-C.
В Swift вызываемые объекты определяются с помощью callAsFunction
. [80]
struct CallableStruct { var value : Int func callAsFunction ( _number : Int , scale : Int ) { print ( scale * ( number + value )) } } let callable = CallableStruct ( value : 100 ) callable ( 4 , scale : 2 ) callable.callAsFunction ( 4 , scale : 2 ) // Оба вызова функции выводят 208.
Swift поддерживает пять уровней контроля доступа для символов: open
, public
, internal
, fileprivate
, и private
. В отличие от многих объектно-ориентированных языков, эти элементы управления доступом игнорируют иерархии наследования : private
указывает, что символ доступен только в непосредственной области действия , fileprivate
указывает, что он доступен только изнутри файла, internal
указывает, что он доступен внутри содержащего его модуля, public
указывает, что он доступен из любого модуля и open
(только для классов и их методов) указывает, что класс может быть подклассифицирован вне модуля. [81]
Важной особенностью Swift являются опциональные типы , которые позволяют ссылкам или значениям работать аналогично общему шаблону в C , где указатель может ссылаться либо на определенное значение, либо вообще не ссылаться на значение. Это подразумевает, что неопциональные типы не могут привести к ошибке нулевого указателя ; компилятор может гарантировать, что это невозможно.
Необязательные типы создаются с помощью Optional
перечисления. Чтобы создать Integer, допускающий значение null, можно использовать объявление, похожее на var optionalInteger: Optional<Int>
. Как и в C#, [82] Swift также включает синтаксический сахар для этого, позволяя указать, что переменная является необязательной, поместив вопросительный знак после имени типа, var optionalInteger: Int?
. [83] Переменные или константы, помеченные как необязательные, либо имеют значение базового типа, либо являются nil
. Необязательные типы оборачивают базовый тип, что приводит к другому экземпляру. String
и String?
являются принципиально разными типами, первый имеет тип , String
а последний — , который Optional
может содержать некоторое String
значение.
Чтобы получить доступ к значению внутри, предполагая, что оно не равно нулю, его необходимо развернуть, чтобы раскрыть экземпляр внутри. Это выполняется с помощью !
оператора:
пусть myValue = anOptionalInstance ! .someMethod ()
В этом случае !
оператор разворачивается, anOptionalInstance
чтобы раскрыть экземпляр внутри, позволяя вызвать метод для него. Если anOptionalInstance
равно nil, возникает ошибка нулевого указателя, завершающая программу. Это известно как принудительное разворачивание. Необязательные элементы могут быть безопасно развернуты с помощью необязательной цепочки , которая сначала проверяет, является ли экземпляр nil, а затем разворачивает его, если он не равен null:
пусть myValue = anOptionalInstance ? .someMethod ()
В этом случае среда выполнения вызывает someMethod
только если anOptionalInstance
не является nil, подавляя ошибку. A ?
должно быть помещено после каждого необязательного свойства. Если любое из этих свойств является nil, все выражение оценивается как nil. Происхождение термина « цепочка» происходит от более распространенного случая, когда несколько вызовов методов/геттеров объединяются в цепочку. Например:
пусть aАрендатор = aЗдание.Списокарендаторов [ 5 ] пусть theirAренда = aАрендатор.Подробностиаренды пусть leaseStart = theirAренда ? .ДатаНачалаАренды
можно свести к:
пусть leaseStart = aBuilding . tenantList [ 5 ]. leaseDetails ?. startDate
Использование опционалов в Swift позволяет компилятору использовать статическую диспетчеризацию , поскольку действие распаковки вызывается для определенного экземпляра (оболочки), а не происходит в системе диспетчеризации во время выполнения.
Во многих объектно-ориентированных языках объекты внутренне представлены двумя частями. Объект хранится как блок данных, размещенный в куче , в то время как имя (или «дескриптор») этого объекта представлено указателем . Объекты передаются между методами путем копирования значения указателя, что позволяет любому, у кого есть копия, получить доступ к тем же базовым данным в куче. Напротив, базовые типы, такие как целые числа и значения с плавающей точкой, представлены напрямую; дескриптор содержит данные, а не указатель на них, и эти данные передаются методам напрямую путем копирования. Эти стили доступа называются передачей по ссылке в случае объектов и передачей по значению для базовых типов.
Обе концепции имеют свои преимущества и недостатки. Объекты полезны, когда данные большие, например, описание окна или содержимое документа. В этих случаях доступ к этим данным обеспечивается путем копирования 32- или 64-битного значения, а не копирования всей структуры данных. Однако меньшие значения, такие как целые числа, имеют тот же размер, что и указатели (обычно оба представляют собой одно слово ), поэтому нет никаких преимуществ в передаче указателя по сравнению с передачей значения.
Swift предлагает встроенную поддержку для объектов, использующих семантику передачи по ссылке или по значению, первая использует class
объявление, а вторая — struct
. Структуры в Swift имеют почти все те же функции, что и классы: методы, реализацию протоколов и использование механизмов расширения. По этой причине Apple называет все данные в общем виде экземплярами , а не объектами или значениями. Однако структуры не поддерживают наследование. [84]
Программист свободен выбирать, какая семантика больше подходит для каждой структуры данных в приложении. Более крупные структуры, такие как окна, будут определены как классы, что позволит передавать их как указатели. Более мелкие структуры, такие как 2D-точка, могут быть определены как структуры, которые будут передаваться по значению и позволять прямой доступ к своим внутренним данным без косвенности или подсчета ссылок. Улучшение производительности, присущее концепции передачи по значению, таково, что Swift использует эти типы почти для всех распространенных типов данных, включая Int
и Double
, а также типов, обычно представленных объектами, таких как String
и Array
. [84] Использование типов значений может также привести к значительному повышению производительности в пользовательских приложениях. [85]
Array
, Dictionary
, и Set
все используют копирование при записи, так что их данные копируются только если и когда программа пытается изменить значение в них. Это означает, что различные аксессоры имеют то, что по сути является указателем на одно и то же хранилище данных. Таким образом, хотя данные физически хранятся как один экземпляр в памяти, на уровне приложения эти значения являются отдельными, и физическое разделение обеспечивается копированием при записи только при необходимости. [86]
Расширения добавляют новую функциональность к существующему типу без необходимости подклассифицировать или даже иметь доступ к исходному коду. Расширения могут добавлять новые методы, инициализаторы, вычисляемые свойства, индексы и соответствия протоколам. [87] Примером может быть добавление проверки орфографии к базовому String
типу, что означает, что все экземпляры String
в программе получают возможность проверки орфографии. Система также широко используется в качестве организационного метода, позволяя собирать связанный код в расширения, подобные библиотекам.
Расширения объявляются с помощью extension
ключевого слова.
структура прямоугольника { пусть ширина : Двойная пусть высота : Двойная}расширение Прямоугольник { var area : Двойная { высота возврата * ширина }}
Протоколы обещают, что определенный тип реализует набор методов или свойств, что означает, что другие экземпляры в системе могут вызывать эти методы в любом экземпляре, реализующем этот протокол. Это часто используется в современных объектно-ориентированных языках в качестве замены множественному наследованию , хотя наборы функций не полностью схожи.
В Objective-C и большинстве других языков, реализующих концепцию протокола, программист должен убедиться, что требуемые методы реализованы в каждом классе. [88] Swift добавляет возможность добавлять эти методы с помощью расширений и использовать обобщенное программирование (generics) для их реализации. В совокупности это позволяет писать протоколы один раз и поддерживать широкий спектр экземпляров. Кроме того, механизм расширения может использоваться для добавления соответствия протоколу к объекту, который не перечисляет этот протокол в своем определении. [89]
Например, протокол может быть объявлен с именем Printable
, что гарантирует, что экземпляры, соответствующие протоколу, реализуют требование description
свойства и printDetails()
метода:
// Определить протокол с именем Printable protocol Printable { var description : String { get } // Требование свойства только для чтения func printDetails () // Требование метода }
Этот протокол теперь может быть принят и другими типами:
// Принять протокол Printable в классе class MyClass : Printable { var description : String { return " Экземпляр MyClass" } func printDetails () { print ( описание ) } }
Расширения могут использоваться для добавления соответствия протокола к типам. Сами протоколы также могут быть расширены для предоставления реализаций по умолчанию их требований. Приемники могут определять свои собственные реализации или использовать реализацию по умолчанию:
extension Printable { // Все экземпляры Printable получат эту реализацию или могут определить свою собственную. func printDetails () { print ( description ) } }// Bool теперь соответствует Printable и наследует реализацию printDetails() выше. extension Bool : Printable { var description : String { return "Экземпляр Bool со значением: \( self ) " }}
В Swift, как и во многих современных языках, поддерживающих интерфейсы, протоколы могут использоваться в качестве типов, что означает, что переменные и методы могут определяться протоколом, а не их конкретным типом:
func getSomethingPrintable () -> любой Printable { return true }var someSortOfPrintableInstance = getSomethingPrintable () print ( someSortOfPrintableInstance . description )// Выводит "Экземпляр Bool со значением: true"
Неважно, какой конкретный тип someSortOfPrintableInstance
, компилятор гарантирует, что он соответствует протоколу, и, таким образом, этот код безопасен. Этот синтаксис также означает, что коллекции могут быть основаны на протоколах, например let printableArray = [any Printable]
.
И расширения, и протоколы широко используются в стандартной библиотеке Swift; в Swift 5.9 примерно 1,2 процента всех символов в стандартной библиотеке были протоколами, а еще 12,3 процента были требованиями протоколов или реализациями по умолчанию. [90] Например, Swift использует расширения для добавления Equatable
протокола ко многим своим базовым типам, таким как строки и массивы, что позволяет сравнивать их с ==
оператором. Equatable
Протокол также определяет эту реализацию по умолчанию:
func !=< T : Equatable >( левая часть : T , правая часть : T ) -> Bool
Эта функция определяет метод, который работает на любом экземпляре, соответствующем Equatable
, предоставляя оператор не равно . Любой экземпляр, класс или структура, автоматически получает эту реализацию, просто соответствуя Equatable
. [91]
Протоколы, расширения и дженерики можно комбинировать для создания сложных API. Например, ограничения позволяют типам условно принимать протоколы или методы на основе характеристик принимающего типа. Обычным вариантом использования может быть добавление метода к типам коллекций только тогда, когда элементы, содержащиеся в коллекции, являются Equatable
:
расширение Массив , где Элемент : Equatable { // allEqual будет доступен только для экземпляров Array, содержащих элементы Equatable. func allEqual () -> Bool { for element in self { if element != self . first { return false } } return true } }
Swift 5.5 ввел структурный параллелизм в язык. [92] Структурный параллелизм использует синтаксис Async/await, похожий на Kotlin, JavaScript и Rust. Асинхронная функция определяется ключевым async
словом после списка параметров. При вызове асинхронной функции await
ключевое слово должно быть написано перед функцией, чтобы указать, что выполнение потенциально будет приостановлено во время вызова функции. Пока функция приостановлена, программа может запустить некоторую другую параллельную функцию в той же программе. Этот синтаксис позволяет программам четко вызывать потенциальные точки приостановки и избегать версии Пирамиды гибели (программирования), вызванной ранее широко распространенным использованием обратных вызовов замыкания. [93]
func downloadText ( name : String ) async -> String { let result = // ... некоторый код асинхронной загрузки ... return result }пусть текст = ожидание загрузкиТекст ( "текст1" )
Синтаксис async let
позволяет выполнять несколько функций параллельно. await
снова используется для обозначения точки, в которой программа приостанавливается для ожидания завершения функций async
, вызванных ранее.
// Каждый из этих вызовов downloadText будет выполняться параллельно. async let text1 = downloadText ( name : "text1" ) async let text2 = downloadText ( name : "text2" ) async let text3 = downloadText ( name : "text3" )let textToPrint = await [ text1 , text2 , text3 ] // Приостанавливает работу до тех пор, пока все три вызова downloadText не вернутся. print ( textToPrint )
Задачи и группы задач можно создавать явно для создания динамического количества дочерних задач во время выполнения:
пусть taskHandle = Задача { await downloadText ( имя : "someText" ) }пусть результат = ожидание taskHandle . значение
Swift использует модель Actor для изоляции изменяемого состояния, позволяя различным задачам изменять общее состояние безопасным образом. Акторы объявляются с actor
ключевым словом и являются ссылочными типами, как классы. Только одна задача может получить доступ к изменяемому состоянию актора в одно и то же время. Акторы могут свободно получать доступ и изменять свое собственное внутреннее состояние, но код, работающий в отдельных задачах, должен помечать каждый доступ ключевым словом, await
чтобы указать, что код может приостановиться, пока другие задачи не закончат доступ к состоянию актора.
Actor Directory { var names : [ String ] = [] func add ( имя : строка ) { имена.append ( имя ) } } пусть каталог = Каталог ()// Код приостанавливается, пока другие задачи не закончат доступ к актору. await directory . add ( name : "Tucker" ) print ( await directory . names )
В системах Apple Swift использует ту же среду выполнения, что и существующая система Objective-C , но требует iOS 7 или macOS 10.9 или выше. Он также зависит от Grand Central Dispatch . [94] Код Swift и Objective-C может использоваться в одной программе, а также, по расширению, C и C++. Начиная с Swift 5.9, код C++ может использоваться непосредственно из кода Swift. [95] В случае Objective-C Swift имеет значительный доступ к объектной модели и может использоваться для подклассификации, расширения и использования кода Objective-C для обеспечения поддержки протокола. [96] Обратное неверно: класс Swift не может быть подклассифицирован в Objective-C. [97]
Чтобы помочь в разработке таких программ и повторном использовании существующего кода, Xcode 6 и выше предлагает полуавтоматическую систему, которая создает и поддерживает заголовок моста для предоставления кода Objective-C в Swift. Это принимает форму дополнительного файла заголовка , который просто определяет или импортирует все символы Objective-C, необходимые коду Swift проекта. В этот момент Swift может ссылаться на типы, функции и переменные, объявленные в этих импортах, как если бы они были написаны на Swift. Код Objective-C также может напрямую использовать код Swift, импортируя автоматически поддерживаемый файл заголовка с объявлениями Objective-C символов Swift проекта. Например, файл Objective-C в смешанном проекте под названием «MyApp» может обращаться к классам или функциям Swift с помощью кода #import "MyApp-Swift.h"
. Однако не все символы доступны через этот механизм — использование специфичных для Swift функций, таких как универсальные типы, необъектные необязательные типы, сложные перечисления или даже идентификаторы Unicode, может сделать символ недоступным из Objective-C. [98]
Swift также имеет ограниченную поддержку атрибутов , метаданных, которые считываются средой разработки и не обязательно являются частью скомпилированного кода. Как и Objective-C, атрибуты используют @
синтаксис, но в настоящее время доступный набор невелик. Одним из примеров является @IBOutlet
атрибут, который отмечает заданное значение в коде как выход , доступный для использования в Interface Builder (IB). Выход — это устройство, которое связывает значение экранного дисплея с объектом в коде.
На системах, отличных от Apple, Swift не зависит от среды выполнения Objective-C или других системных библиотек Apple; их заменяет набор реализаций Swift "Corelib". Они включают "swift-corelibs-foundation" для замены Foundation Kit , "swift-corelibs-libdispatch" для замены Grand Central Dispatch и "swift-corelibs-xctest" для замены API XCTest из Xcode . [99]
Начиная с 2019 года, с Xcode 11, Apple также добавила новую парадигму пользовательского интерфейса под названием SwiftUI. SwiftUI заменяет старую парадигму Interface Builder новой декларативной парадигмой разработки. [100]
Swift использует автоматический подсчет ссылок (ARC) для управления памятью . Каждый экземпляр класса или замыкания поддерживает счетчик ссылок, который ведет текущий подсчет количества ссылок, удерживаемых программой. Когда этот счетчик достигает 0, экземпляр освобождается. Это автоматическое освобождение устраняет необходимость в сборщике мусора, поскольку экземпляры освобождаются, как только они больше не нужны.
Сильный цикл ссылок может возникнуть, если два экземпляра строго ссылаются друг на друга (например, A ссылается на B, B ссылается на A). Поскольку счетчик ссылок ни одного экземпляра не может достичь нуля, ни один из них не освобождается, что приводит к утечке памяти . Swift предоставляет ключевые слова weak
и unowned
для предотвращения сильных циклов ссылок. Эти ключевые слова позволяют ссылаться на экземпляр без увеличения его счетчика ссылок. weak
ссылки должны быть необязательными переменными, поскольку они могут изменяться и становиться nil
. [101] Попытка получить доступ к unowned
значению, которое уже было освобождено, приводит к ошибке выполнения.
Замыкание внутри класса также может создать цикл сильных ссылок, захватывая ссылки на себя. Ссылки на себя, которые следует рассматривать как слабые или не имеющие владельца, можно обозначить с помощью списка захвата.
класс Человек { пусть имя : Строка слабая var home : Home ? // Определена как слабая ссылка, чтобы разорвать цикл ссылок. слабые ссылки не увеличивают счетчик ссылок экземпляра, на который они ссылаются. init ( имя : Строка ) { сам . имя = имя } deinit { print ( "Деинициализировано \( имя ) " ) }}класс Главная { пусть адрес : Строка владелец переменной : Персона ? init ( адрес : Строка , владелец : Лицо ?) { сам . адрес = адрес сам . владелец = владелец } deinit { print ( "Деинициализированный \( адрес ) " ) }}var stacy : Person ? = Person ( имя : "Stacy" )var house21b : Дом ? = Дом ( адрес : "21b Baker Street" , владелец : stacy )stacy ?. home = house21b // stacy и house42b теперь ссылаются друг на друга.stacy = nil // Количество ссылок для stacy теперь равно 1, поскольку house21b все еще хранит ссылку на нее.house21b = nil // количество ссылок на house21b падает до 0, что, в свою очередь, снижает количество ссылок на stacy до 0, поскольку house21b был последним экземпляром, содержащим сильную ссылку на stacy.// Печатает:// Деинициализация 21b Baker Street// Деинициализированная Стейси
Ключевым элементом системы Swift является ее способность быть чисто отлаженной и запущенной в среде разработки, используя цикл read-eval-print (REPL), что дает ей интерактивные свойства, более общие со скриптовыми возможностями Python, чем с традиционными языками системного программирования . REPL дополнительно улучшен с помощью игровых площадок , интерактивных представлений, работающих в среде Xcode или приложения Playgrounds , которые реагируют на изменения кода или отладчика на лету. [102] Playgrounds позволяют программистам добавлять код Swift вместе с документацией markdown. Программисты могут пошагово проходить по коду и добавлять точки останова, используя LLDB либо в консоли, либо в IDE, такой как Xcode.
Swift считается языком программирования семейства C и во многом похож на C:
+
ведут себя немного по-другому. Например, в Swift +
прерывания при переполнении, тогда как &+
используется для обозначения поведения, похожего на C, переноса при переполнении.===
предоставляется для проверки того, ссылаются ли два элемента данных на один и тот же объект .while
, if
, и switch
похожи, но имеют расширенные функции, например, , switch
который принимает нецелые случаи while
и if
поддерживает сопоставление с образцом и условное развертывание необязательных параметров, for
использует синтаксис.for i in 1...10
Он также имеет сходство с Objective-C:
Int, UInt, Float, Double
self
в методах класса — это класс, в котором был вызван метод.for
... in
синтаксис перечисления.Отличия от Objective-C включают в себя:
;
), хотя ее необходимо использовать, чтобы разрешить размещение более одного оператора в одной строке.i = 0
вместо i == 0
(которая выдает ошибку времени компиляции).break
операторы в switch
блоках. Отдельные случаи не попадают в следующий случай, если fallthrough
оператор не используется.&+
, &-
, &*
, &/
и &%
. Свойства min
и max
определены в Swift для всех целочисленных типов и могут использоваться для безопасной проверки потенциальных переполнений, вместо того чтобы полагаться на константы, определенные для каждого типа во внешних библиотеках.if
and while
, которая позволяет опускать скобки вокруг оператора, не поддерживается.for (int i = 0; i < c; i++)
, подверженное ошибкам из-за несоответствия одному элементу , не поддерживается (начиная с версии Swift 3). [104]i++
, --i
...) не поддерживаются (начиная с версии Swift 3), тем более, что for
операторы в стиле C также не поддерживаются, начиная с версии Swift 3. [105]Поскольку Swift может работать на Linux, его иногда используют как серверный язык. [106] Некоторые веб-фреймворки уже разработаны, например, Kitura от IBM (теперь прекращена), Perfect и Vapor .
Apple также создала официальную рабочую группу «Server APIs» [107], в которой члены сообщества разработчиков Swift играют центральную роль. [108]
Вторая бесплатная реализация Swift, ориентированная на Cocoa , Microsoft Common Language Infrastructure ( .NET Framework , теперь .NET ), а также платформы Java и Android, существует как часть Elements Compiler от RemObjects Software . [109]
Подмножества Swift были перенесены на дополнительные платформы, такие как Arduino [110] и Mac OS 9. [ 111]
{{cite web}}
: Отсутствует или пусто |title=
( помощь )Swift является проприетарным и закрытым: он полностью контролируется Apple, и не имеет реализации с открытым исходным кодом.
можете себе представить, что многие из нас хотят, чтобы исходный код был открытым и стал частью LLVM, но обсуждение еще не состоялось и не состоится в течение некоторого времени.
Язык Swift является продуктом неустанных усилий команды экспертов по языку, гуру документации, ниндзя оптимизации компиляторов и невероятно важной внутренней группы по догфудингу, которая предоставляла обратную связь, чтобы помочь отточить и проверить идеи в бою. Конечно, он также в значительной степени выиграл от опыта, полученного с трудом многими другими языками в этой области, черпая идеи из Objective-C, Rust, Haskell, Ruby, Python, C#, CLU и слишком многих других, чтобы перечислить их.
Я начал работу над языком программирования Swift в июле 2010 г. Я реализовал большую часть базовой структуры языка, и лишь несколько человек знали о его существовании. Несколько других (удивительных) людей начали вносить серьезный вклад в конце 2011 г., и это стало основным направлением для группы Apple Developer Tools в июле 2013 г. [...], черпая идеи из
Objective-C
, Rust, Haskell, Ruby, Python, C#, CLU и слишком многих других, чтобы перечислить.
{{cite web}}
: |last=
имеет общее название ( помощь ){{cite web}}
: |last=
имеет общее название ( помощь )