原文链接:http://www.ioswift.org/
1.欢迎使用Swift
欢迎使用Swift语言;
从这篇文章开始,我们正式进入Swift学习,本系列文章翻译自苹果Swift官方学习文档《The Swift Programming Language》,在学习过程中如果您发现文档有错误之处,请联系我们(http://www.ioswift.org/);
因为在翻译过程中是团队翻译,风格可能有所不同,如果给您带来阅读上的不便,敬请谅解。
2.关于Swift
Swift 是一种新的编程语言,主要用于开发 IOS 和 OS X 应用。Swift 结合了 C 和 Objective-C 的优点并且不受 C 的兼容性的限制。Swift 采用了安全的编程模式,并添加现代的编程功能,使编程更加简单、灵活和有趣。界面则基于备受青睐的 Cocoa 和 Cocoa Touch 框架,展示了软件开发的新方向。
Swift 已经存在了多年。苹果公司改进了现有的编译器、调试器、框架结构。通过ARC(Automatic Reference Counting,自动引用计数)来简化内存管理。在 Foundation 和 Cocoa 的基础上构建框架。Objective-C 本身支持块、集合语法和模块,支持现代编程语言技术。得益于这些基础工作,Swift 将用于未来的苹果软件的开发。
对于 Objective-C 开发者来说,对Swift会有似曾相识的感觉。Swift 采用了 Objective-C 的命名参数和动态对象模型。提供了对 Cocoa 框架和 mix-and-match 的互操作性。基于这些基础,Swift引入了很多新特性,并支持面向过程和面向对象编程。
对于初学者来说 Swift 也很友好。它是第一个既满足工业标准又像脚本语言一样充满表现力和趣味的编程语言。它支持代码预览,允许程序员在不编译和运行应用程序的前提下运行 Swift 代码并实时查看结果。
Swift 集成了现代编程语言思想和苹果工程师文化的智慧。编译器对性能进行了优化,编程语言对开发进行了优化,两者互不干扰。Swift 即可以用于开发“hello, world”这样的小程序,也可以用于开发一个完整的操作系统。所有这些使得 Swift 成为苹果软件开发者一项值得的投资。
用 Swift 编写 IOS 和 OS X 应用将是一场美妙的体验,Swift 会持续推进新特性和兼容性。我们迫不及待的看到你用 Swift 可以创造什么。
3.Swift预览
一般来说,编程语言教程中的第一个程序是在屏幕上打印“Hello, world”。在 Swift 中,可以用一行代码实现:
如果你写过 C 或者 Objective-C 代码,那你应该很熟悉这种形式——在 Swift 中,这行代码就是一个完整的程序。你不需要为了输入输出或者字符串处理导入一个单独的库。全局作用域中的代码会被自动当做程序的入口点,所以你也不需要 main 函数。你同样不需要在每个语句结尾写上分号。
这个教程会通过一系列编程例子来让你对 Swift 有初步了解,如果你有什么不理解的地方也不用担心——任何本章介绍的内容都会在后面的章节中详细讲解。
3.1.简单值
let 做常量 var 做变量。常量值在编译中并不需要被知道,但是必须一次性精确的进行赋值:也就是说只能在在定义的时候赋值一次,但是可以多次使用
myVariable = 50
let myConstant = 42
常量和变量在设定值时必须采用相同格式。但并不需要定义精准的类型。创建一个常量或变量时提供一个值,让编译器判断其类型。在上面的例子中,编译器指定 myVariable 是一个整数,因为它的初始值是整数。
若初始化时未提供足够信息(没有初始值),可以在变量后面指定类型,用冒号隔开。
let implicitDouble = 70.0
let explicitDouble: Double = 70
练习:创建一个类型是Float的,值为4的常量
值在转化为另一种类型时从不具有隐含性。如果需要转化值到另一种类型,请明确性地为值进行格式转换。
let width = 94
let widthLabel = label + String(width)
练习:试着将最后一行的 String 转换去掉,你会得到什么错误?
更简单的方法将值转换为String:将值写在括号中,并在括号前添加一个反斜杠。例:
let oranges = 5
let appleSummary = "I have \(apples) apples."
let fruitSummary = "I have \(apples + oranges) pieces of fruit."
通过 [] 创建一个数组和字典,通过 index 和 key 获取对应的值
shoppingList[1] = "bottle of water"
var occupations = [
"Malcolm": "Captain",
"Kaylee": "Mechanic",
]
occupations["Jayne"] = "Public Relations"
创建空数组和字典,以及初始化语法。
let emptyDictionary = Dictionary<String, Float>()
为了防止类型信息被更改,空数组列用[],空字典用[:]进行初始化 - 例如,为变量赋新值和给函数传递参数的时候。
3.2.流程控制
使用 if 和 switch 判断条件,使用 for-in 、 for 、 while 和 do-while 处理循环。条件和循环变量的括号可以省略,语句体的大括号是必须的。
let individualScores = [75, 43, 103, 87, 12]
var teamScore = 0
for score in individualScores {
if score > 50 {
teamScore += 3
} else {
teamScore += 1
}
}
teamScore
在 if 语句中,条件必须是一个布尔表达式 —— 这意味着像 if score { ... } 这样的代码将报错,而不会隐形地与 0 做对比。
你可以一起使用 if 和 let 来处理条件值缺失的情况。有些变量的值是可选的。一个可选的值如果是一个具体的值或者是 nil ,那表明这个值缺失。在类型后面加一个 ? 来标记这个变量的值是可选的。
var optionalString: String? = "Hello"
optionalString == nil
var optionalName: String? = "John Appleseed"
var greeting = "Hello! "
if let name = optionalName {
greeting = "Hello, \(name)"
}
练习:把 optionalName 改成 nil,greeting 会是什么?添加一个 else 语句,当 optionalName 是 nil 时给 greeting 赋一个不同的值。
如果变量的可选值是 nil ,条件会判断为 false ,并且大括号中的代码会被跳过。如果不是nil,会将值赋给let后面的常量,这样代码块中就可以使用这个值了。
使用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."
}
练习:删除 default 语句,看看会有什么错误?
运行 switch 中匹配到的子句之后,程序会退出switch语句,并不会继续向下运行,所以不需要在每个子句结尾写break。
使用 for-in 遍历字典,需要两个变量来表示键和值。
let interestingNumbers = [
"Prime": [2, 3, 5, 7, 11, 13],
"Fibonacci": [1, 1, 2, 3, 5, 8],
"Square": [1, 4, 9, 16, 25],
]
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
你可以在循环中使用 .. 来表示范围,也可以使用传统的写法,两者是等价的:
var firstForLoop = 0
for i in 0..3 {
firstForLoop += i
}
firstForLoop
var secondForLoop = 0
for var i = 0; i < 3; ++i {
secondForLoop += 1
}
secondForLoop
使用 .. 表示的范围不包括上界,如果想包括的话需要使用 ...
3.3.函数和闭包
使用 func 来声明一个函数,通过函数的名字和参数来调用函数。使用 -> 指定函数返回值(分离了返回值和参数)
return "Hello \(name), today is \(day)."
}
greet("Bob", "Tuesday")
使用元组定义函数的多个返回值
return (3.59, 3.69, 3.79)
}
getGasPrices()
传递可变数量的参数,通过数组获取参数
var sum = 0
for number in numbers {
sum += number
}
return sum
}
sumOf()
sumOf(42, 597, 12)
函数可以嵌套,被嵌套的函数可以访问外部函数的变量。可以通过函数的嵌套来重构太长或者太复杂的函数。
var y = 10
func add() {
y += 5
}
add()
return y
}
returnFifteen()
函数是一级类型,这意味着函数可以使用另一个函数作为返回值
func addOne(number: Int) -> Int {
return 1 + number
}
return addOne
}
var increment = makeIncrementer()
increment(7)
函数也可以使用另一个函数作为参数
for item in list {
if condition(item) {
return true
}
}
return false
}
func lessThanTen(number: Int) -> Bool {
return number < 10
}
var numbers = [20, 19, 7, 12]
hasAnyMatches(numbers, lessThanTen)
实际上函数是一种特殊的闭包。通过 {} 创建一个匿名的闭包,使用 in 将执行体和参数、返回值进行分离
(number: Int) -> Int in
let result = 3 * number
return result
})
有多种更简明创建闭包的方法。如果一个闭包类型已知,比如作为一个回调函数,这时可以忽略它的参数类型、或则返回值类型、或则二者都忽略。单条语句的闭包可以直接将语句的结果当做返回值。
可以通过参数的位置而不是名称来引用参数--这对于简短的闭包来说非常有用;闭包作为最后一个参数传递给函数时,可以直接跟在括号后面。
3.4.对象和类
使用 class 并紧跟类名创建一个类。属性的声明类似常量和变量的声明,不同的是作用范围是这个类。同样的,方法和函数的声明一样。
var numberOfSides = 0
func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides."
}
}
通过类名和 () 创建一个类的实例,实例通过点语法访问属性和方法。
shape.numberOfSides = 7
var shapeDescription = shape.simpleDescription()
var numberOfSides: Int = 0
var name: String
init(name: String) {
self.name = name
}
func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides."
}
}
还是通过构造器(像name)。
使用 deinit 创造一个析构函数,它可以在对象被删除之前进行一些清理工作。
子类的定义通过 : 后面紧跟父类名称的方式。
当然不是每个类都需要标准的根类,所以可以忽略父类。
如果子类需要重写父类的方法,使用 override 关键字;如果没有使用 override 就重写父类的方法,编译器将会报错。
同样的编译器会检查 override 是否在父类中。
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()
为了更简单的存储属性,属性可以有 setter 和 getter 方法
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
在perimeter的 setter 中,新值有一个隐式的名称是newValue。可以在set之后的括号中提供一个明确的名称
注意 EquilateralTriangle 类的构造器执行了三步:
1.设置子类声明的属性值
2.调用父类的构造器
3.改变父类定义的属性值。调用方法、getters和setters都可以在这个阶段完成。
如果你不需要计算属性值,但是需要在设置新值之前或者之后执行一些代码,可以通过 willSet 和 didSet 完成。比如,确保三角形的边长和正方形的边长相同。
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
类的方法和函数有一个重要的区别。函数的参数名只在函数内部使用,方法在调用的时候需要显式说明参数名(除了第一个参数)。
默认情况下,方法调用时和方法内部使用的参数名是一样的;不过你也可以定义第二个名字,它只能用在方法内部。
var count: Int = 0
func incrementBy(amount: Int, numberOfTimes times: Int) {
count += amount * times
}
}
var counter = Counter()
counter.incrementBy(2, numberOfTimes: 7)
处理可选值时,可以在操作(如方法、属性和子脚本)之前加 ? ,如果 ? 之前是 nil ,那么 nil 之后的都会被忽略,并且整个表达式返回 nil 。否则 ? 之后的都会被执行。这两中情况下,整个表达式的值是可选值。
let sideLength = optionalSquare?.sideLength
3.5.枚举和结构
使用 enum 创建一个枚举。像类和所有其他的命名类型一样,枚举可以与他们相关的方法
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()
上面的例子表名,枚举的原始值类型是 Int ,所以需要指定第一个原始值。其余的原始值被顺序分配。字符串、 浮点数都可以作为枚举的原始值。
使用 toRaw 和 fromRaw 函数转换原始值和枚举值。
let threeDescription = convertedRank.simpleDescription()
}
枚举的成员值是实际值,并不是其原始值的另一种方式。事实上,在这种情况下,如果原始值没有意义,您不需要设置。
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()
注意,Hearts成语被引用有两中方式:将值分配给 hearts 常量,枚举成员 Suit.Hearts 的全名被引用,因为常量没有一个明确的
指定类型。在 switch 中,枚举通过缩写形式.Hearts 被引用,因为 self 的值是被已知是一个 Suit 。在已知变量类型的情况下可以使用缩写。
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()
一个枚举成员的实例有实例值与之对应。相同的枚举成员实例可以有不同的值。实例值和原始值是不同的:对于所有实例来说,枚举成员的原始值是一样的,在定义枚举的时候进行原始值的设置。
例如,假设从服务器获取日出和日落时间,服务器会返回正常信息或者错误信息。
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)"
}
3.6.协议和扩展
使用 protocol 声明一个接口
var simpleDescription: String { get }
mutating func adjust()
}
类、枚举和结构都可以实现接口
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
注意在 SimpleStructure 声明的时候,使用 mutating 关键字标记一个会修改结构体的方法。SimpleClass 的声明不需要方法标记,因为类中的方法经常会修改类。
使用 extension 为现有的类型添加功能,比如添加一个计算属性的方法。你可以在任何地方使用 extension 来给任意类型添加协议,甚至是从外部库或者框架中导入的类型。
var simpleDescription: String {
return "The number \(self)"
}
mutating func adjust() {
self += 42
}
}
7.simpleDescription
你可以像使用其他命名类型一样,使用一个接口名称 :例如,创建一个有不同类型但是都实现同一个接口的对象集合。当你处理接口类型的值时,接口外定义的方法不可用。
protocolValue.simpleDescription
// protocolValue.anotherProperty // Uncomment to see the error
即使 protocolValue 变量在运行时的类型是 simpleClass,但是编译器会把它当做 ExampleProtocol 类型。这表示你不能调用实现此接口的类中的自有的方法或者属性。
3.7.泛型
在尖括号(< >)中写一个名字来创建一个泛型函数或者类型
var result = ItemType[]()
for i in 0..times {
result += item
}
return result
}
repeat("knock", 4)
你可以创建函数和方法的通用形式,以及类、枚举、结构。
enum OptionalValue<T> {
case None
case Some(T)
}
var possibleInteger: OptionalValue<Int> = .None
possibleInteger = .Some(100)
在类型名后面使用 where 来指定一个需要的列表 —— 例如,限定实现一个接口的类型,限定两个类型要相同,或者限定一个类必须有一个特定的父类。
for lhsItem in lhs {
for rhsItem in rhs {
if lhsItem == rhsItem {
return true
}
}
}
return false
}
anyCommonElements([1, 2, 3], [3])
相关推荐
总的来说,Swift语言为iOS开发提供了一个高效、安全且易于学习的环境。通过深入学习Swift,不仅可以提升个人技能,也为参与苹果生态系统的创新和开发打开了大门。无论是初入编程的新手还是经验丰富的开发者,Swift都...
Swift语言实战入门源代码是针对初学者的一份宝贵资源,它包含了《Swift语言实战入门》这本书中的所有示例和练习代码。Swift是由Apple开发的一种强大且直观的编程语言,用于构建iOS、iPadOS、macOS、watchOS和tvOS的...
swift学习例子集合 Swift语言基础 【实例简介】swiftui 学习例子集合,多个页面集合到一个项目中,可供参考学习 【核心代码】. ├── swift-example │ ├── Example │ │ ├── AppDelegate.swift │ │ ├─...
swift语言实战晋级的扫描版 非常清晰 附带书签 供大家学习参考
在“Swift语言快速入门”这个教程中,我们可以期待学习到以下几个关键知识点: 1. **基础语法**:Swift的基础语法简洁明了,包括变量和常量的声明(var和let)、数据类型(Int、Double、String等)、运算符(算术、...
Swift语言以其安全、现代和简洁的特点迅速受到开发者的青睐,而《Swift语言实战入门》作为一本旨在帮助开发者掌握和深入应用Swift语言的教程,由伍星、罗飞、刘志华、王浩力、刘蕾等多位经验丰富、专业背景深厚的...
本资源“Swift语言学习基础Demo集合”旨在为初学者提供一系列实践示例,帮助他们更好地理解和掌握Swift的基础概念。 1. **变量与常量**:在Swift中,我们使用`var`声明变量,`let`声明常量。通过这些基础元素,你...
Swift语言是苹果公司推出的一种现代、安全、强大的编程语言,主要应用于iOS、macOS、watchOS和tvOS的开发。自2014年发布以来,Swift迅速成为了全球开发者首选的iOS开发语言之一,它的设计目标是提升开发效率,简化...
Swift语言是一种现代、安全且性能优异的编程语言,特别适用于苹果操作系统的应用程序开发。Swift语言的特点在于其简洁、易学和强大的编译器,它能够快速发现程序中的错误,并提供实时反馈。 首先,Swift语言的基本...
Swift语言是苹果公司推出的一种强大的、现代化的编程语言,用于构建iOS、iPadOS、macOS、watchOS和tvOS的应用程序。本教程“Swift语言教程:Swift项目实战”旨在通过实际项目开发,深入理解Swift语言的各个方面,...
自 2014年 WWDC 发布 Swift 语言以来,本项目 一直致力于将主流 Swift 中文学习、开发资源汇集于此,并且尽力紧密地跟踪、甄选优秀 Swift 开源项目,以方便开发者快速获得并使用。考虑 Swift 已经正式发布超过四年半...
对于Swift语言的广大开发者而言,这不仅是一个编程语言的学习资源,也是一个关于团队协作和奉献精神的启示录。通过本教程的学习,开发者们可以更好地掌握Swift语言,为构建强大的iOS应用打下坚实的基础。
Swift语言是苹果公司于2014年推出的一种面向对象的编程语言,旨在为iOS、macOS、watchOS和tvOS等平台的开发提供更高效、简洁和安全的编程体验。本快速入门教程将帮助初学者掌握Swift的基础知识,逐步进阶到高级编程...
Swift语言实战精讲的课程源文件是一份深入学习Swift编程的宝贵资料,涵盖了从基础到高级的各种主题。Swift是由Apple开发的一种强大且易学的编程语言,主要用于iOS、iPadOS、macOS、watchOS和tvOS的应用开发。这份...
Swift编程入门教程,从零开始,深入浅出的Swift语言学习指南; Swift编程入门教程,从零开始,深入浅出的Swift语言学习指南; Swift编程入门教程,从零开始,深入浅出的Swift语言学习指南; Swift编程入门教程,从零...
《Swift语言》中文版API是苹果公司为开发者提供的官方文档,旨在帮助中文用户更好地理解和使用Swift编程语言。Swift是一款高效、安全、互动性强的开源编程语言,被广泛应用于iOS、iPadOS、macOS、watchOS以及tvOS的...
Swift语言案例资源涵盖了从基础语法到高级功能...总之,Swift语言案例资源是开发者学习和实践Swift语言的重要参考,它们提供了从基础到高级的系统学习材料,以及丰富的实际应用场景和工具库支持。通过学习和实践这些案
Swift 通过向其他现代编程模式学习,定义了大量类来避免常⻅的编程错误: 变量一定是在使用前初始化的; 数组索引会检查越界错误; 整数会检查溢出; 可选项保证了 nil 值会显式处理; 内存自动管理; 错误处理允许从意外...