1.数组元素类型转换map
//swift为函数的参数自动提供简写形式,$0代表第一个参数,$1代表第二个参数
let array = ["1", "2", "3"]
let str1 = array.map({ "\($0)"}) //数组每个元素转成String类型
//字符串数组转NSInteger类型数组
let array1 = array.map { (obj) -> NSInteger in
return NSInteger(obj) ?? 0
}
//NSInteger类型数组转字符串数组
let array2 = array1.map { (obj) -> String in
return String(obj)
}
print("array1: \(array1)")
print("array2: \(array2)")
//str1 ["1", "2", "3"]
//array1: [1, 2, 3]
//array2: ["1", "2", "3"]
举例 ,年月日字符串分割成数组,这时数组是Substring类型数组,需要定义Substring数组,否则无法转换
var timeArray = [Substring]()
timeArray = (model.functionTitle?.split(separator: "-"))!
guard timeArray.count > 0 else {
return
}
//let dataArray = timeArray.map { (obj) -> NSInteger in
// return NSInteger(obj) ?? 0
//}
//可以省略写法
let dataArray = timeArray.map {return NSInteger($0) ?? 0}
flatMap, 功能跟map类似; 区别是flatMap会过滤nil元素, 并解包Optional。
flatMap还可以将多维数组转换为一维数组,对于N维数组, map函数仍然返回N维数组。
let array = [[1, 2, 3],[1, 2, 3],[1, 2, 3]]
let arrret = array.flatMap{$0}
let arrret1 = array.map{$0}
print(arrret)
print(arrret1)
//[1, 2, 3, 1, 2, 3, 1, 2, 3]
//[[1, 2, 3], [1, 2, 3], [1, 2, 3]]
filter函数, 顾名思义就是过滤出符合条件的元素。
let array = [1, 2, 3]
let resultArray = array.filter { return $0 > 1 }
print(resultArray)
//[2, 3]
2.匿名函数
函数可以使用func关键字创建,也可以使用{ }(花括号)来创建,这种方法可以称为匿名函数
//第一种写法
func doublerTest(i: Int) -> Int {
return i * 2
}
[1,2,3,4].map(doublerTest)
//第二种写法 (匿名函数)
let doublerTest1 = {(i: Int) -> Int in
return i * 2
}
[1,2,3,4].map(doublerTest1)
上述这两种出了传参的处理上略有不同,其实是完全等价的。
3.闭包表达式
1.正常函数
//正常函数
func fn(v1:Int,v2:Int) -> Int {
v1+v2
}
//闭包
//闭包写法
{
(参数) -> 返回值类型 in
函数体代码
}
//闭包调用写法
var fn1 = {
(v1:Int,v2:Int) -> Int in
return v1 + v2
}
//闭包调用简写1
var fn2 = {
(v1:Int,v2:Int) in
v1 + v2
}
print(fn(v1: 10, v2: 12))
print(fn1(10,20))
print(fn2(10,20))
2.函数嵌套
//正常函数
func sum(v1:Int,v2:Int,fn:(Int,Int) -> Int ) {
print(fn(v1, v2))
}
//正常函数
func fn(v1:Int,v2:Int) -> Int {
v1+v2
}
//闭包调用简写1
sum(v1: 10, v2: 20,fn: {
(v1:Int,v2:Int) -> Int in
return v1+v2
})
//闭包调用简写2
sum(v1: 10, v2: 20,fn: {
(v1:Int,v2:Int) in
return v1+v2
})
//闭包调用简写3
sum(v1: 10, v2: 20,fn: {
(v1,v2) in
return v1+v2
})
//闭包调用简写4
sum(v1: 10, v2: 20,fn: {
v1,v2 in
return v1+v2
})
//闭包调用简写5
sum(v1: 10, v2: 20,fn: {
v1,v2 in
v1+v2
})
//闭包调用简写6
sum(v1: 10, v2: 20,fn: {
$0 + $1
})
//尾随闭包写法
//闭包调用简写7
sum(v1: 10, v2: 20) { v1, v2 in
v1 + v2
}
//闭包调用简写8
sum(v1: 10, v2: 20) { $0 + $1
}
最完美写法尾随闭包
//尾随闭包调用简写8
sum(v1: 10, v2: 20) { $0 + $1
}
3.尾随闭包
1.如果很长的闭包表达式作为函数的最后一个实参(必须最后一个实参),使用尾随闭包可以增强函数的可读性,尾随闭包是一个被书写在函数调用括号外面(后面)的闭包表达式,如上闭包调用简写8
2.如果闭包表达式作为函数的唯一实参,并且使用了尾随闭包的语法,那就不需要在函数后面写圆括号
//正常函数
func sum(fn:(Int,Int) -> Int ) {
print(fn(1, 2))
}
func fn(v1:Int,v2:Int) -> Int {
v1+v2
}
//调用简写1
sum { v1, v2 in
v1+v2
}
//调用简写2
sum {$0+$1}
4.闭包(闭包和闭包表达式是两种概念)
一个函数和它所捕获的变量\常量环境组合起来,称为闭包
一般指定义在函数内部的函数
一般它捕获的是外层函数的局部变量\函数
//定义Fn类型是参数int返回int的方法
typealias Fn = (Int) -> Int
func getFn() -> Fn{
//局部变量,
var num = 0
func plus(i: Int) -> Int {
num += i
return num
}
return plus
}//返回的plus和num形成了闭包
//上面方法等同下面方法
func getFn1() -> Fn{
//局部变量
var num = 0
return {
num += $0
return num
}
}//返回的plus和num形成了闭包
let fn = getFn()//这就是闭包,可以放放局部变量、常量
print(fn(1))
print(fn(2))
print(fn(3))
print(fn(4))
//返回1 3 6 10
let fn1 = getFn()//这就是闭包,可以放放局部变量、常量
print(fn1(1))
print(fn1(3))
//返回1 4
如果不初始化方法局部变量放在堆空间,所以不会销毁,如果初始化会销毁对空间
闭包可以想象成一个类的实例对象,内存在堆空间
当需要一个方法返回一个方法对象给别人时,就需要用到闭包
5.Error处理
1.返回类型后面加? 可选类型
func divide(num1:Int,num2:Int) -> Int? {
if num2 == 0 {
return nil
}
return num1/num2
}
print(divide(num1: 1, num2: -1))
2.do try-catch
//1.创建自定义的异常枚举,并遵守 Error 协议:
enum someError: Error{
case illegalArg(String)
case ourtOfBounds(Int,Int)
}
//2.主要涉及关键字 throws、throw 的用法,代码形式如下:
func divide(num1:Int,num2:Int) throws-> Int {
if num2 == 0 {
throw someError.illegalArg("0不能作为除数")
}
return num1/num2
}
3.在 do 中 try 可以抛出错误的方法、并调用继续执行的方法;在 catch 中处理响应的错误,并且 catch 的写法多种多样(可以在多个 catch 中分别 捕获不同错误,也可以在 catch 中 通过 switch case 分别进行捕获),所有捕获的情况一定要写全。
func test() {
do {
print(try divide(num1: 1, num2: 0))
} catch let someError.illegalArg(msg) {
print("参数异常",msg)
} catch let someError.ourtOfBounds(size ,index){
print("内存溢出","size\(size)","index\(index)")
} catch {
print("其他错误")
}
}
3.特殊关键字 try!、try?
try!、try?调用可能抛出Error的函数,这样就不用去处理Error(try?、try!修饰的方法里还是需要做判断处理抛出异常)
若确定可能抛出异常的某方法本次不抛出异常,则可前置 try! 来调用,可一旦这段代码抛出了一个异常,则会引起运行时错误。
try? 代表方法可能抛出错,也可能没错,如果发生错误,那么返回nil,如果没有发生错误,系统会把数据包装成一个可选类型的值返回。
enum someError: Error{
case illegalArg(String)
case ourtOfBounds(Int,Int)
}
//2.主要涉及关键字 throws、throw 的用法,代码形式如下:
func divide(num1:Int,num2:Int) throws-> Int {
if num2 == 0 {
throw someError.illegalArg("0不能作为除数")
}
return num1/num2
}
func test() {
var result1 = try? divide(num1: 10, num2: 10)
var result2 = try? divide(num1: 10, num2: 0)
var result3 = try! divide(num1: 10, num2: 10)
}
下面两个定义是等价的
var a = try? divide(num1: 10, num2: 0)
var b: Int?
do {
try b = divide(num1: 10, num2: 0)
} catch {
b = nil
}
4. rethrows表名:函数本身不回抛出错误,但调用闭包参数抛出错误,那么它会将参数向上抛
5.defer语句:用来定义以任何方式(抛出错误、return等)离开代码块之前必须执行的代码,defer语句讲延迟至当前作用域结束之前执行
enum someError: Error{
case illegalArg(String)
case ourtOfBounds(Int,Int)
}
func divide(num1:Int,num2:Int) throws-> Int {
if num2 == 0 {
throw someError.illegalArg("0不能作为除数")
}
print(num1/num2)
return num1/num2
}
func result() {
defer {
print("必须执行")
}
try? divide(num1: 10, num2: 0)
}
6.泛型
泛型是可以将类型参数化,提高代码复用率,减少代码量。可以用在类、结构体、函数、枚举
//元素交换方法
func swapValues<T>(_ a: inout T,_ b:inout T ) {
(a,b) = (b,a)
}
var a = 10
var b = 20
swapValues(&a, &b)
var c = 10.05
var d = 20.05
swapValues(&c, &d)
7.关联类型
关联类型用在协议中,协议可以又多个关联类型
protocol Stackable {
associatedtype Element //关联类型
associatedtype Element1 //关联类型
associatedtype Element2 //关联类型
mutating func push(_ element: Element)
mutating func pop() -> Element
func top() -> Element
func size() -> Int
}
class strungStack: Stackable {
typealias Element1 = Int
typealias Element2 = Double
typealias Element = String///给关联类型定义真实类型
func push(_ element: Element) {
}
func pop() -> Element {
return "111"
}
func top() -> Element {
return "111"
}
func size() -> Int {
return 111
}
}
网友评论