欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

swift基础部分小记

程序员文章站 2024-02-20 15:19:34
...

1 术语

运算符分为一元,二元和三元运算符

  • 一元运算符对单一操作对象操作,一元运算符分前置运算符和后置运算符,前置运算符需要紧跟在操作对象之前 如(!b),后置运算符需紧跟在操作对象之后如(c!)
  • 二元运算符操作两个操作对象,如(2 + 3)是中置的,因为它们出现在两个操作对象之间。
  • 三元运算符操作三个操作对象,和C语言一样,Swift只有一个三元运算符,就是三目运算符(a ? b : c)

tips
在求余运算符中,除数的符号是被忽略的,其他不影响
-9 % -2 = -9 % 2
空合运算符
a != nil ? a! : b 等价于 a ?? b
区间运算符
1...5 表示从1到5 闭区间
1..<5 表示从1到4 半开区间

  • 字符串字面量有以下特殊字符

转义字符\0(空字符 是零)、\(反斜线)、\t(水平制表符)、\n(换行符)、\r(回车符)、"(双引号)、'(单引号)。

2 字符串和字符

空的字符 下面两者是等价的
var emptyString = ""
var anotherEmptyString = String()
字符串是值类型 意味着如果你创建了一个新的字符串,那么当其进行常量,变量赋值操作,或在函数,方法中传递时,会进行拷贝

3 数组和字典

数组可以用isEmpty来判断数组是否为空 当数组的count为0时,isEmpty为true
字典可以用updateValue 来修改值,添加值,也可以用来移除一个值

  • 如果存在key updataValue ... forKey:key 修改值
  • 如果不存在key updataValue ... forKey:key 添加值
  • 如果设置key对应的value 为nil updataValue :nil forKey:key 修改值 移除值

4 检查api的可用性

if #available(iOS 10, macOS 10.12, *) {
    // 在 iOS 使用 iOS 10 的 API, 在 macOS 使用 macOS 10.12 的 API
} else {
    // 使用先前版本的 iOS 和 macOS 的 API
}
if #available(platform name version, ..., *) {
    APIs 可用,语句将执行
} else {
    APIs 不可用,语句将不执行
}

5 可变参数

可变参数可以接受零个或多个值,函数调用时,你可以用可变参数来指定函数参数可以被传入不确定数目的输入值,通过在变量函数名后面加入...方式来定义可变参数
例如
func arithmeticMean(_ numbers: Double...) -> Double {
    var total: Double = 0
    for number in numbers {
        total += number
    }
    return total / Double(numbers.count)
}
arithmeticMean(1, 2, 3, 4, 5)
// 返回 3.0, 是这 5 个数的平均数。
arithmeticMean(3, 8.25, 18.75)
// 返回 10.0, 是这 3 个数的平均数。
 注意:
    一个函数最多只能拥有一个可变参数

6 输入输出参数

函数参数默认是常量,试图在函数体中更改参数值将会导致编译错误

如果你想要在函数中修改参数值,你需要定义为输入输出参数,在参数定义前家inout关键字
在传入参数是需要再参数前面加&符,便是这个值可以被函数修改。

