Swift基础学习<一>

1,018 阅读10分钟

文章来源: swiftgg苹果官方文档

swift特性:

  • 支持泛型
  • 支持元组
  • 函数嵌套
  • 结构体、枚举可以定义函数、属性
  • set get willset didset 写在一个地方
  • 属性没有成员变量
  • 变量var 常量let
  • 类型安全的语言,必须初始化
  • 有可选类型 Int 和 Int?是两种类型,可选绑定 可选链 guard关键字
  • 符号函数 + +=(str1+str2)
  • 数组、字典 key/value类型相同,Any AnyObject除外
  • 有区间类型 ...
  • 系统自带高阶函数
  • Int Double等类型 必须转换
  • extension强大
  • 可对协议扩展

一:声明常量、变量

1、Swift中声明变量使用var关键字,使用let声明常量
2、一旦常量定义了,就不可改变 3、这里变量名后边的 : String : Float 可以省略,编译器会通过赋值得知这个变量属于什么类型
4、常量和变量名可以包含任何字符,包括 Unicode 字符
5、变量和常量名不能以数字开头

var name: String = "xxx"
let height: Float = 1.80

二:基本数据类型

Int、Float、Double
1、Swift中增加了Int8 Int16 Int32 Int64等类型,一般使用Int就够了

  • 在32位平台上,Int 和 Int32 长度相同。
  • 在64位平台上,Int 和 Int64 长度相同。
    2、类型转换
var xx = Double(3)
var xxx = Int(3.14)

3、Bool值,Swift中Bool是 true 和 false两个值,Swift中条件语句中是用Bool值来判断的,不像OC中的 不为0、nil就是真

let i = 1
if i {
    // 这个例子不会通过编译,会报错
}

let i = 1
if i == 1 {
    // 这个例子会编译成功
}

三:元组

1、元组最大的用处是当需要返回多个值的函数,试想下OC中,想返回多个值,得包装在NSArray或NSDictionary或NSString中,有了元组,直接可返回多个值

let http404Error = (404, "Not Found")
//http404Error 的类型是 (Int, String),值是 (404, "Not Found")

可以赋值:
let (statusCode, statusMessage) = http404Error
print("The status code is \(statusCode)") 
// 输出“The status code is 404”
print("The status message is \(statusMessage)")
// 输出“The status message is Not Found”

还可以通过下标来访问:
print("The status code is \(http404Error.0)")
// 输出“The status code is 404”
print("The status message is \(http404Error.1)")
// 输出“The status message is Not Found”

四:可选类型

1、可选类型是来处理值可能缺失的情况,或者为nil,或者有值,为可选类型,使用可选绑定或者拆包来获取值

字符串转换为Int
let possibleNumber = "123"
let convertedNumber = Int(possibleNumber)
// convertedNumber 被推测为类型 "Int?", 或者类型 "optional Int"

通过可选绑定或者强拆包来获取值
if let xx = convertedNumber {
	print(xx) //打印123
}

假如你知道这个convertedNumber变量一定有值,直接使用!拆包
print(convertedNumber!)

如果声明一个可选类型且没有赋值,编译器默认会赋值nil
var surveyAnswer: String?
// surveyAnswer 被自动设置为 nil

五:可选绑定

标准可选绑定示例:意思是someOptional有值,然后赋值给临时常量constantName
if let constantName = someOptional {
    statements
}

可以包含多个可选绑定或bool条件在一个if语句中:

下面两个示例是一个意思
if let firstNumber = Int("4"), let secondNumber = Int("42"), firstNumber < secondNumber && secondNumber < 100 {
    print("\(firstNumber) < \(secondNumber) < 100")
}
// 输出“4 < 42 < 100”

if let firstNumber = Int("4") {
    if let secondNumber = Int("42") {
        if firstNumber < secondNumber && secondNumber < 100 {
            print("\(firstNumber) < \(secondNumber) < 100")
        }
    }
}
// 输出“4 < 42 < 100”

