有些东西很简单,但是我还是把它记录了下来。
推荐阅读
the swift programming language swift 5.2
基础语法快速浏览
基础
print("Hello, world!")
Swift打印使用print函数,无需导入单独的库来实现输入输出或字符串处理功能。
- main()
无需关心mian函数,Swift项目中已经自动添加了全局的相关程序的入口,我们只需要在其他文件中编写hello world打印即可。
代码最后也不必须添加分号。
- 变量常量
var 声明一个变量
let 声明一个常量,常量的只需赋值一次,可在多个地方使用。
常量或变量的类型,必须要与值得类型相同。声明的时候不必须声明类型,在创建常量或变量时候给它一个值,可以让编译器推断其类型。
例如:var number = 42; 声明一个整数类型的变量,编译器通过42,自动识别number的类型为整形。
如果初始值不能明确的指出变量/常量类型,或者未给变量/常量赋值得话,需要在变量后面加冒号来指明变量的类型。
例如:var score : Double = 70;
值类型转化
值不会隐式转换为其他类型,如果要转换,则需要将值创建为其他类型的实例
let label = "The width is "
let width = 94
let widthLabel = label + String(width)
反斜杠和括号搭配,可以在字符串中包含值。
let apples = 3
let oranges = 5
let appleSummary = "I have \(apples) apples."
let fruitSummary = "I have \(apples + oranges) pieces of fruit."
如果是需要字符串多行输出,则使用 ‘’’’’’
let quotation = """
I said "I have \(4) apples.
And then I said "I have \(5) pieces of fruit.
"""
print(quotation);
使用方括号[]来创建字典或数组,最后一个元素后面允许添加逗号
var shoppingList = ["catfish", "water", "tulips"] //便捷构造数组
shoppingList[1] = "bottle of water" // 给数组第一个元素赋值
var occupations = [ "Malcolm": "Captain","Kaylee": "Mechanic",] // 便捷构造字典
occupations["Jayne"] = "Public Relations" // 给key为Jayne的value赋值为Public Relations
Swift中没有可变或者不可变数组的概念,数组随着添加元素而自动增长
shoppingList.append("blue paint")
如果创建一个空的数组/字典,请使用初始化方法
let emptyArray = [String]() // 初始化一个空数组,指定数组的元素类型为String类型
let emptyDictionary = [String: Float]() // 初始化一个空字典,指定字典的key和value的类型分别是String和Float
如果编译器可以推断出数据类型,则数组和字典的初始化也可以不指定相关的类型,但是这时候开发者需要注意一下,不能插入不同类型的数据。我不建议程序这样写,推荐初始化时指定相关类型。
shoppingList = []
occupations = [:]
控制流
if 、if else、switch、for in、for
这些都大同小异…
方法
- func声明函数
使用 func 来声明一个函数。通过函数名加上后面括号里的参数来调用函数,这个跟其他语言大差不离。
// 声明并实现greet函数
func greet(person: String, day: String) -> String {
return "Hello \(person), today is \(day)."
}
// 调用greet函数
greet(person: "Bob", day: "Tuesday")
person和day是两个形参,它们都是String类型的。-> 指明返回值是String类型。
调用函数时,传入两个实参Bob和Tuesday。
- 参数标签
关于参数标签,对于开发者来说,个人感觉没什么卵用,这样设计的目的是什么呢?
默认情况下,函数使用其参数名称作为其参数的标签。或者我们可以在在参数名称前写一个自定义参数标签。或者在参数名前加_表示不使用任何参数标签。
- 使用元祖返回复合值
如果一个函数需要多个返回值的话,使用元祖对返回值进行包装并返回。
func calculateStatistics(scores: [Int]) -> (min: Int, max: Int, sum: Int) {
var min = scores[0]
var max = scores[0]
var sum = 0
for score in scores {
if score > max {
max = score
} else if score < min {
min = score
}
sum += score
}
return (min, max, sum)
}
let statistics = calculateStatistics(scores: [5, 3, 100, 3, 9])
print(statistics.sum)
// Prints "120"
print(statistics.2)
// Prints "120"
- 函数嵌套
即一个函数的实现里面,嵌套另一个函数。
func returnFifteen() -> Int {
var y = 10
func add() {
y += 5
}
add()
return y
}
returnFifteen()
returnFifteen()中嵌套了一个add()函数及其实现。
感觉这个功能还是挺好的。
- 函数作为返回值
func makeIncrementer() -> ((Int) -> Int) {
func addOne(number: Int) -> Int {
return 1 + number
}
return addOne
}
var increment = makeIncrementer()
increment(7)
目前不太清楚业务里应该怎么用,直接将一个函数作为返回值倒是很有趣的。
- 函数作为参数
// 这里定义了一个函数hasAnyMatches,传入参数是一个数组和一个函数,如果数组里的元素都满足condition这个函数的条件,则返回YES。
func hasAnyMatches(list: [Int], condition: (Int) -> Bool) -> Bool {
for item in list {
if condition(item) {
return true
}
}
return false
}
// 这里定义了一个函数lessThanTen,功能是传入参数和10比较大小,如果比10小返回YES,否则返回NO。
func lessThanTen(number: Int) -> Bool {
return number < 10
}
// 定义一个数组
var numbers = [20, 19, 7, 12]
// 调用函数hasAnyMatches
hasAnyMatches(list: numbers, condition: lessThanTen)
hasAnyMatches()作为一个匹配数组numbers元素的函数,如果有一个元素满足lessThanTen()这个函数的条件,即其中任意一个元素小于10的话,直接返回true,否则匹配完,所有元素都大于或者等于10的话,返回false。
类和对象
- 声明一个类
class 关键字声明类,在类中声明变量和函数的方法和前面的都一样。
class Shape {
var numberOfSides = 0
func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides."
}
}
- 实例化类对象
var shape = Shape() // 初始化一个对象
shape.numberOfSides = 7 // 给属性numberOfSides赋值
var shapeDescription = shape.simpleDescription() // 调用方法
以下写法和overwrite 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."
}
}
枚举和结构体
定义一个枚举
enum 枚举名:类型 {
case...
case...
}
Swift中枚举可以有与之相关联的方法。
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.rawValue)
}
}
}
let ace = Rank.ace // 获取枚举值
let aceRawValue = ace.rawValue // 获取枚举值对应的value
let aceString = ace() // Rank.ace() 调用枚对应的函数
这么看来定义一个枚举和定义一个类有点相似,可以定义方法。
这里举了一个例子,枚举这么用的话让感觉特别棒
enum ServerResponse {
case result(String, String)
case failure(String)
}
let success = ServerResponse.result("6:00 am", "8:09 pm")
let failure = ServerResponse.failure("Out of cheese.")
switch success {
case let .result(sunrise, sunset):
print("Sunrise is at \(sunrise) and sunset is at \(sunset).")
case let .failure(message):
print("Failure... \(message)")
}
定义一个结构体
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()
结构支持许多与类相同的行为,包括方法和初始化程序。
结构和类之间最重要的区别之一是,结构在代码中传递时始终会被复制,而类是通过引用传递的。
Runtime源码中我们可以看到类的定义其本质就是一个结构体,这个结构体中有成员变量,成员函数等。
协议和扩展
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
用于extension向现有类型添加功能
extension Int: ExampleProtocol {
var simpleDescription: String {
return "The number \(self)"
}
mutating func adjust() {
self += 42
}
}
print(7.simpleDescription)
错误处理
- do- catch
do {
let printerResponse = try send(job: 1040, toPrinter: "Bi Sheng")
print(printerResponse)
} catch {
print(error)
}
- try?
let printerSuccess = try? send(job: 1884, toPrinter: "Mergenthaler")
有点像三目运算,将结果转换为可选的。
*defer