func swapTwoInts(_ a: inout Int, _ b: inout Int) {
    let temporaryA = a
    a = b
    b = temporaryA
}
var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt)
print("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
// 打印 "someInt is now 107, and anotherInt is now 3"
注意:
输入输出参数和返回值是不一样的。上面的 swapTwoInts 函数并没有定义任何返回值,但仍然修改了 someInt 和 anotherInt 的值。输入输出参数是函数对函数体外产生影响的另一种方式。

7 特殊字符

转义符
\0(空字符),\\(反斜线)\t(水平制表符)\n(换行符),/r(回车符),\"(双引号),
\'(单引号)。
前缀/后缀相等
通过调用字符串的hasPrefix(:)/hasSuffix(:)方法来检查字符串是否拥有特定前缀/后缀,两个方法均接受一个string类型的参数,并返回一个布尔值

8 函数

每个函数都有特定的函数类型,函数的类型由函数的参数类型和返回类型组成

  • 可选元组返回类型
func minMax(array:[Int]) -> (min:Int, max:Int)? {}

可选元组类型这里表示整个元组可选,而不是元组中的每个元素值可选 如果想要个元素值可选(min:Int?,max:Int?)

  • 默认参数
    在函数中通过给参数赋值为任意一个参数定义默认参数,当默认值被定义后,调用这个函数时你可以忽略这个参数,直接使用默认参数
fun someInt(_ someInt:Int = 1) {}

一般情况下,我们将不带默认参数值的参数放在函数参数列表前面,将默认参数放在函数参数列表后面

  • 函数类型
func mathAdd(first:Int,second:Int) -> Int {
return first + second
}

var mathfunction:(Int,Int) -> Int = mathAdd(first:second:)
mathfunction(4, 6)
  • 嵌套函数
func chooseStepFunction(backward: Bool) -> (Int) -> Int {
    func stepForward(input: Int) -> Int { return input + 1 }
    func stepBackward(input: Int) -> Int { return input - 1 }
    return backward ? stepBackward : stepForward
}

9 闭包

闭包是自包含的函数代码块,可以在代码中被传递和使用
闭包可以捕获和存储其所在上下文中任意常量和变量的引用。被称为包裹常量和变量。
在内联闭包表达式中,函数和返回值类型都写在大括号内,而不是大括号外,闭包的函数体部分有关键字in引入,该关键字表示闭包的参数和返回类型定义已经完成,闭包函数体即将开始。

闭包表达式
{(parameters)-> returntype in
sttements
}
方便下面自己举例
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]

闭包的完整写法 也是我目前在使用的,把闭包的参数和返回类型都声明出来,在in后面写逻辑

names.sorted(by: { (s1: String, s2: String) -> Bool in
    return s1 > s2
})

这个也可以
names.sorted { (a, b) -> Bool in
  return    a > b
}

names.sorted { (a, b) -> Bool in
    a > b
}
  • 根据上下文推测
    因为排序闭包函数作为sorted(by:)方法的参数传入,swift可以推断出其参数和返回值类型 那么 类型就可以不用指定 可以简写为
names.sorted(by: { s1, s2 in return s1 > s2 } )
  • 单表达式闭包隐式返回
names.sorted(by: { s1, s2 in s1 > s2 } )

在这个例子中,sorted(by:)方法参数类型明确了闭包必须返回一个bool类型,闭包函数体只包含了一个单一表达式(s1 > s2),该表达式返回 Bool 类型值,因此这里没有歧义,return 关键字可以省略。

  • 参数名称缩写
names.sorted(by: { $0 > $1 } )