guard语句,guard语句当不满足条件时直接走大括号内逻辑,提前退出代码块,满足条件,走guard语句后边代码,guard后边必须跟着一个else从句

guard let name = nameStr, name.count > 0 else {
    return
}

代码逻辑
...
...
...

六:运算符

  • 算术运算符 + - * \
  • % 求余
  • = 赋值运算符
  • 三目运算符 ?:
  • 组合运算符 += -= *= =
  • 比较运算符 == != > >= < <=
  • 空合运算符 ?? 可选值为空时,选择默认值
  • 区间运算符 (闭区间)... (半开区间)..<
  • 逻辑运算符 逻辑或|| 逻辑与&& 逻辑非!
let names = ["Anna", "Alex", "Brian", "Jack"]
let count = names.count
for i in 0..<count {
    print("第 \(i + 1) 个人叫 \(names[i])")
}
// 第 1 个人叫 Anna
// 第 2 个人叫 Alex
// 第 3 个人叫 Brian
// 第 4 个人叫 Jack

单侧区间:
for name in names[2...] {
    print(name)
}
// Brian
// Jack

for name in names[...2] {
    print(name)
}
// Anna
// Alex
// Brian

半开区间
for name in names[..<2] {
    print(name)
}
// Anna
// Alex

七:字符串String和字符Character

1、字符串是值类型,不同于OC的NSString对象类型
2、字面量创建字符串

let str = "some string"

3、多行串使用 """ """包裹

let name = """ 
li 
xxx
xxx
print(name)
打印:
li
xxx
xxx
"""

4、转义字符 \0(空字符)、\(反斜线)、\t(水平制表符)、\n(换行符)、\r(回车符)、"(双引号)、'(单引号)。 5、 += 符合运算符,是运算符函数,String重载了该运算符

var name = "li"
name += " n"
let str = name + "ing"
print(str)
打印:li ning

6、遍历字符串每一个字符

for c in "Dog!🐶" {
    print(c)
}
打印:
// D
// o
// g
// !
// 🐶

7、使用字符数组组成字符串

let characters: [Character] = ["c","a","t"]
let cat = String(characters)
print(cat)

8、+ 连接符

let string1 = "hello"
let string2 = " there"
var welcome = string1 + string2
// welcome 现在等于 "hello there"

9、常用属性、方法:

  • count
  • func append(_ other: String) 末尾添加串
  • func append(_ c: Character) 末尾添加字符
  • func remove(at i: String.Index) -> Character
  • func insert(_ newElement: Character, at i: String.Index)
  • func hasPrefix(_ prefix: String) -> Bool
  • func hasSuffix(_ suffix: String) -> Bool
  • 等等

10、子字符串: 官方文档的一段话,比较长

就像 String,每一个 Substring 都会在内存里保存字符集。而 String 和 Substring 的区别在于性能优化上,Substring 可以重用原 String 的内存空间,或者另一个 Substring 的内存空间(String 也有同样的优化,但如果两个 String 共享内存的话,它们就会相等)。这一优化意味着你在修改 String 和 Substring 之前都不需要消耗性能去复制内存。就像前面说的那样,Substring 不适合长期存储 —— 因为它重用了原 String 的内存空间,原 String 的内存空间必须保留直到它的 Substring 不再被使用为止。

子字符串也是一种类型,可以和字符串共用内存空间来提高性能。 一张图来表示内存关系: 来源于官网

八:集合类型

1、Swift集合类型有Array、Dictionary、Set
2、Array是有序集合,Set是无序无重复集合,Dictionary是无序键值对
3、Swift集合是值类型,不同于OC的对象类型NSArray、NSDictionary、NSSet
4、Swift的Array被桥接到了OC的NSArray,详情请看bridge
5、创建数组

var someInts = [Int]()
someInts.append(3)

带默认值
var threeDoubles = Array(repeating: 0.0, count: 3)

