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一样。
var total = 0
for i in 0..<4 {// 0到3
total += i
}
for i in 0..<4 {// 0到4
total += i
}
if let firstNumber = Int("4"), let secondNumber = Int("42"), firstNumber < secondNumber && secondNumber < 100 {
}
15.数组修改,追加append, 删除remove, 追加另外一个数组+=, 插入insert, 判空isEmpty。按照方法来说,应该是链表实现的。
16.集合set,方法和java差不多。
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)
}
两种定义方式:
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是值类型,所以赋值的时候是值拷贝,生成了另外一个struct实例。和类差异并不大。
和类相同的地方:
类还有如下的附加功能:
类的恒等运算符
使用这两个运算符检测两个常量或者变量是否引用了同一个实例:
if tenEighty === alsoTenEighty {
print("tenEighty and alsoTenEighty refer to the same VideoMode instance.")
}
变量用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 观察器。而在父类初始化方法调用之前,给子类的属性赋值时不会调用子类属性的观察器。
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(index: Int) -> Int {
get {
// 返回一个适当的 Int 类型的值
}
set(newValue) {
// 执行适当的赋值操作
}
}
二维数组:
subscript(row: Int, column: Int) -> Int {
get {
// 返回一个适当的 Int 类型的值
}
set(newValue) {
// 执行适当的赋值操作
}
}
常量的初始化,可延迟到构造函数里。