如果你在闭包表达式中使用参数名称缩写,你可以在闭包中省略参数列表,并且对应参数名称缩写的类型会通过函数类型推断 in关键字也可以被省略,因为此时闭包表达式完全由闭包函数体构成
在这个例子中,$0和`$1表示闭包中第一个和第二个 String 类型的参数。

  • 运算符方法
names.sorted(by: >)

还有一种更简短的方式来编写上面例子中的闭包表达式。Swift 的 String 类型定义了关于大于号(>)的字符串实现,其作为一个函数接受两个 String 类型的参数并返回 Bool 类型的值。而这正好与 sorted(by:) 方法的参数需要的函数类型相符合。因此,你可以简单地传递一个大于号,Swift 可以自动推断出你想使用大于号的字符串函数实现

  • 尾随闭包

如果你需要将一个很长的闭包表达式作为最后一个参数传递给函数,可以使用尾随闭包来增强函数的可读性。尾随闭包是一个书写在函数括号之后的闭包表达式,函数支持将其作为最后一个参数调用。在使用尾随闭包时,你不用写出它的参数标签

reversedNames = names.sorted() { $0 > $1 }
可以简写为
reversedNames = names.sorted { $0 > $1 }
  • 值捕获
    swift 可以在其被定义的上下文中捕获常量或变量,即使这些常量和变量的原作用域已经不存在,闭包仍然可以在闭包函数体内引用和修改这些值
func makeIncrementer(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0
    func incrementer() -> Int {
        runningTotal += amount
        return runningTotal
    }
    return incrementer
}

这个方法是返回类型为()-> Int这意味着返回的是一个函数
incrementer这个函数从上细纹中捕获了这两个值runningTotalamount的引用,捕获引用保证了这两个变量在调用玩makeIncrementer后不会消失并且保证了再写一次执行incrementer函数时,runningTotal依旧保存。

  • 注意 :为了优化,如果一个值不会被闭包改变,或者在闭包创建后不会改变,swift可能会改为捕获并保存一份对值的拷贝,swift也会负责对捕获变量的所有内存管理工作,包括释放不再需要的变量。

示例

let incrementByTen = makeIncrementer(forIncrement: 10)
incrementByTen()
// 返回的值为10
incrementByTen()
// 返回的值为20
incrementByTen()
// 返回的值为30
  • 逃逸闭包
    当一个闭包作为参数传到一个函数中,但是这个闭包在函数返回之后才被执行,我们称为闭包从函数中逃逸。
    一种使用闭包逃逸的方法是,将这个闭包保存在一个函数外部定义的变量中,很多启动异步操作的函数接受一个闭包参数作为completion handler 这类函数会在异步操作开始之后立即方法,但是闭包知道异步操作结束之后才会被调用,在这种情况下,闭包需要“逃逸”出函数,因为闭包需要在函数返回之后被调用。
保存在外部变量中
var completionHandlers: [() -> Void] = []
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
    completionHandlers.append(completionHandler)
}

延迟调用
    func someFunctionWithEscapingClosure(completionHandler:   @escaping () -> Void)  {
        DispatchQueue.global().asyncAfter(deadline: DispatchTime.now() + 1) { 
            completionHandler()
        }
        
    }

tips:将一个闭包标记为@escaping以为着 你必须在闭包中显式的引用self

  • 自动闭包
    自动闭包是一种自动创建的闭包,用于包装传递给函数作为参数的表达式。这种闭包不接受任何参数,当它被调用的时候,会返回被包装在其中的表达式。这种便利语法让你能够省略闭包的花括号,用一个普通的表达式来代替显式的闭包。
    自动闭包让你能够延迟求值,因为直到你调用这个闭包,代码才会被执行。
var customersInLine = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
print(customersInLine.count)
// 打印出 "5"

let customerProvider = { customersInLine.remove(at: 0) }
print(customersInLine.count)
// 打印出 "5"

print("Now serving \(customerProvider())!")
// Prints "Now serving Chris!"
print(customersInLine.count)
// 打印出 "4"

尽管在闭包的代码中,customersInLine 的第一个元素被移除了,不过在闭包被调用之前,这个元素是不会被移除的。如果这个闭包永远不被调用,那么在闭包里面的表达式将永远不会执行,那意味着列表中的元素永远不会被移除。请注意,customerProvider 的类型不是 String,而是 () -> String,一个没有参数且返回值为 String 的函数。

将闭包作为参数传递给函数时,你能获得同样的延时求值行为。

// customersInLine is ["Alex", "Ewa", "Barry", "Daniella"]
func serve(customer customerProvider: () -> String) {
    print("Now serving \(customerProvider())!")
}
serve(customer: { customersInLine.remove(at: 0) } )
// 打印出 "Now serving Alex!"

这个serve(customer:)函数接受一个返回顾客名字的显式的闭包
下面这个版本的 serve(customer:) 完成了相同的操作,不过它并没有接受一个显式的闭包,而是通过将参数标记为 @autoclosure 来接收一个自动闭包。现在你可以将该函数当作接受 String 类型参数(而非闭包)的函数来调用。customerProvider 参数将自动转化为一个闭包,因为该参数被标记了 @autoclosure 特性。

// customersInLine is ["Ewa", "Barry", "Daniella"]
func serve(customer customerProvider: @autoclosure () -> String) {
    print("Now serving \(customerProvider())!")
}
serve(customer: customersInLine.remove(at: 0))
// 打印 "Now serving Ewa!"

如果你想要一个自动闭包可以逃逸,则同时使用@autolosure和@escaping属性。

// customersInLine i= ["Barry", "Daniella"]
var customerProviders: [() -> String] = []
func collectCustomerProviders(_ customerProvider: @autoclosure @escaping () -> String) {
    customerProviders.append(customerProvider)
}
collectCustomerProviders(customersInLine.remove(at: 0))
collectCustomerProviders(customersInLine.remove(at: 0))

print("Collected \(customerProviders.count) closures.")
// 打印 "Collected 2 closures."
for customerProvider in customerProviders {
    print("Now serving \(customerProvider())!")
}
// 打印 "Now serving Barry!"
// 打印 "Now serving Daniella!"

知识比较薄弱整理为了自己以后查看