使用+运算符
var anotherThreeDoubles = Array(repeating: 2.5, count: 3)
var sixDoubles = threeDoubles + anotherThreeDoubles

可以把:[String]去掉,编译器会通过上下文知道数组类型
var shoppingList: [String] = ["Eggs", "Milk"]
var shoppingList = ["Eggs", "Milk"]

数组遍历:

for item in arr {
	print(item)
}

for index in 0..<arr.count {
	print(i)
}

for (index,item) in arr.enumerated() {
	print("\(index) -- \(item)")
}

Set:

1、Set是无序无重复的集合,其他和Array相似
2、数学 常用方法

  • 使用 intersection(_:) 方法根据两个集合的交集创建一个新的集合。
  • 使用 symmetricDifference(_:) 方法根据两个集合不相交的值创建一个新的集合。
  • 使用 union(_:) 方法根据两个集合的所有值创建一个新的集合。
  • 使用 subtracting(_:) 方法根据不在另一个集合中的值创建一个新的集合。

官网示例:

let oddDigits: Set = [1, 3, 5, 7, 9]
let evenDigits: Set = [0, 2, 4, 6, 8]
let singleDigitPrimeNumbers: Set = [2, 3, 5, 7]

oddDigits.union(evenDigits).sorted()
// [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
oddDigits.intersection(evenDigits).sorted()
// []
oddDigits.subtracting(singleDigitPrimeNumbers).sorted()
// [1, 9]
oddDigits.symmetricDifference(singleDigitPrimeNumbers).sorted()
// [1, 2, 9]

字典

1、一个字典的key必须遵循Hashable协议
2、字典的key和value需是相同类型,[Int:String] key是Int类型,value是String类型
3、其他使用详情请移步官方文档

九:控制流

1、for-in
2、while
3、repeat-while 和OC的 do-while循环类似,一定走一次代码块 4、if-else
5、switch-case Swift的switch语句要遍历完所有的case情形,要不然给一个default,没有列出的case情形会走default 6、case语句不存在隐式贯穿,也就是说不需要显式的写break,执行完case中的语句会直接退出 7、case语句支持区间匹配

官网示例:
let approximateCount = 62
let countedThings = "moons orbiting Saturn"
let naturalCount: String
switch approximateCount {
case 0:
    naturalCount = "no"
case 1..<5:
    naturalCount = "a few"
case 5..<12:
    naturalCount = "several"
case 12..<100:
    naturalCount = "dozens of"
case 100..<1000:
    naturalCount = "hundreds of"
default:
    naturalCount = "many"
}
print("There are \(naturalCount) \(countedThings).")
// 输出“There are dozens of moons orbiting Saturn.”

8、case语句可以使用元组,且可以使用值绑定

官网示例:
let somePoint = (1, 1)
switch somePoint {
case (0, 0):
    print("\(somePoint) is at the origin")
case (_, 0):
    print("\(somePoint) is on the x-axis")
case (0, _):
    print("\(somePoint) is on the y-axis")
case (-2...2, -2...2):
    print("\(somePoint) is inside the box")
default:
    print("\(somePoint) is outside of the box")
}
// 输出“(1, 1) is inside the box”

值绑定:
let anotherPoint = (2, 0)
switch anotherPoint {
case (let x, 0):
    print("on the x-axis with an x value of \(x)")
case (0, let y):
    print("on the y-axis with a y value of \(y)")
case let (x, y):
    print("somewhere else at (\(x), \(y))")
}
// 输出“on the x-axis with an x value of 2”

9、case语句可以使用 where添加额外判断条件

官网示例:
let yetAnotherPoint = (1, -1)
switch yetAnotherPoint {
case let (x, y) where x == y:
    print("(\(x), \(y)) is on the line x == y")
case let (x, y) where x == -y:
    print("(\(x), \(y)) is on the line x == -y")
case let (x, y):
    print("(\(x), \(y)) is just some arbitrary point")
}
// 输出“(1, -1) is on the line x == -y”

