- Var 表示变量, let表示常量。
- 数组和map, 都用中括号[].可以直接赋值。可以用下标或键访问。
var shoppingList = ["catfish", "water", "tulips", "blue paint”]//最后一个可以加逗号。
shoppingList[1] = "bottle of water"
var occupations = [
"Malcolm": "Captain",
"Kaylee": "Mechanic",
]
空数组就赋[], 而空map 就赋[:]。有点无语。
- 字符串处理。用\() 可以处理字符串的变量插入。
let apples = 3
let oranges = 5
let appleSummary = "I have \(apples) apples."
let fruitSummary = "I have \(apples + oranges) pieces of fruit."
三个双引号(""")来包含多行字符串内容
4.swift也有可空类型, String?, 同样用!表示非空。但是不像其他语言用null表示空, 而是nil。非要别出新裁。
双??的用法和dart一样。
- Switch语法,支持任何类型的case。而且不需要用break, 找到case后执行完自己会退出switch,不会往下执行。当需要提前退出时,也可以用break。多个case可以用逗号合并。还有:区别匹配case 100..<1000;元组匹配(1,1)。 Case let Where语句。fallthrough可以继续下一个case。
- 条件语句和循环语句都允许不用包含在括号里面, if, for-in, while,repeat-while。
- repeat-while就是do-while
- 在for循环中,..< 来表示下标范围, 但不包含上界, 如果包含的就用…
var total = 0
for i in 0..<4 {// 0到3
total += i
}
for i in 0..<4 {// 0到4
total += i
}
- 强制类型转换是用转换后的类型加上括号。Int(3.14)转换后就是3.
- 可以定义类名的别名,typealias。 typealias AudioSample = Int AudioSample就可以当Int来使用了。这种傻逼功能还是少用。让人想起c/c++宏定义魔窟。
- 元组。 (name:type, name:type),和kotlin的很像。let http200Status = (statusCode: 200, description: "OK”)。针对函数返回值很有用的。
- 可选绑定 if let的用法。 把一个可控类型的参数赋值给一个正常参数,如果可控参数有值,就赋值成功,同时if语句是true, 在if语句里面就不需要用!来表示非空了。还可以多个一起,只要一个不成功就是false。
if let firstNumber = Int("4"), let secondNumber = Int("42"), firstNumber < secondNumber && secondNumber < 100 {
}
- 运算符方面,包含了java的所有功能, 包括三元运算符是一样的,这点很好比kotlin强。另外,增加了??和单双边运算符[…]
- 字符串方面和java大同小异。 字符串插值\(), 去语义#” ”#. 字符串拼接也是+,和java一样。
- 数组方面。 数组类型定义是这样:[type],由于有类型推断,也可以不用写。 支持两个数组相加后合并到一起。
15.数组修改,追加append, 删除remove, 追加另外一个数组+=, 插入insert, 判空isEmpty。按照方法来说,应该是链表实现的。
16.集合set,方法和java差不多。
- Guard关键词,和 if let相识,只是在不满足时会跟一个else。
- 关于函数,总体和kotlin一样。但返回是用->表示;在函数参数前可以加标签注释, 如果参数名前加了下划线_j就不能加了;动态参数用…. ;当函数体只有一条代码,返回时,可以不带return;函数类型的使用也和kotlin类似。
- 闭包整体和kotlin的一样。闭包是引用类型。
reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in return s1 > s2 } )
尾随方式
reversedNames = names.sorted(){ (s1, s2) -> Bool in return s1 > s2 }
可以用$0,$1…,来特指参数。 如果其中一个不用,那用_替代。
reversedNames = names.sorted(){ return $0>$1 }
可以把括号也省掉
reversedNames = names.sorted{ return $0>$1 }
如果闭包在最后,那么也可以是尾随闭包。
func test1( values:String, process:()->Bool){
}
test1(values:""){true}
闭包逃逸,就是说闭包传到函数里面,但是没有执行闭包, 只是把闭包引用给了别人。要加一个 @escaping
var completionHandlers: [() -> Void] = []
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
completionHandlers.append(completionHandler)
}
自动闭包就是函数定义。
let customerProvider = { customersInLine.remove(at: 0) } //定义了一个函数;
在函数中直接写执行代码没有括号。要加 @autoclosure
func serve(customer customerProvider: @autoclosure () -> String) {
print("Now serving \(customerProvider())!")
}
serve(customer: customersInLine.remove(at: 0))
可以即是自动闭包又可以是逃役闭包,
var customerProviders: [() -> String] = []
func collectCustomerProviders(_ customerProvider: @autoclosure @escaping () -> String) {
customerProviders.append(customerProvider)
}
- 枚举,成员前要加case。
两种定义方式:
enum CompassPoint {
case north
case south
case east
case west
}
enum Planet {
case mercury, venus, earth, mars, jupiter, saturn, uranus, neptune
}
var directionToHead = CompassPoint.west
一旦 directionToHead 被声明或者被推断出为 CompassPoint 类型,可以间断成这样:
directionToHead = .east
遍历枚举成员:
enum Beverage: CaseIterable {
case coffee, tea, juice
}
let numberOfChoices = Beverage.allCases.count
枚举关联值,这个功能很好,就是附带信息用的。和kotlin的sealed class有点像,就是没有执行方法。比如把异常的code和error情况塞到里面。
enum Barcode {
case upc(Int, Int, Int, Int)
case qrCode(String)
}
var productBarcode = Barcode.upc(8, 85909, 51226, 3)
使用时如下:
switch productBarcode {
case .upc(let numberSystem, let manufacturer, let product, let check):
print("UPC: \(numberSystem), \(manufacturer), \(product), \(check).")
case .qrCode(let productCode):
print("QR code: \(productCode).")
}
枚举初始值。枚举值可以是任何类型的值,可以是int/double/String。
和C#一样,会递增。如果不设值第一个默认是0
enum Planet: Int {
case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune
}
enum CompassPoint: String {
case north, south, east, west
}
let earthsOrder = Planet.earth.rawValue
// earthsOrder 值为 3
let sunsetDirection = CompassPoint.west.rawValue
// sunsetDirection 值为 "west"
前面提到“枚举值可以是任何类型的值”。所以也可以是枚举自身啊。所以这里就有递归问题了。
而且递归是支持的,用关键字:indirect
enum ArithmeticExpression {
case number(Int)
indirect case addition(ArithmeticExpression, ArithmeticExpression)
indirect case multiplication(ArithmeticExpression, ArithmeticExpression)
}
你也可以在枚举类型开头加上 indirect 关键字来表明它的所有成员都是可递归的:
indirect enum ArithmeticExpression {
case number(Int)
case addition(ArithmeticExpression, ArithmeticExpression)
case multiplication(ArithmeticExpression, ArithmeticExpression)
}
例子:let five = ArithmeticExpression.number(5)
let four = ArithmeticExpression.number(4)
let sum = ArithmeticExpression.addition(five, four)
let product = ArithmeticExpression.multiplication(sum, ArithmeticExpression.number(2))
因为枚举的最终使用还是在选择语句上:
func evaluate(_ expression: ArithmeticExpression) -> Int {
switch expression {
case let .number(value):
return value
case let .addition(left, right):
return evaluate(left) + evaluate(right)
case let .multiplication(left, right):
return evaluate(left) * evaluate(right)
}
}
- 结构体struct。 swift还保留着struct。可能是内存回收机制缺陷导致的,便于一些情况下的回收。还有就是速度更快一点,相当于是在栈上。
struct是值类型,所以赋值的时候是值拷贝,生成了另外一个struct实例。和类差异并不大。
和类相同的地方:
- 定义属性用于存储值
- 定义方法用于提供功能
- 定义下标操作用于通过下标语法访问它们的值
- 定义构造器用于设置初始值
- 通过扩展以增加默认实现之外的功能
- 遵循协议以提供某种标准功能
类还有如下的附加功能:
- 继承允许一个类继承另一个类的特征
- 类型转换允许在运行时检查和解释一个类实例的类型
- 析构器允许一个类实例释放任何其所被分配的资源
- 引用计数允许对一个类的多次引用
类的恒等运算符
- 相同(===)
- 不相同(!==)
使用这两个运算符检测两个常量或者变量是否引用了同一个实例:
if tenEighty === alsoTenEighty {
print("tenEighty and alsoTenEighty refer to the same VideoMode instance.")
}
- 属性。 分为存储属性和计算属性。 存储属性就是property,计算属性就是getter/setter方法。
变量用var,常量用let.
懒加载,用 lazy 来标示一个延时加载存储属性。必须声明成var, 因为是构造后才使用, 不能是let。
但是swift的懒加载不支持多线程安全。
class DataImporter {
/*
DataImporter 是一个负责将外部文件中的数据导入的类。
这个类的初始化会消耗不少时间。
*/
var fileName = "data.txt"
// 这里会提供数据导入功能
}
class DataManager {
lazy var importer = DataImporter()
var data = [String]()
// 这里会提供数据管理功能
}
计算属性getter/setter, 下面是完整的方式:
struct Point {
var x = 0.0, y = 0.0
}
struct Size {
var width = 0.0, height = 0.0
}
struct Rect {
var origin = Point()
var size = Size()
var center: Point {
get {
let centerX = origin.x + (size.width / 2)
let centerY = origin.y + (size.height / 2)
return Point(x: centerX, y: centerY)
}
set(newCenter) {
origin.x = newCenter.x - (size.width / 2)
origin.y = newCenter.y - (size.height / 2)
}
}
}
简化Get, 当单行代码时。可以省去return。
简化Set, 用newValue替代设置值。
struct CompactRect {
var origin = Point()
var size = Size()
var center: Point {
get {
Point(x: origin.x + (size.width / 2),
y: origin.y + (size.height / 2))
}
set {
origin.x = newValue.x - (size.width / 2)
origin.y = newValue.y - (size.height / 2)
}
}
}
当只有getter时,可以简化, 省去get关键字和{}。
struct Cuboid {
var width = 0.0, height = 0.0, depth = 0.0
var volume: Double {
return width * height * depth
}
}
属性观察器
- willSet 在新的值被设置之前调用
- didSet 在新的值被设置之后调用
即使新值和当前值相同的时候也不例外。
在父类初始化方法调用之后,在子类构造器中给父类的属性赋值时,会调用父类属性的 willSet 和 didSet 观察器。而在父类初始化方法调用之前,给子类的属性赋值时不会调用子类属性的观察器。
class StepCounter {
var totalSteps: Int = 0 {
willSet(newTotalSteps) {
print("将 totalSteps 的值设置为 \(newTotalSteps)")
}
didSet {
if totalSteps > oldValue {
print("增加了 \(totalSteps - oldValue) 步")
}
}
}
}
属性包装器,就是getter/setter的套用模版。可以是结构体也可以是类。
@propertyWrapper
struct SmallNumber {
private var maximum: Int
private var number: Int
var wrappedValue: Int {
get { return number }
set { number = min(newValue, maximum) }
}
init() {
maximum = 12
number = 0
}
init(wrappedValue: Int) {
maximum = 12
number = min(wrappedValue, maximum)
}
init(wrappedValue: Int, maximum: Int) {
self.maximum = maximum
number = min(wrappedValue, maximum)
}
}
struct NarrowRectangle {
@SmallNumber(wrappedValue: 2, maximum: 5) var height: Int
@SmallNumber(wrappedValue: 3, maximum: 4) var width: Int
}
这样height最大值就是5,width最大值就是4。
- 结构体/类的下标,枚举也可以。定义下标使用 subscript 关键字。
一维数组
subscript(index: Int) -> Int {
get {
// 返回一个适当的 Int 类型的值
}
set(newValue) {
// 执行适当的赋值操作
}
}
二维数组:
subscript(row: Int, column: Int) -> Int {
get {
// 返回一个适当的 Int 类型的值
}
set(newValue) {
// 执行适当的赋值操作
}
}
- 继承。 用:继承, 用self替代this, 调用超类方法用super。重写在func前加override。防止重写用final。
- 构造函数。全是用init()来替代类名构造, 要么已经初始化好了,直接class()。可选属性在init里可以不初始化。
常量的初始化,可延迟到构造函数里。