Swift(编程语言)
范例 | 多范式:面向协议,面向对象,功能,命令,块结构,声明,并发 |
---|---|
设计 | 克里斯·拉特纳(Chris Lattner) ,道格·格雷戈尔(Doug Gregor),约翰·麦考尔(John McCall),泰德·克雷梅内克(Ted Kremenek),乔·格罗夫( Joe Groff)和苹果公司 |
开发人员 | 苹果公司和开源贡献者 |
首先出现 | 2014年6月2日 |
稳定版本 | 5.9.2 / 2023年12月11日
|
预览发布 | 5.9
|
打字学科 | 静态,强,推断 |
内存管理 | 自动参考计数 |
作业系统 | 苹果的操作系统( Darwin , iOS , iPados , MacOS , TVOS , WatchOS ), Linux , Windows , Android |
执照 |
Apache许可证2.0 (Swift 2.2及以后) 专有(最高2.2) |
文件名扩展 | .swift, .SWIFT |
网站 | |
被影响 | |
Objective-C , Rust , Haskell , Ruby , Python , C# , Clu , D | |
受影响 | |
RUST , V(Vlang) |
Swift是由Apple Inc.和开源社区开发的高级通用,多范式的多范式。 Swift将其编译到机器代码,因为它是基于LLVM的编译器。 Swift于2014年6月首次发行,自2014年版本以来,Swift Toolchain已发货Xcode 。
苹果公司打算支持与Objective-C相关的许多核心概念,特别是动态调度,广泛的较晚绑定,可扩展的编程和类似功能,但以“更安全”的方式,使捕获软件错误变得更加容易; Swift具有解决一些常见编程错误(例如NULL指针删除)的功能,并提供句法糖以帮助避免厄运的金字塔。 Swift支持协议可扩展性的概念,该概念可以应用于类型,结构和类,Apple作为编程范式中的真正变化,它们称为“以协议为导向的编程”(类似于特征和类型类别)。
Swift是在Apple 2014年全球开发人员会议(WWDC)上引入的。它在2014年进行了1.2版的升级,并在WWDC 2015上进行了对Swift 2的重大升级。最初是专有语言,2015年12月3日,根据Appache License 2.0为Apple Platforms and Linux制作了2.2版2.2版。
通过3.0版,Swift的语法经历了重大演变,核心团队使源稳定性成为后来版本的重点。在2018年第一季度,Swift超过了Objective-C,在衡量的受欢迎程度方面。
Swift 4.0于2017年发行,对某些内置类和结构进行了一些更改。可以使用Xcode内置的迁移功能更新以前版本的Swift版本。 Swift 5于2019年3月发布,在Apple平台上引入了稳定的二进制界面,从而使Swift运行时可以将其纳入Apple操作系统。它与Swift 4兼容。
Swift 5.1于2019年9月正式发布。Swift5.1通过扩展语言的稳定功能以通过引入模块稳定性来编译时间,从而在Swift 5的先前版本上构建。引入模块稳定性使创建和共享将与Swift版本发行的二进制框架成为可能。
Swift 5.5是Apple在2021 WWDC上正式宣布的,大大扩展了对并发和异步代码的语言支持,特别是引入了Actor模型的独特版本。
当前版本Swift 5.9于2023年9月发布,包括宏系统,通用参数包以及新consume
操作员等所有权功能。
历史
克里斯·拉特纳(Chris Lattner)于2010年7月开始开发斯威夫特(Swift),苹果许多其他程序员的最终合作。斯威夫特的激励是需要替换苹果早期的编程语言Objective-C ,自1980年代初以来,该语言基本上不变,并且缺乏现代语言功能。斯威夫特(Swift)采用了语言想法“从Objective-C , Rust , Haskell , Ruby , Python , C# , Clu和其他太多其他人列出”。 2014年6月2日, Apple Worldwide开发人员会议(WWDC)申请成为第一个由Swift撰写的公开发布的应用程序。该编程语言的Beta版本已在会议上发布给注册的Apple开发人员,但该公司并不保证Swift的最终版本将与测试版本兼容源代码。 Apple计划如果需要,将源代码转换器可用。
Swift编程语言是一本免费的500页手册,也在WWDC上发布,可在Apple Books Store和官方网站上找到。
斯威夫特(Swift)于2014年9月9日达到了1.0里程碑, iOS的Xcode 6.0金牌大师。 Swift 1.1于2014年10月22日发布,以及Xcode 6.1的发布。 Swift 1.2于2015年4月8日与Xcode 6.3一起发布。 Swift 2.0于2015年WWDC宣布,并于2015年9月21日在App Store上发布应用程序。Swift3.0于2016年9月13日发布。Swift4.0于2017年9月19日发布。Swift4. 1发布了2018年3月29日。
Swift在2015年的堆栈溢出开发人员调查中获得了最喜欢的编程语言的第一名,并在2016年获得了第二名。
2015年12月3日,Swift语言,支持库,调试器和软件包经理在Apache 2.0许可证下开源,具有运行时库例外,并创建了Swift.org来托管该项目。源代码托管在GitHub上,任何人都可以轻松获取代码,自己构建代码,甚至创建拉动请求以将代码贡献回该项目。
2015年12月, IBM宣布了Swift Sandbox网站,该网站允许开发人员在一个窗格中编写Swift代码并在另一个窗格中显示输出。 Swift Sandbox在2018年1月被弃用。
在2016年WWDC期间,苹果宣布了一个名为Swift Playgrounds的iPad独家应用程序,旨在教人们如何在Swift中进行编码。该应用程序以3D视频游戏的接口显示,该界面在以一定顺序放置并执行的代码行时提供反馈。
2017年1月,克里斯·拉特纳(Chris Lattner)宣布离开苹果公司(Apple)担任特斯拉汽车公司(Tesla Motors)的新职位,Swift Project Project主角将担任老将Ted Kremenek。
在2019年WWDC期间,Apple宣布了Swiftui的Xcode 11,该XCode 11为所有Apple平台提供了声明性UI结构设计的框架。
自Swift 2.2以来,已经提供了用于Linux Ubuntu发行的官方下载,自Swift 5.2.4, CentOS和Amazon Linux以来添加了更多发行版。也有一个非正式的SDK和Android的本机工具链包装。
平台
SWIFT的平台支持是Apple的操作系统( Darwin , iOS , iPados , MacOS , TVOS , WatchOS ), Linux , Windows和Android 。
Swift设计的一个关键方面是它可以与过去几十年中为Apple产品开发的庞大的Objective-C代码互操作的能力,例如可可和可可触摸框架。在Apple平台上,它与Objective-C运行时库链接,该库允许C , Objective-C , C ++和Swift代码在一个程序中运行。
版本历史记录
版本 | 发布日期 | 苹果系统 | Linux | 视窗 |
---|---|---|---|---|
Swift 1.0 | 2014年9月9日 | 是的 | 不 | 不 |
Swift 1.1 | 2014年10月22日 | 是的 | 不 | 不 |
Swift 1.2 | 2015年4月8日 | 是的 | 不 | 不 |
Swift 2.0 | 2015年9月21日 | 是的 | 不 | 不 |
Swift 2.1 | 2015年10月20日 | 是的 | 不 | 不 |
Swift 2.2 | 2016年3月21日 | 是的 | 是的 | 不 |
Swift 2.2.1 | 2016年5月3日 | 是的 | 是的 | 不 |
Swift 3.0 | 2016年9月13日 | 是的 | 是的 | 不 |
Swift 3.0.1 | 2016年10月28日 | 是的 | 是的 | 不 |
Swift 3.0.2 | 2016年12月13日 | 是的 | 是的 | 不 |
Swift 3.1 | 2017年3月27日 | 是的 | 是的 | 不 |
Swift 3.1.1 | 2017年4月21日 | 是的 | 是的 | 不 |
Swift 4.0 | 2017年9月19日 | 是的 | 是的 | 不 |
Swift 4.0.2 | 2017年11月1日 | 是的 | 是的 | 不 |
Swift 4.0.3 | 2017年12月5日 | 是的 | 是的 | 不 |
Swift 4.1 | 2018年3月29日 | 是的 | 是的 | 不 |
Swift 4.1.1 | 2018年5月4日 | 不 | 是的 | 不 |
Swift 4.1.2 | 2018年5月31日 | 是的 | 是的 | 不 |
Swift 4.1.3 | 2018年7月27日 | 不 | 是的 | 不 |
Swift 4.2 | 2018年9月17日 | 是的 | 是的 | 不 |
Swift 4.2.1 | 2018年10月30日 | 是的 | 是的 | 不 |
Swift 4.2.2 | 2019年2月4日 | 不 | 是的 | 不 |
Swift 4.2.3 | 2019年2月28日 | 不 | 是的 | 不 |
Swift 4.2.4 | 2019年3月29日 | 不 | 是的 | 不 |
Swift 5.0 | 2019年3月25日 | 是的 | 是的 | 不 |
Swift 5.0.1 | 2019年4月18日 | 是的 | 是的 | 不 |
Swift 5.0.2 | 2019年7月15日 | 不 | 是的 | 不 |
Swift 5.0.3 | 2019年8月30日 | 不 | 是的 | 不 |
Swift 5.1 | 2019年9月10日 | 是的 | 是的 | 不 |
Swift 5.1.1 | 2019年10月11日 | 不 | 是的 | 不 |
Swift 5.1.2 | 2019年11月7日 | 是的 | 是的 | 不 |
Swift 5.1.3 | 2019年12月13日 | 是的 | 是的 | 不 |
Swift 5.1.4 | 2020年1月31日 | 不 | 是的 | 不 |
Swift 5.1.5 | 2020年3月9日 | 不 | 是的 | 不 |
Swift 5.2 | 2020年3月24日 | 是的 | 是的 | 不 |
Swift 5.2.1 | 2020年3月30日 | 不 | 是的 | 不 |
Swift 5.2.2 | 2020年4月15日 | 是的 | 是的 | 不 |
Swift 5.2.3 | 2020年4月29日 | 不 | 是的 | 不 |
Swift 5.2.4 | 2020年5月20日 | 是的 | 是的 | 不 |
Swift 5.2.5 | 2020年8月5日 | 不 | 是的 | 不 |
Swift 5.3 | 2020年9月16日 | 是的 | 是的 | 是的 |
Swift 5.3.1 | 2020年11月13日 | 是的 | 是的 | 是的 |
Swift 5.3.2 | 2020年12月15日 | 是的 | 是的 | 是的 |
Swift 5.3.3 | 2021年1月25日 | 不 | 是的 | 是的 |
Swift 5.4 | 2021年4月26日 | 是的 | 是的 | 是的 |
Swift 5.4.1 | 2021年5月25日 | 不 | 是的 | 是的 |
Swift 5.4.2 | 2021年6月28日 | 是的 | 是的 | 是的 |
Swift 5.4.3 | 2021年9月9日 | 不 | 是的 | 是的 |
Swift 5.5 | 2021年9月20日 | 是的 | 是的 | 是的 |
Swift 5.5.1 | 2021年10月27日 | 是的 | 是的 | 是的 |
Swift 5.5.2 | 2021年12月14日 | 是的 | 是的 | 是的 |
Swift 5.5.3 | 2022年2月9日 | 不 | 是的 | 是的 |
Swift 5.6 | 2022年3月14日 | 是的 | 是的 | 是的 |
Swift 5.6.1 | 2022年4月9日 | 不 | 是的 | 是的 |
Swift 5.6.2 | 2022年6月15日 | 不 | 是的 | 是的 |
Swift 5.6.3 | 2022年9月2日 | 不 | 是的 | 是的 |
Swift 5.7 | 2022年9月12日 | 是的 | 是的 | 是的 |
Swift 5.7.1 | 2022年11月1日 | 是的 | 是的 | 是的 |
Swift 5.8 | 2023年3月30日 | 是的 | 是的 | 是的 |
Swift 5.8.1 | 2023年6月1日 | 是的 | 是的 | 是的 |
Swift 5.9 | 2023年9月18日 | 是的 | 是的 | 是的 |
Swift 5.9.1 | 2023年10月19日 | 是的 | 是的 | 是的 |
Swift 5.9.2 | 2023年12月11日 | 是的 | 是的 | 是的 |
特征
Swift是通用编程语言,它采用了现代的编程语言理论概念,并努力提出一种简单而强大的语法。 Swift将来自各种编程语言的创新和惯例与Objective-C的显著灵感结合在一起,该灵感替换为Apple平台上的主要开发语言。
Swift的设计旨在对新程序员安全且友好,同时又不牺牲速度。默认情况下,Swift会自动管理所有内存,并确保在使用前始终初始化变量。检查阵列访问是否存在界外错误,并检查整数操作是否有溢出。参数名称允许创建清晰的API。协议定义了可能采用类型的接口,而扩展程序使开发人员可以为现有类型添加功能。 Swift启用面向对象的编程,并支持类,亚型和方法覆盖。选项允许明确,安全地处理零值。可以使用异步/等待语法编写并发程序,参与者隔离可共享的可变状态,以消除数据种族。
基本语法
Swift的语法类似于C风格的语言。默认情况下,代码开始在全局范围内执行。另外,可以应用@ main
属性一个结构,类或枚举声明,以表明其包含程序的入口点。
斯威夫特的“你好,世界!”程序是:
print("Hello, world!")
Swift的标准库中包含了print ( _ : separator : terminator :)
函数,该函数可供所有程序可用,而无需导入外部模块。 Swift中的陈述不必以半隆结尾,但是半分离句必须分开在同一行上写的多个语句。单行注释以//
开头,然后继续直至当前行的末尾。多行注由/*
和*/
字符包含。使用带有var
关键字的let
关键字和变量来声明常数。值必须在读取之前初始化。值可以根据提供的初始值的类型来推断其类型。如果在该值声明之后设置了初始值,则必须明确声明类型。
let highScoreThreshold = 1000 // A constant with type Int. The type was inferred based on the provided value.
var currentScore = 980 // A variable with type Int.
currentScore = 1200 // The value of variables can change over time.
let playerMessage: String // A constant with explicit type String.
if currentScore > highScoreThreshold {
playerMessage = "You are a top player!"
} else {
playerMessage = "Better luck next time."
}
print(playerMessage) // Prints "You are a top player!"
Swift中的控制流与IF-ELSE , Guard和Switch语句一起管理,以及ins和for-in-In循环。如果语句采用布尔参数并执行IF语句的主体,如果条件为真,则执行可选的else
主体。 if - let
语法提供句法糖,用于检查是否存在可选值并同时解开它。
let someNumber = 42
if someNumber % 2 == 0 { // Use the remainder operator to find the remainder of someNumber divided by 2.
print("\(someNumber) is even.")
} else{
print("\(someNumber) is odd.")
}
// Prints "42 is even."
功能由
关键字定义。函数参数可能具有允许函数调用的名称,可以像短语一样读取。参数名称之前的下划线允许从呼叫站点省略参数标签。元组可以使用函数一次返回多个数据。func
func constructGreeting(for name: String) -> String {
return "Hello \(name)!"
}
let greeting = constructGreeting(for: "Craig")
print(greeting) // Prints "Hello Craig!"
函数和匿名函数称为闭合,可以像其他任何值一样分配给属性并围绕该程序传递。
func divideByTwo(_ aNum: Int) -> Int {
return aNum / 2
}
func multiplyByTwo(_ aNum: Int) -> Int {
return aNum * 2
}
let mathOperation = multiplyByTwo
print(mathOperation(21)) // Prints "42"
语句要求给定的条件是正确的,然后再继续以前的guard
声明,否则提供了guard
子句的主体。 else
条款必须退出显示else
语句的代码块的控制。 guard
语句对于确保在继续执行程序之前满足某些要求很有用。特别是它们可用于创建可选值的未包装版本,该版本保证在封闭范围的其余部分中是非nil的。guard
func divide(numerator: Int?, byDenominator denominator: Int) -> Int? {
guard denominator != 0 else {
print("Can't divide by 0.")
return nil
}
guard let numerator else {
print("The provided numerator is nil.")
return nil
}
return numerator / denominator
}
let result = divide(numerator: 3, byDenominator: 0)
print("Division result is: \(result)")
// Prints:
// "Can't divide by 0."
// "Division result is: nil."
switch
语句比较具有多个潜在值的值,然后执行关联的代码块。必须通过包括所有可能的值的情况或包括在提供的值不匹配其他任何情况时运行的default
情况,必须使switch
语句详尽。 switch
案例并没有隐含地掉落,尽管它们可以用fallthrough
关键字明确地做到这一点。模式匹配可以在switch
语句中以各种方式使用。这是整数与许多潜在范围匹配的示例:
let someNumber = 42
switch someNumber {
case ..<0:
print("\(someNumber) negative.")
case 0:
print("\(someNumber) is 0.")
case 1...9:
print("\(someNumber) greater than 0, but less than 10.")
default:
print("\(someNumber) is greater than 9.")
}
// Prints "42 is greater than 9."
for-in
循环迭代一系列值:
let names = ["Will", "Anna", "Bart"]
for name in names {
print(name)
}
// Prints:
// Will
// Anna
// Bart
while
给定的布尔条件评估为true
,循环迭代了:
// Add together all the numbers from 1 to 5.
var i = 1
var result = 0
while i <= 5 { // The loop performs its body as long as i is less than or equal to 5.
result += i // Add i to the current result.
i += 1 // Increment i by 1.
}
print(result) // Prints "15"
关闭支持
Swift支持关闭,它们是可以通过代码传递和使用的独立功能块,也可以用作匿名功能。这里有一些例子:
// Closure type, defined by its input and output values, can be specified outside the closure:
let closure1: (Int, Int) -> Int = { arg1, arg2 in
return arg1 + arg2
}
// …or inside it:
let closure2 = { (arg1: Int, arg2: Int) -> Int in
return arg1 + arg2
}
// In most cases, closure's return type can be inferred automatically by the compiler.
let closure3 = { arg1: Int, arg2: Int in
return arg1 + arg2
}
可以将关闭分配给变量和常数,并且可以将其作为参数传递到其他功能或封闭中。单表达封闭可能会删除return
关键字。
Swift还具有尾随的闭合语法,该语法允许在函数调用结束后而不是在函数的参数列表中编写闭合。如果关闭是函数的唯一参数,则可以完全省略括号:
// This function takes a closure which receives no input parameters and returns an integer,
// evaluates it, and uses the closure's return value (an Int) as the function's return value.
func foo(closure bar: () -> Int) -> Int {
return bar()
}
// Without trailing closure syntax:
foo(closure: { return 1 })
// With trailing closure syntax, and implicit return:
foo { 1 }
从5.3版开始,Swift支持多个尾随封闭:
// This function passes the return of the first closure as the parameter of the second,
// and returns the second closure's result:
func foo(bar: () -> Int, baz: (Int) -> Int) -> Int {
return baz(bar())
}
// With no trailing closures:
foo(bar: { return 1 }, baz: { x in return x + 1 })
// With 1 trailing closure:
foo(bar: { return 1 }) { x in return x + 1 }
// With 2 trailing closures (note that only the first closure's argument name is omitted):
foo { return 1 } baz: { x in return x + 1 }
Swift将为内联封闭提供速记参数名称,从而消除了明确命名所有关闭参数的需求。可以使用名称$ 0,$ 1,$ 2等来参考参数:
let names = ["Josephine", "Steve", "Chris", "Barbara"]
// filter calls the given closure for each value in names.
// Values with a character count less than 6 are kept, the others are dropped.
let shortNames = names.filter { $0.count < 6 }
print(shortNames) // Prints "["Steve", "Chris"]"
封闭可能会从周围范围捕获价值。只要闭合存在,封闭将指出此被捕获的值:
func makeMultiplier(withMultiple multiple: Int) -> (Int) -> (Int) {
// Create and return a closure that takes in an Int and returns the input multiplied by the value of multiple.
return {
$0 * multiple
}
}
let multiplier = makeMultiplier(withMultiple: 3)
print(multiplier(3)) // Prints "9"
print(multiplier(10)) // Prints "30"
字符串支持
SWIFT标准库包括符合Unicode的String
和Character
类型。字符串值可以用字符串文字初始化,这是一系列字符,被双引号包围。字符串可以与+
运算符连接:
var someString = "Hello,"
someString += " world!"
字符串插值允许从其他值和表达式创建新字符串。括号之间写入A \
之间写入的值将插入封闭字符串字面的字体:
var currentScore = 980
print("Your score is \(currentScore).")
// Prints "Your score is 980."
可以使用一个for-in循环迭代字符串中包含的字符:
for character in "Swift" {
print(character)
}
// S
// w
// i
// f
// t
当Foundation Framework导入Swift时,Swift无形地将字符串类型桥接到NSString,这是APPECOCT-C中常用的字符串类。
可呼叫对象
在Swift中,使用callAsFunction
定义可呼叫的对象。
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)
// Both function calls print 208.
访问控制
Swift支持符号的五个访问控制级别: open
, public
, internal
, fileprivate
和private
。与许多面向对象的语言不同,这些访问控件忽略继承层次结构: private
表示仅在直接范围中访问符号, fileprivate
表示仅在文件中可以访问它, internal
表示它可以在包含的模块中访问, public
指示可以访问它可以从任何模块访问,并open
(仅适用于类及其方法),表明该类可以在模块外部子分类。
选择和链接
Swift中的一个重要功能是选项类型,该选项类型允许引用或值以类似于C中的共同模式的方式运行,在该方式中,指针可以指定特定值或根本没有值。这意味着非选举类型不能导致零销误差。编译器可以确保这是不可能的。
使用Optional
枚举创建可选类型。为了使整数可随机无效,将使用类似于var optionalInteger: Optional<Int>
。与C#一样,Swift还包括句法糖,允许一个人通过在类型名称var optionalInteger: Int?
类型名称下方放置问号来表明变量是可选的。 。标记为可选的变量或常数具有基础类型的值,要幺是nil
。可选类型包装基本类型,从而导致不同的实例。 String
和String?
从根本上是不同的类型,前者是类型String
,而后者是可能具有某些String
值的Optional
。
要访问内部的值,假设它不是零,则必须拆开它以公开内部实例。这是与!
操作员:
let myValue = anOptionalInstance!.someMethod()
在这种情况下, !
操作员拆开了anOptionalInstance
,以将实例公开内部,从而可以在其上进行调用。如果anOptionalInstance
为零,则会发生无数分数错误,从而终止程序。这被称为“力解开”。可以使用可选链条安全地解开选项,该链首先测试实例是否为nil,然后将其解开,如果它是非零件:
let myValue = anOptionalInstance?.someMethod()
在这种情况下,只有在不nil的anOptionalInstance
时,运行时呼叫someMethod
,从而抑制了错误。一个?
必须在每个可选属性之后放置。如果这些属性中的任何一个是零,则整个表达式将评估为nil。链条术语的起源来自更常见的情况,即几种方法调用/获取器被链接在一起。例如:
let aTenant = aBuilding.tenantList[5]
let theirLease = aTenant.leaseDetails
let leaseStart = theirLease?.startDate
可以简化为:
let leaseStart = aBuilding.tenantList[5].leaseDetails?.startDate
Swift使用选项的使用允许编译器使用静态调度,因为在定义的实例(包装器)上调用了未包装操作,而不是在运行时调度系统中发生的。
价值类型
在许多面向对象的语言中,对像在内部以两个部分表示。该对像作为放置在堆上的数据块存储,而该对象的名称(或“句柄”)由指针表示。对像在方法之间通过复制指针的值来传递,从而允许使用复制品的任何人访问堆上的相同基础数据。相比之下,直接表示整数和浮点值之类的基本类型。该句柄包含数据,而不是指向数据,并且该数据通过复制直接传递给方法。在对象的情况下,这些访问样式被称为通过转文和基本类型的通过。
这两个概念都有其优势和缺点。当数据很大时,对像很有用,例如窗口的描述或文档的内容。在这些情况下,通过复制32或64位值来提供对数据的访问,而不是复制整个数据结构。但是,像整数这样的较小值与指针的大小相同(通常都是一个单词),因此传递指针与传递值没有优势。
Swift使用通过传递或传递语义为对象提供内置支持,前者使用class
声明和后者使用struct
。 Swift中的结构几乎具有与类别相同的所有功能:方法,实现协议和使用扩展机制。因此,Apple将所有数据术语视为实例,与对像或值。但是,结构不支持继承。
程序员可以自由选择哪些语义更适合应用程序中的每个数据结构。诸如Windows之类的较大结构将被定义为类,从而使它们作为指针传递。较小的结构,例如2D点,可以定义为结构,该结构将通过价值传递,并允许在没有间接或参考计数的情况下直接访问其内部数据。通过逐个价值概念固有的性能改进是,Swift将这些类型用于几乎所有常见的数据类型,包括Int
和Double
,以及通常由对象表示的类型,例如String
和Array
。使用价值类型也可能导致用户应用程序的性能改善。
Array
, Dictionary
Set
所有内容设置在写入上,以便仅在程序尝试更改其中值时才复制其数据。这意味着各种访问者俱有实际上是指向相同数据存储的指针。因此,尽管数据将数据物理存储在存储器中,但在应用程序的级别上,这些值是单独的,并且仅在需要时通过写入副本来执行物理分离。
扩展
扩展为现有类型添加了新功能,而无需子类,甚至可以访问原始源代码。扩展可以添加新方法,初始化器,计算属性,下标和协议符合符合度。一个示例可能是将咒语检查器添加到基本String
类型中,这意味着程序中的所有String
实例都可以获得拼写检查的能力。该系统也被广泛用作组织技术,可以将相关代码收集到类似图书馆的扩展中。
使用extension
关键字声明扩展名。
struct Rectangle {
let width: Double
let height: Double
}
extension Rectangle {
var area: Double {
return height * width
}
}
面向协议的编程
协议承诺某种类型实现一组方法或属性,这意味着系统中的其他实例可以在任何实现该协议的实例上调用这些方法。尽管特征集并不完全相似,但这通常在现代面向对象的语言中用作多种继承的替代。
在Objective-C和实施协议概念的大多数其他语言中,要确保在每个类中实现所需方法。 Swift添加了使用扩展添加这些方法的能力,并使用通用编程(Generics)实现它们。结合在一起,这些协议可以编写一次并支持各种实例。同样,扩展机制可用于添加协议符合对象,该对像在其定义中不列出该协议。
例如,可以声明一个协议称为Printable
,该协议可确保符合协议的实例实现description
属性和printDetails()
方法要求:
// Define a protocol named Printable
protocol Printable {
var description: String { get } // A read-only property requirement
func printDetails() // A method requirement
}
该协议现在可以由其他类型采用:
// Adopt the Printable protocol in a class
class MyClass: Printable {
var description: String {
return "An instance of MyClass"
}
func printDetails() {
print(description)
}
}
扩展名可用于添加协议符合类型。协议本身也可以扩展以提供其要求的默认实现。采用者可以定义自己的实现,或者可以使用默认实现:
extension Printable { // All Printable instances will receive this implementation, or they may define their own.
func printDetails() {
print(description)
}
}
// Bool now conforms to Printable, and inherits the printDetails() implementation above.
extension Bool: Printable {
var description: String {
return "An instance of Bool with value: \(self)"
}
}
在Swift中,就像许多支持接口的现代语言一样,协议可以用作类型,这意味着可以通过协议而不是其特定类型来定义变量和方法:
func getSomethingPrintable() -> any Printable {
return true
}
var someSortOfPrintableInstance = getSomethingPrintable()
print(someSortOfPrintableInstance.description)
// Prints "An instance of Bool with value: true"
无论哪种具体类型的someSortOfPrintableInstance
都无关紧要,编译器将确保其符合协议,因此该代码是安全的。该语法还意味着收集也可以基于协议,例如let printableArray = [any Printable]
。
扩展和协议都在Swift的标准库中广泛使用;在Swift 5.9中,标准库中所有符号中约有1.2%是协议,另有12.3%是协议要求或默认实现。例如,Swift使用扩展名将Equatable
协议添加到其许多基本类型(例如字符串和数组)中,从而可以将它们与==
Operator进行比较。 Equatable
协议还定义了此默认实现:
func !=<T : Equatable>(lhs: T, rhs: T) -> Bool
此函数定义了一种在任何符合Equatable
实例上有效的方法,提供了不等的操作员。任何实例,类或结构,都可以简单地通过符合Equatable
来自动获得此实现。
可以将协议,扩展名和仿制药组合在一起以创建复杂的API。例如,约束允许类型根据采用类型的特征有条件地采用协议或方法。仅当收集中包含的元素Equatable
时,常见的用例才能在集合类型上添加一种方法:
extension Array where Element: Equatable {
// allEqual will be available only on instances of Array that contain Equatable elements.
func allEqual() -> Bool {
for element in self {
if element != self.first {
return false
}
}
return true
}
}
并行
Swift 5.5将结构化并发引入了语言。结构化的企业使用异步/等待语法类似于Kotlin,JavaScript和Rust。在参数列表之后,使用async
关键字定义异步函数。调用异步函数时,必须在函数之前写入await
关键字,以表明执行在调用函数时可能会暂停。虽然暂停函数,但程序可能会在同一程序中运行其他并发功能。该语法允许程序清楚地召集潜在的悬架点,并避免由先前广泛使用封闭回调引起的厄运(编程)金字塔的版本。
func downloadText(name: String) async -> String {
let result = // ... some asynchronous downloading code ...
return result
}
let text = await downloadText("text1")
async let
语法允许多个函数并行运行。 await
再次用于标记该程序将暂停等待以前调用的async
函数的完成点。
// Each of these calls to downloadText will run in parallel.
async let text1 = downloadText(name: "text1")
async let text2 = downloadText(name: "text2")
async let text3 = downloadText(name: "text3")
let textToPrint = await [text1, text2, text3] // Suspends until all three downloadText calls have returned.
print(textToPrint)
可以明确创建任务组和任务组,以在运行时创建动态数量的子任务数:
let taskHandle = Task {
await downloadText(name: "someText")
}
let result = await taskHandle.value
Swift使用Actor模型来隔离可变状态,从而使不同的任务以安全的方式突变共享状态。演员关键字宣布actor
,并且是参考类型,例如类。只有一个任务可以同时访问演员的可变状态。演员可以自由访问和突变自己的内部状态,但是在单独的任务中运行的代码必须标记每个await
权限,以表明代码可能暂停,直到其他任务完成访问演员的状态为止。
actor Directory {
var names: [String] = []
func add(name: String) {
names.append(name)
}
}
let directory = Directory()
// Code suspends until other tasks finish accessing the actor.
await directory.add(name: "Tucker")
print(await directory.names)
图书馆,运行时和开发
在Apple Systems上,Swift使用与现有的Objective-C系统相同的运行时,但需要iOS 7或MACOS 10.9或更高。这也取决于大中央调度。 Swift and Objective-C代码可以在一个程序中使用,并且还可以通过扩展为C和C ++。从Swift 5.9开始, C ++代码可以直接从Swift代码中使用。在Objective-C的情况下,Swift可以相当大的访问对像模型,可用于子类,扩展和使用Objective-C代码来提供协议支持。相反的不是真的:Swift类不能在Objective-C中分类。
为了帮助开发此类程序,并重复使用现有代码,Xcode 6及更高版本提供了一个半自动化系统,该系统构建和维护桥接标头,以将Objective-C代码曝光到Swift。这采用了一个附加的标头文件的形式,该文件简单地定义或导入项目SWIFT代码所需的所有Objective-C符号。到那时,Swift可以指这些导入中声明的类型,功能和变量,就好像它们是用Swift编写的一样。 Objective-C代码还可以直接使用SWIFT代码,并通过带有项目Swift符号的Objective-C声明自动维护标头文件。例如,一个称为“ myApp”的混合项目中的Objective-C文件可以使用代码#import "MyApp-Swift.h"
访问Swift类或功能。但是,并非所有符号都可以通过这种机制获得,但是使用诸如通用类型,非对象的可选类型,复杂的枚举,甚至Unicode标识符等快速特定功能可能会使Objective-C无法访问的符号。
Swift对属性,元数据的支持也有限,该属性是由开发环境阅读的,不一定是编译代码的一部分。与Objective-C一样,属性使用@
语法,但是当前可用的集合很小。一个示例是@IBOutlet
属性,该属性将代码中的给定值标记为插座,可在接口构建器(IB)中使用。插座是将屏幕显示值绑定到代码中对象的设备。
在非应用系统上,Swift不取决于Objective-C运行时或其他Apple系统库;一组Swift“ Corelib”实现取代了它们。其中包括一个“迅捷的核心基金会”,以支持基金会套件,一个“迅捷的corelibs-libdispatch”,以支持大中央派遣人员,以及一个“ swift-corelibs-xctest”来自Xcode的API。
截至2019年,随着Xcode 11,苹果还增加了一个名为Swiftui的主要新UI范式。 Swiftui用新的声明性开发范式代替了较旧的接口构建器范式。
内存管理
Swift使用自动参考计数(ARC)来管理内存。类或闭合的每个实例都保持参考数计数,该参考计数可以使程序所保留的参考数量保持运行。当此计数达到0时,实例被交易。这种自动Deadlocation消除了垃圾收集器的需求,因为不再需要垃圾。
如果两个实例相互强烈参考,则可能会发生强烈的参考周期(例如,参考文献B,B参考a)。由于没有任何实例参考计数都无法达到零,从而导致内存泄漏。 Swift提供了weak
和unowned
关键字,以防止强大的参考周期。这些关键字允许引用一个实例,而无需增加其参考计数。 weak
参考必须是可选的变量,因为它们可以改变并成为nil
。试图访问已经在运行时错误中已被划分的结果的unowned
值。
班级中的关闭还可以通过捕获自我参考来创造强大的参考周期。可以使用捕获列表来指示要被视为弱或无人驾驶的自我参考。
class Person {
let name: String
weak var home: Home? // Defined as a weak reference in order to break the reference cycle. weak references do not increment the reference count of the instance that they refer to.
init(name: String) {
self.name = name
}
deinit { print("De-initialized \(name)") }
}
class Home {
let address: String
var owner: Person?
init(address: String, owner: Person?) {
self.address = address
self.owner = owner
}
deinit { print("De-initialized \(address)") }
}
var stacy: Person? = Person(name: "Stacy")
var house21b: Home? = Home(address: "21b Baker Street", owner: stacy)
stacy?.home = house21b // stacy and house42b now refer to each other.
stacy = nil // The reference count for stacy is now 1, because house21b is still holding a reference to it.
house21b = nil // house21b's reference count drops to 0, which in turn drops stacy's count to 0 because house21b was the last instance holding a strong reference to stacy.
// Prints:
// De-initialized 21b Baker Street
// De-initialized Stacy
侦错
Swift系统的一个关键要素是使用读取– eval -print循环(depp)在开发环境中进行干净调试和运行的能力,使其与传统系统编程相比,使其与Python的脚本能力更为常见语言。通过操场,在XCode环境中运行的交互式视图或Playgrounds应用程序中响应代码或调试器即时更改的互动视图进一步增强。游乐场允许程序员以及Markdown文档添加Swift代码。程序员可以使用控制台或XCode (例如Xcode)中的LLDB逐步介绍代码并添加断点。
与其他语言的比较
Swift被认为是C家庭编程语言,并且以各种方式与C相似:
- C中的大多数操作员也出现在Swift中,尽管某些操作员(例如
+
的行为略有不同。例如,+
在溢出的迅速陷阱中,而&+
用于表示溢出上包裹的类似C的行为。 - 卷曲括号用于分组语句。
- 变量是使用平等符号分配的,但使用两个连续的平等符号进行比较。提供了一个新的身份操作员===,以检查两个数据元素是否涉及同一对象。
- 控制语句
while
,if
和switch
相似,但具有扩展功能,例如,一个符合非直觉案例的switch
,while
支持模式匹配和有条件if
for
for i in 1. .. 10
。 - 方括号与数组一起使用,既可以声明它们,又要在其中一个索引中获得一个值。
它还与Objective-C相似:
- 基本数字类型(
Int, UInt, Float, Double
) - 类方法是继承的,例如实例方法;类方法中的
self
是该方法被调用的类。 in
枚举语法中for
。
与Objective-C的差异包括:
- 语句不需要以分号(
;
)结尾,尽管必须使用这些陈述在一行上允许多个语句。 - 没有标题文件。
- 使用类型推理。
- 通用编程.
- 功能是一流的对象。
- 枚举案例可以具有关联的数据(代数数据类型)。
- 可以重新定义运算符(操作员过载),并且可以定义新运营商。
- 字符串完全支持Unicode 。大多数Unicode字符都可以在标识符或操作员中使用。
- 没有例外处理。 Swift 2引入了一个不同且不兼容的错误处理模型。
- 较早的C家族语言的几个功能已被删除:
- 默认情况下,指针不会公开。程序员无需跟踪和标记名称以引用或取消给出。
- 作业返回没有值。这样可以防止写入
i = 0
而不是i == 0
的常见错误,这可以通过丢弃编译时间错误。 - 无需在
switch
块中使用break
语句。除非使用fallthrough
陈述,否则单个案件不会落在下一个情况下。 - 变量和常数始终是初始化的,并且始终检查数组边界。
-
整数溢出,导致C中签名整数的不确定行为被困在Swift中的运行时错误。程序员可以选择使用特殊的算术运算符
&+
,&-
,&*
,&/
and&%
来允许溢出。属性min
和max
用于所有整数类型的Swift定义,可用于安全检查潜在的溢出,而不是依靠为外部库中的每种类型定义的常数。 if
andwhile
的单态形式,允许省略陈述周围的牙套。- 不支持(从Swift 3开始)(从Swift 3开始)(从Swift 3开始) (从Swift 3开始)
for (int i = 0; i < c; i++)
C风格枚举。 - 未支撑(从Swift 3开始),前和减少的运算符(
i++
,--i
...)是不支持的,更重要的是,由于c-Stylefor
语句的C风格也不支持Swift 3 。
开发和其他实现
因为Swift可以在Linux上运行,因此有时也将其用作服务器端语言。已经开发了一些网络框架,例如IBM的Kitura (现已停产),完美和蒸气。
苹果公司还成立了一个官方的“服务器API”工作组,Swift开发人员社区的成员扮演着核心角色。
Swift的第二次免费实现,该实施是针对可可, Microsoft的常见语言基础结构( .NET )以及Java和Android平台的第二次免费实现,这是RemoBjects Software的元素编译器的一部分。
通过结合LLVM和Macintosh程序员研讨会的工具链,可以在Mac OS 9上运行一小部分语言子集。