10、复合型case,多个可能放在一个case语句中,使用,隔开
11、使用fallthrough关键字,使走完的case语句自动走到下一个case中

官方示例:
let integerToDescribe = 5
var description = "The number \(integerToDescribe) is"
switch integerToDescribe {
case 2, 3, 5, 7, 11, 13, 17, 19:
    description += " a prime number, and also"
    fallthrough
default:
    description += " an integer."
}
print(description)
// 输出“The number 5 is a prime number, and also an integer.”

十:函数

  • 没有返回值的函数默认返回一个Void特殊值 ,该值是一个空元组,()
  • 函数代码块中单一表达式时,可以省略return,隐式返回
//有参有返
func xxx(age: Int) -> Int {
    return age+1
}
//还可以把age省略,调用的地方看不到age _
func xxx(_ age: Int) -> Int {
    return age+1
}
//隐式返回
func xxx(age: Int) -> Int {
    age+1
}

//返回元组
func xxx(n: String,a: Int) -> (name: String,age: Int) {
    return (n,a)
}

//无参无返
func xxx() -> Void {

}
//还可以把 -> Void 省略
func xxx() {

}

//带标签函数,函数内部age是参数
func xxx(label age: Int) {

}
//带有默认值参数的函数,调用方可忽略age参数
func xxx(name: String ,age: Int = 9) {

}
xxx(name: "")

//可变参数
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 个数的平均数。

//函数类型作为函数参数,闭包
func xxx(closure: (Int) -> Int,num: Int) -> Int {
    return closure(num*2)
}

//嵌套函数 函数中声明函数

十一:闭包

1、闭包是引用类型,跟OC的block一样也是对象类型
2、闭包表达式

{ (paras) -> returntype in
	代码块
}

3、下边以系统方法sorted举例:

//定义一个数组
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]

//sorted接受一个 (String,String) -> Bool 参数
let a = names.sorted(by: (String, String) -> Bool)

//定义一个参数为(String,String) -> Bool函数
func back(_ s1: String, _ s2: String) -> Bool {
    return s1 > s2
}

//把back函数传递给sorted函数
let a = names.sorted(by: back(s1:s2:))


//1、闭包表达式代码:
let a = names.sorted { (s1: String, s2: String) -> Bool in
    return s1 > s2
}

//2、闭包可以根据上下文推断类型,可以去掉对应类型
let a = names.sorted { (s1, s2) in
    return s1 > s2
}

//3、参数的括号也可以忽略
let a = names.sorted { s1, s2 in
    return s1 > s2
}

//4、如果是单表达式,可以隐式返回,忽略return
let a = names.sorted { s1, s2 in
    s1 > s2
}

//5、参数名可以简写,$0,$1,以此类推
let a = names.sorted { $0 > $1 }

//运算符方法 String类型定义了 >运算符函数,类型也是(String,String) -> Bool,只写一个 > ,swift会自动去找系统 >符号方法
let a = names.sorted(by: >)

4、尾随闭包 尾随闭包是闭包作为函数的最后一个参数,可以写在函数圆括号外边的闭包表达式。

//文档示例:
func someFunctionThatTakesAClosure(closure: () -> Void) {
    // 函数体部分
}

// 以下是不使用尾随闭包进行函数调用
someFunctionThatTakesAClosure(closure: {
    // 闭包主体部分
})

// 以下是使用尾随闭包进行函数调用
someFunctionThatTakesAClosure() {
    // 闭包主体部分
}

举例:
//定义一个函数,函数最后一个参数是闭包函数
func xxx(num: Int,closure: (Int) -> Int) -> Int {
    return closure(num)
}

//正常写法
let b = xxx(num: 2, closure: {(n: Int) -> Int in
    return n*n
})

//尾随闭包写法
let a = xxx(num: 2) { (n) -> Int in
    return n*n
}

//还可以简写成这样
let b = xxx(num: 7) { $0*$0 }

