// 教程地址:https://www.bilibili.com/video/BV1mT4y1C7JZ?p=16&vd_source=84310ee3c28453390868c23631486732
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
do {
// 数据类型转换
// let i: Int = 10
// let j = 0.1
// let c = Int(j) + i
// print("c:\(c)")
//
// // 元组
// let error = (tit: 400, ddd: "not found")
// let d = error.0
// print("d:\(d)")
//
// let (code, des) = error
// print(code, des)
//
// let _ = error.tit
}
do {
// if语句
// var i = 10
// if i > 0 {
// print("i 大于 0")
// }
}
// 循环 还可以使用where条件
do {
// var i = 10
// repeat {
// print(10)
// } while i < 10
//
// for i in 0...3 {
// print(i)
// }
//
// for i in 0..<3 where i > 1 {
// print(i)
// }
//
// let array = [1, 2, 3 ,4]
// for item in array[0..<2] {
// print("haha\(item)")
// }
//
// for item in array[...2] {
// print(item)
// }
}
// switch
do {
var c = "c"
switch c {
case "1":
print("haha")
case "2", "3":
print("aaaa")
default:
break
}
// 区间匹配
var index = 10
switch index {
case 0...1:
fallthrough
case 2...3:
break
default:
break
}
// 元组匹配
let tuple = (1, 1)
switch tuple {
case (_, 1):
break
case (1...2, 1):
break
case (1...2, 1..<3):
break
default:
break
}
// 值绑定
switch tuple {
case (2, let a):
print(a)
case let (x, y):
print(x, y)
case let (a, b) where a > b: // 使用where过滤条件
print(a)
}
}
}
}
/// ------------
// 函数
func 函数() {
// 有入参 有返回值
func func1(a: Int, b: Int) -> Int {
return a + b
}
// 无入参无返回值
func fun2() {
}
// 带参数标签和默认参数值
func fun3(outname inname: Int = 10) {
}
// 可变参数
func fun4(numbers: Int..., age: Int) {
for index in numbers {
print(index)
}
}
// 输入输出参数
func fun5(a: inout Int) {
a += 5
}
}
/// ------------
func 别名typealias() {
// 给元组声明一个别名
typealias Date = (year: Int, month: Int, day: Int)
func eatAt(date: Date) {
print(date.0)
print(date.year)
}
eatAt(date: (2011, 2, 1))
// 给函数声明一个别名
typealias DeleteFunc = (Int, Int) -> Int
func operate(f: DeleteFunc, a: Int, b: Int) -> Int {
return f(a, b)
}
}
/// ------------
func 枚举enum() {
// 原始值 rawValue
enum Score: Int {
case point = 2 // 设置原始值
case grade = 43 // 设置原始值
}
let s = Score.grade
// 打印原始值
print(s.rawValue)
let _ = Score(rawValue: 65)
// 隐式原始值,如果枚举的原始值类型是Int或者String, swift会默认设置原始值
enum Di: String {
case source // swift会默认设置 case source = "source"
case north
}
typealias Location = (x: Int, y: Int)
// 关联值
enum Direction {
case sourth(Location)
case east(Int)
case west(Float)
}
var dir = Direction.sourth((10, 20))
// 可以根据类型推断出枚举类型 就可以用.省略类型
dir = .east(1)
print(dir)
// 枚举结合switc
switch dir {
case .east(let value) where (10...20).contains(value):
print(1)
case .sourth(let location) where location.x == 10:
print(location.x)
default:
break
}
}
/// ------------
func 可选项optional() {
// 类型后面+?
var name: String? = "jack"
name = nil
print(name) // Optional(jack)
// 可选值强制解包
let n = name!
print(n) // jack
// 可选绑定
if let number = Int("123123") {
// number是解包后的值 123123
} else {
}
// 可选绑定的if语句中 需要使用,分割
if let a = Int("1"),
let b = Int("2"),
a > b {
print("yes")
}
// 空合并运算符 a??b , a为可选项 b为可选项或者值都可以
var score1: String? = "11"
var score2: String? = "2"
print(score1 ?? score2)
print(score1 ?? 2) // 如果返回score1 那么会强制解包,因为后面的是一个值 非可选项
if let n = score1 ?? score2 {
// 这种写法等价于 scrol1 != nil || score2 != nil
}
if let n = score1,
let c = score2 {
// 这种写法等价于 scrol1 != nil && score2 != nil
}
// guard语句,当条件为false的时候 会执行括号里面的代码
// guard 条件 else { return、break、continue退出}
guard let c = Int("adfasf") else {
print("条件没有成立")
return
}
print(c)
// 隐式解包:如果一个可选值必定有值,可以在类型后面+!
let s: Int! = Int("123")
let d: Int = s
print(d)
// 多重可选项
let t: Int? = Int("234234")
let m: Int?? = t // 包装了一个可选值的可选值
// 可选项本质是枚举
enum Optional<T> {
case same(T)
case none // nil
}
}
/// ------------
func 结构体struct() {
// 编译器会默认给结构体增加一个初始化器 Initializer, 它的宗旨是保证所有的存储属性都有初始值
struct Date {
var year: Int
var month: Int
var day: Int
}
let d1 = Date(year: 2022, month: 2, day: 2)
// 自定义初始化器
struct Datt {
var year: Int
var m: Int
// 自定义初始器,此时编译器就不会生成默认初始化器
init(yy: Int, mm: Int) {
self.m = mm
self.year = yy
}
}
// let类型的结构体 它的存储属性也是let类型不可以修改
let d = Date(year: 11, month: 1, day: 1)
// d.day = 22 会报错
}
/// ------------
func 类class() {
// 编译器不会给类生成默认初始化器
class Student {
var age: Int
var name: String
init(age: Int, name: String) {
self.age = age
self.name = name
}
}
let s = Student(age: 1, name: "jack")
}
/// ------------
///
func 闭包() {
// swift中可以使用func来定义一个函数,也可以使用闭包来定义函数
/*
闭包格式
{
(参数列表) -> 返回值类型 in
函数体代码
}
*/
// 使用func定义函数
func sum(a: Int, b: Int) -> Int {
a + b
}
// 使用闭包定义函数
var fuck = {
(a: Int, b: Int) -> Int in
a + b
}
let _ = sum(a: 1, b: 2) // 调用func函数
let _ = fuck(2, 4) // 调用闭包,闭包会省略参数标签
// 如果闭包是函数的最后一个参数 可以使用尾随闭包
func delete(a: Int, b: Int, fc: (Int ,Int) -> Int) -> Int {
fc(a, b)
}
_ = delete(a: 1, b: 2) { a, b in
a + b
}
_ = delete(a: 1, b: 3, fc: {
$0 + $1
})
}
/// ------------
func 方法() {
// 值类型如果想要在方法中修改属性 需要使用mutating关键字
struct DDD {
var x: Int = 10
mutating func changeX(a: Int) {
x = a
}
}
class DS {
// 相当于dispatch once
static let a = "adfaf"
}
// 消除函数返回值未使用的警告@discardableResult
@discardableResult func delete(a: Int, b: Int) -> Int {
a - b
}
// 下标subscript
class Person {
var age: Int = 10
// 下标方法可以是类方法 在前面增加static字段即可
subscript(index: Int) -> Int {
set {
if index == 0 {
age = newValue
}
}
get {
if index == 0 {
return age
}
return 3
}
}
}
}
/// ------------
func 继承() {
// 类可以继承,结构体不行
// 继承后可以重写父类的方法或者属性 使用override关键字
class Animal {
var name = ""
var age:Int = 10
}
class Dog: Animal {
// 重写父类属性为计算属性
override var name: String {
set {
super.name = newValue
}
get {
return ""
}
}
// 在子类中给父类存储属性添加观察器, 也可以给父类的计算属性添加属性观察器
override var age: Int {
willSet {
print(newValue)
}
didSet {
print(oldValue)
}
}
// 被final修饰的属性 方法,禁止被重写。类禁止被继承
}
}
/// ------------
func 初始化构造链() {
// 父类的属性在自己的初始化方法中给属性赋值,不会触发属性观察器
// 父类的属性 在子类的初始化方法中给属性赋值,会触发属性观察器
class Animal {
var age: Int
init(age: Int) {
self.age = age
}
}
class Dog: Animal {
var name: String
init(name: String) {
// 1. 子类先初始化自己的东西
self.name = name
// 2. 再调用父类构造方法
super.init(age: 1)
// 第二阶段后 才可以使用self关键字
// 3. 最后可以自定义一些东西
age = 10
}
}
// --------
class Person {
var age: Int
// 使用关键字required 那么子类必须继承或者重写该指定初始化器
required init(age: Int) {
self.age = age
}
}
class XiaoMing: Person {
// 子类也必须使用required关键词重写 不用加override
required init(age: Int) {
super.init(age: age)
}
}
// -----
// 可失败初始化器
class Bird {
var age: Int
init?(age: Int) {
if age < 0 {
return nil
}
self.age = age
}
}
// ------
// 反初始化器
class Fish {
// 先调用子类的deinit方法,后再调用父类的deinit方法
// 父类的反初始化方法可以继承给子类,即子类销毁的时候 会调用父类的deinit方法
deinit {
print("销毁了")
}
}
}
func 可选链() {
class Person {
var age: Int = 0
}
var p: Person? = Person()
// 结果是可选项 因为p有可能是nil,如果p是nil的情况 那么就不会继续调用.age方法
let _ = p?.age
// 如果本来就是可选项 那么可选链不会再次包装 也就是不会出现??的情况
// ----
// 利用可选链有值才会继续向后执行的特性
// 第二行加上? 会判断 如果w有值才会继续赋值20, 如果w没有值 那么就不会执行后面的赋值操作了
var w: Int? = 10
w? = 20
}
/// ------------
// 协议
protocol 协议 {
func haha() // 定义方法
var name: String { get set } // 定义属性 并声明可读可写权限, 子类可以实现一个存储属性 也可以是计算属性
var age: String { get }
subscript(index: Int) -> String { get set }
// 定义类方法 必须用static关键字 不能使用class,因为有可能是结构体遵守这个协议
static func eat()
mutating func say() // 如果要在方法中修改属性值,必须在协议中增加mutating关键字
// 协议中定义方法不能带默认参数值
// 协议中定义属性必须用var 不能用let,因为实现的时候 有可能是计算属性 值是不确定的
// 协议中声明的权限 实现的时候可以大于 不能小于,比如是get只读权限 实现的时候 可以为可读可写
// 协议中还可以定义默认初始化方法。但是实现类必须加上required关键字
init(age: Int)
}
protocol hha {
}
class PPPPP {
}
// 别名
typealias 多组合 = PPPPP & 协议 & hha
// 协议组合,要求参数是指定类型且遵守必要的协议
func eat(a: 多组合) {
}
/// ----------
/// 枚举遵循CaseIterable协议 就可以实现枚举遍历
enum Season: CaseIterable {
case summer
case winter
}
func 遍历season() {
for cacse in Season.allCases {
print(cacse)
}
}
/// ----------
/// 对象遵守CustomStringConvertible并实现description方法 就可以自定义print内容
class CustomStringC: CustomStringConvertible {
var age: Int = 0
var description: String {
return "\(age)哈哈"
}
}
/// --------------
/// swift提供了两种特殊的类型 Any和AnyObject。或者说是两种协议
/// Any可以代表任意类型 枚举、结构体、类型、函数
/// AnyObject可以代表任意类类型,不能代表结构体。 如果协议后面注明AnyObject,表示只有类才能遵守这个协议
protocol ClassProtocol: AnyObject {
}
class BBB: ClassProtocol {
}
var anyArr = Array<Any>() // 存放任意类型的数组
var anyObjArr = Array<AnyObject>() // 存放任意类的数组
var anyDic = [Any]()
var anyObjDic = [AnyObject]()
/// --------------
/// is as as? as!
/// is用来判断是否是某种类型
/// as用来做类型转换。 as?表示可选转换, as!表示强制解包, as表示百分百转换成功 比如as Any时候可以用as
///
func is_as() {
var a: Any
a = 10
if a is Int {
print("是整型")
}
class Person {
func eat() {
print("eat")
}
}
var p: Any = Person()
// as?拿到的是可选类型 因为转换有可能失败
// 第二个?代表是可选链调用eat方法,当前面成立 不为nil 才会调用eat方法
(p as? Person)?.eat()
}
/// --------------
protocol haha {
func test() -> Self
}
func self_type_AnyClass() {
// X是类
// X.self是一个元类型的指针,元类型中存放着类的相关信息,可以称为元类型 相当于oc的class
// X.self是X.type类型
class Person {
required init() {
}
}
var typet: Person.Type = Person.self
// oc中使用class来创建vc ,在swift中可以使用元类型x.type来创建
// [[class alloc] init];
let _ = Person.self.init()
func create(type: Person.Type) {
let _ = type.init()
}
// Self一般用作返回值类型 或者参数类型,限定返回值必须跟方法调用者是同一个类型
// 类似于oc的instancetype
class Person1: haha {
required init() {
}
func test() -> Self {
return type(of: self).init()
}
}
}
func 错误error() {
// swift可以自定义运行时错误
// 可以自定义类 遵守Error协议, 可以是枚举或者类或者结构体
enum MyError: Error {
case local(String)
case remote(Int)
}
// 方法需要增加throws关键字
// 方法内部抛出错误使用throw关键字
func delete(a: Int, b: Int) throws -> Int {
if a < b {
throw MyError.local("haha")
}
return a - b
}
// 调用的时候 可以使用try try? try!
// 1,调用时候一般使用do catch来捕捉错误
do {
print(1)
var _ = try delete(a: 10, b: 1) // 如果这一步异常了 就不会执行下面print2
print(2)
} catch let MyError.local(ll) {
print(ll)
} catch let MyError.remote(rrr) {
print(rrr)
} catch {
print("兜底")
}
// 语法糖
do {
try delete(a: 10, b: 1)
} catch let error as MyError {
print(1)
} catch is MyError {
print(23)
} catch {
}
// 2. 调用方法的时候 还可以不处理 使用throws继续往上抛
func callDelete() throws {
var _ = try delete(a: 10, b: 1) // 如果这一行执行报错 后面print也不会再执行了
print(3)
}
// 3.使用try? try!
var _ = try? delete(a: 10, b: 10) // 返回的是Int?类型 如果正常是可选值Optional(Int) 如果错误是nil ,跟下面的写法等价
do {
try delete(a: 10, b: 10)
} catch {
}
// 还可以使用try! 强制解包
let _ = try! delete(a: 10, b: 10) // 返回值是Int类型
}
func 懒执行defer() {
// 用来定义任何方式离开前 都必须会执行的代码,包括return 抛异常error
defer {
}
}
func 泛型() {
// 1.方法中使用泛型
// 交换参数
func swapValue<T>(a: inout T, b: inout T) {
(a, b) = (b , a)
}
var a = 10
var b = 2
swapValue(a: &a, b: &b)
// 把泛型函数赋值给变量
let fu: (inout Int, inout Int) -> () = swapValue
fu(&a, &b)
// 2.类中使用泛型
class Stack<T> {
var array = [T]()
func push(t: T) {
array.append(t)
}
}
// 创建类的时候 需要显式标明类型
var s = Stack<Int>()
// 如果是子类继承 也需要增加泛型
class SSStack<T>: Stack<T> {
}
}
/// ------
func associatedType关联类型() {
}
// 给协议中用到的类型 定义一个占位名称,可以简单理解协议中想要实现泛型 不能用上面的<T>这种方式 只能使用关联类型这种方式
// 协议中可以定义多个类型
protocol Stack {
associatedtype element
mutating func push(e: element)
}
// 遵守协议的时候, 可以通过typealias来指定类型,也可以省略typealias 让编译器自己根据我们写的方法类型判断
class BBBB: Stack {
typealias element = Int
func push(e: Int) {
print(1)
}
}
/// -------- 类型约束
/// 约束泛型t的类型或者必须遵守协议
func mutal<T: PPPPP & Stack>(a: T) -> T {
return a
}
/// 约束协议中的泛型必须遵守协议
protocol Hadaf {
associatedtype T: Stack
}
// 还可以在func中增加where语句做更细致的类型约束
func aasdfas<T, M>(a: T, b: M) where T == M {
}
/// some 限制只能返回一种类型,不透明协议
protocol Masdfasf {
associatedtype T
}
class Flya: Masdfasf {
typealias T = Int
}
class FlaB: Masdfasf {
typealias T = Double
}
func getf(a: Int) -> some Masdfasf { // 限制方法内部 只能返回一种遵守Masdfasf的类型 不能返回两种
return FlaB()
}
///-------- 溢出运算符
/// swift支持溢出运算 &+ &- &*
var max = Int8.max
var mmm = max + 1 // 会崩溃 因为溢出了
var mmmm = max &+ 1 // 不会崩溃 但是会变成最小值 因为溢出了
///-------- 运算符重载
struct HhhAAA {
// 运算符重载方法 需要增加static关键字
static func +(a: HhhAAA, b: HhhAAA) -> HhhAAA {
return a
}
static func +=(a: HhhAAA, b: HhhAAA) -> HhhAAA {
return a
}
}
/// equatable协议 就是重载==运算符
class Eafafd: Equatable {
var name: Int = 0
static func ==(lhs: Eafafd, rhs: Eafafd) -> Bool {
return lhs.name == rhs.name
}
}
/// Comparable协议 用来重载<实现比较大小
//class ASDFAFD: Comparable {
// static func < (lhs: ASDFAFD, rhs: ASDFAFD) -> Bool {
// return true
// }
//
//}
/// 自定义运算符 使用operator关键字
///
/// ------------ 拓展 entension,类似于oc的分类
/// 可以添加方法、计算属性、下标、(便捷)初始化器、嵌套类型、协议等等
//扩展不能办到的事情:
// 口不能覆盖原有的功能
// 口不能添加存储属性,不能向已有的属性添加属性观察器
// 口不能添加父类
// 口不能添加指定初始化器,不能添加反初始化器
class Paer {
}
extension Paer {
}
/// ------------ 访问控制 权限控制
/// 访问权限控制这块,Swift提供了5个不同的访问级别(以下是从高到低排列,实体指被访问级别修饰的内容)
/// 模块可以理解为一个可执行文件 target,一个动态库或者静态库是一个模块
//口open:允许在定义实体的模块、其他模块中访问,允许其他模块进行继承、重写(open只能用在类、类成员上)
//口public:允许在定义实体的模块、其他模块中访问,不允许其他模块进行继承、重写
//口internal:只允许在定义实体的模块中访问,不允许在其他模块中访问
//口fileprivate:只允许在定义实体的源文件中访问
//口private:只允许在定义实体的封闭声明中访问
//访问级别的使用准则
//一个实体不可以被更低访问级别的实体定义,比如
//变量\常量类型 >= 变量\常量
//口参数类型、返回值类型 >= 函数
//父类子类 >= 父协议子协议
//原类型 >= typealias
//原始值类型、关联值类型 >= 枚举类型
//定义类型A时用到的其他类型 >= 类型A
/// ----- 内存管理 weak unowned
/// weak定义的必须是可选类型的var 因为销毁后arc会自动把该弱引用置为nil 类似于oc的weak
/// unowned 类似于oc的assing 对象销毁后还保存着该指针 再次访问容易引发野指针崩溃
// 如果想在定义闭包属性的同时引用self,这个闭包必须是lazy的(因为在实例初始化完毕之后才能引用self)
func weakUnowned() {
class Person {
//左边的闭包fn内部如果用到了实例成员(属性、方法)
lazy var fn: (() ->()) = {
[weak self] in
//口编译器会强制要求明确写出self
self?.run()
}
func run() { print("run") }
deinit { print("deinit") }
}
//如果lazy属性是闭包调用的结果,那么不用考虑循环引用的问题(因为闭包调用后,闭包的生命周期就结束了)
class Person1 {
var age: Int = 0
lazy var getAge: Int = {
self.age
}()
}
}
///---------- 逃逸闭包escaping
///逃逸闭包、逃逸闭包,一般都是当做参数传递给函数
///非逃逸闭包:闭包调用发生在函数结束前,闭包调用在函数作用域内
///逃逸闭包:闭包有可能在函数结束后调用,闭包调用逃离了函数的作用域,需要通过@escaping声明
///
func 逃逸闭包escaping() {
typealias Fn = () -> ()
//fn是非逃逸闭包
func test1(_ fn: Fn) { fn() }
//fn是逃逸闭包
var gFn: Fn?
func test2(_ fn: @escaping Fn) { gFn = fn }
}
///---------- 局部作用域 do, 类似于oc的{ }
func 局部作用域do() {
do {
var a = 10
}
do {
var a = 2
}
}
/// ------ 指针
func pointer() {
func unsafePointer(a: UnsafePointer<Int>) {
print(a.pointee)
}
func unsafeMPointer(a: UnsafeMutablePointer<Int>) {
a.pointee = 20
}
var b = 10
unsafePointer(a: &b)
unsafeMPointer(a: &b)
// Swift中也有专门的指针类型,这些都被定性为“Unsafe”(不安全的),常见的有以下4种类型:
// UnsafePointer<Pointee>似 const Pointee *, 不可修改 只能访问
// UnsafeMutablePointer<Pointee>似 Pointee * ,可以修改指针指向的内容
// UnsafeRawPointer似 const void *
// UnsafeMutableRawPointer 类似 void *
}
/// ---- 通配符
/// _ 匹配任何值
/// _? 匹配非nil值 针对可选项来说
///
func 通配符() {
enum Price {
case a(Int, Int?)
case b(Double?)
}
var c = Price.a(10, 10)
switch c {
case .a(let first, _): // 第二个值nil或者有值都可以
print(first)
case .b(_?): // 匹配非空
print("afa")
default:
break
}
}
/// ---- 枚举case模式
///
func enumcase() {
var age = 10
// if case等价于只有一个case的switch语句
if case 0...9 = age {
print("haha")
}
switch age {
case 0...9:
print("haha")
default: break
}
// guard case模式
guard case 0..<10 = age else {
return
}
}
/// ------ 注释
func 注释() {
// FIXME: ADF
// TODO: HAHD
// MARK: ASDFAF
// MARK: - ADFASF
}
/// --- oc调用swift
func oc调用swift() {
@objc(NewClass) // 可以使用@objc自定义方法名和类名
@objcMembers class Caaa: NSObject { // 需要继承自NSObject
// @objcMembers可以把所有方法和属性都暴露给oc 相当于每个成员前面都增加@objc
@objc func callrun() {
perform(#selector(run))
perform(#selector(run(a:)))
}
@objc func run(a: Int) {
}
}
}
/// --- string substring 字符串处理
func stringt() {
// String可以通过下标、prefix、 suffix等截取子串,子串类型不是String,而是Substring
var str = "1_2_3_4_5"
//1_2
var substr1 = str.prefix(3)
var substr2 = str.suffix(3)
var range = str.startIndex..<str.index(str.startIndex, offsetBy: 3)
var substr3 = str[range]
//最初的String,1_2_3_4_5
print(substr3.base)
// Substring -> String
var str2 = String(substr3)
}
/// ------ swift 支持kvc kvo
/// 类需要继承自nsobject
/// 用@objc dynamic来修饰属性
///
///
///
/// ------ swift 关联对象 给拓展增加存储属性
class Prer {
}
extension Prer {
private static var nameKey = true // 使用void?也行 因为都占用一个字节
var name: Int {
get {
objc_getAssociatedObject(self, &Self.nameKey) as! Int
}
set {
objc_setAssociatedObject(self, &Prer.nameKey, newValue, .OBJC_ASSOCIATION_ASSIGN)
}
}
}
/// ------ 可选项的map和flatMap
/// map和flatMap会先判断 如果是非nil才会继续执行,flatMap区别是会判断已经是可选项了 就不会再次包装 即不会出现??的情况
func optionalMap() {
var age: Int? = 10
var b = age.flatMap {
$0 + 1
}
print(b as Any)
}