5、值捕获 闭包可以在其定义的地方捕获上下文的变量或者常量,当定义的变量或者常量的原作用域不存在时,在闭包内依然可以使用这些变量常量,也就是说,那些变量常量类似于copy到闭包了一份。OC的block有同样的机制,block捕获的变量不受外界影响,block内部维护变量的生命周期,不过block要加上__block修饰符。显然Swift处理了更多的东西,使用户不必有太多关心。

//模拟网络请求,当网络请求数据回来,suc,failed执行,且这两个闭包是逃逸闭包,逃逸闭包是函数返回后才执行,称该闭包在函数中逃逸。
func callback(suc: @escaping (_ code: Int,_ data: Any)->Void,failed: @escaping (_ code: Int,_ error: String)->Void) {
    if true {
        suc(200,"suc")
    } else {
        failed(404,"error")
    }
}

//调用方 闭包内部使用self,闭包捕获了self,也就是self强引用闭包,闭包内部强引用self,为了避免循环引用,使用weak修饰,
callback { [weak self] (code1, data1) in
    //内部使用self weak修饰,闭包捕获到self
} failed: { (code2, data2) in

}

6、自动闭包

十二:枚举

1、Swift的枚举要比OC的强大的多,可以定义构造函数、添加方法、添加属性、可以给枚举扩展、枚举可以遵循协议
2、枚举可以标明类型

//带有原始值的String类型的枚举
enum CampassPoint : String {
    case north
    case south
    case east
    case west
}

//定义一个枚举变量
var d = CampassPoint.west

//可以打印初始值,初始值就是每个枚举对应的字符串
print(d.rawValue)

//case语句匹配枚举
func xxx(direct: CampassPoint) {
    switch direct {
    case .east:
        print("east")
    case .west:
        print("west")
    default:
        print("other")
    }
}

3、枚举遵循协议,直接在枚举名后边 ,协议名 即可

enum CampassPoint : String,CaseIterable {
    case north
    case south 
    case east
    case west
}

4、枚举成员的遍历 遍历上边定义的枚举CampassPoint

//allCases 是CaseIterable协议里的只读变量
for item in CampassPoint.allCases {
    print(item)
}

5、关联值

//官方示例:
//可以这么理解,定义了一个枚举Barcode,它定义了一个(int,int,int,int)类型关联值的upc,另一个定义了带有(String)类型关联值的qrCode
enum Barcode {
    case upc(Int, Int, Int, Int)
    case qrCode(String)
}

//定义productBarcode变量
var productBarcode = Barcode.upc(8, 85909, 51226, 3)

//同一个商品被分配了不同的条形码
productBarcode = .qrCode("ABCDEFGHIJKLMNOP")

//关联值可以提取出来成为switch的一部分,可以使用var或者let赋值一个变量或者常量
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).")
}
// 打印“QR code: ABCDEFGHIJKLMNOP.”

6、原始值的隐式赋值,如果原始值的类型是String时,每个枚举成员的原始值就是成员名

venus向下依次是23...
enum Planet: Int {
    case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune
}

//枚举成员String类型
enum CompassPoint: String {
    case north, south, east, west
}

7、递归枚举 在枚举成员前边加上 indirect 关键字来标识该成员可递归,目前不知道使用场景。略

十三:结构体

Swift结构体和类都可以:

  • 定义属性用于存储值
  • 定义方法用于提供功能
  • 定义下标用于使用下标来操作结构体
  • 定义构造器用于设置初始值
  • 可用扩展extension来额外增加功能
  • 都可以遵循协议来提供某些功能

结构体特有:

  • 结构体是值类型,在恰当的时候Swift会生成一个结构体备份
  • 结构体有逐一构造器

类特有:

  • 类是引用类型
  • 有继承
  • 类型转换允许在运行时进行类型判定
  • 析构器可释放为类示例分配的内存
  • 内存管理使用引用计数

苹果推荐优先使用结构体,因为结构体更轻量级,当出现以下情况是使用类:

本章完!