Swift-基础知识

151 阅读6分钟

一、struct和class区别

1、值类型和引用类型

值类型变量

值类型变量是直接包含数据,每个值类型变量都有自己的数据副本,因此对一个值类型变量操作不会影响另一个值类型变量

引用类型变量

引用类型变量存储数据的引用,引用类型的变量也就是对象,对一个引用类型变量的操作可能影响另一个变量所引用的对象

2、结构体(struct)

  • 结构体是值类型
  • 没有引用计数,不会因为循环引用造成内存泄漏,值类型是线程安全的
  • 内存分配在栈中
  • 地址存储的就是值,传递过程相当于传递了一个副本
  • 自动初始化构造方法
  • 不能继承
  • 不能被序列化成NSData对象
  • 不支持身份操作符“===”

3、类(class)

  • class是引用类型
  • 有引用计数,循环引用会导致内存泄漏
  • 内存分配在堆中,需要开发者自行管理内存
  • 地址存储的是引用,class的实例是通过引用传递的
  • 需要显式初始化方法
  • 可以继承
  • 可以被序列化成NSData对象
  • 支持身份操作符“===”

4、什么时候用struct

  • 模型较小时
  • 无需继承时
  • 无需序列化成NSData对象时
  • 无需Objective-C使用时
  • 对变量不做变化时
  • 对变量变化不需要传递时

二、访问控制关键字

  • open:具备最高的访问权限,其修饰的类和方法,可以在任意模块中被访问和重写
  • public:权限仅次于open,和open的区别是不允许其他模块进行继承和重写
  • internal:默认权限,只允许在当前模块中访问,可以继承和重写,不允许在其他模块中被访问
  • fileprivate:修饰的对象只允许在当前文件中被访问,例如他可以被一个文件中的class、struct、extension共同使用
  • private:限制的实体只能在其定义的作用域(类、结构体、枚举、扩展)内访问

三、Swift和OC如何相互调用?

Swift调用OC代码

  • 需要创建一个Target-BriBridging-Header.h的桥文件,在桥文件中导入需要调用OC代码的头文件即可

OC调用Swift代码

  • 在OC中直接导入Target-Swift.h文件即可, Swift代码对OC可见需要@objc标记属性和方法

四、Swift的高阶函数

map

map函数用于对集合中的每一个元素应用一个转换闭包,然后返回一个包含转换结果的新集合。 示例:

let numbers = [1, 2, 3, 4, 5]
let newNumbers = numbers.map { $0 * 2 }
print(newNumbers)   //输出[2, 4, 6, 8, 10]

filter

filter函数用于从集合中选择满足指定条件的元素,并返回一个包含满足条件的元素的新集合。 示例:

let numbers = [1, 2, 3, 4, 5]
let newNumbers = numbers.filter { $0 % 2 == 0 }
print(newNumbers)   //输出[2, 4]

reduce

reduce函数用于将集合中的所有元素组成单个值,并返回该值。 示例:

let numbers = [1, 2, 3, 4, 5]
let newNumbers = numbers.reduce(0, { $0 + $1 })
print(newNumbers)   //输出15

flatMap

flatMap函数用于对集合中的每一个元素应用一个转换闭包,并将结果拼接成一个新的集合。 示例:

let numbers = [[1, 2, 3], [4, 5, 6]]
let newNumbers = numbers.flatMap { $0 }
print(newNumbers)   //输出[1, 2, 3, 4, 5, 6]

compactMap

compactMap函数用于对集合中的每一个元素应用一个转换闭包,并过滤掉结果中的nil值。 示例:

let numbers = ["1", "2", "3", "hello", "5"]
let newNumbers = numbers.compactMap { Int($0) }
print(newNumbers)   //输出[1, 2, 3, 5]

allSatisfy

allSatisfy函数用于检查序列中的所有元素是否都满足指定条件。 示例:

let numbers = [2, 4, 6, 8, 10]
let newNumbers = numbers.allSatisfy { $0 % 2 == 0 }
print(newNumbers)   //输出true

五、Swift中的存储属性和计算属性

Swift语言中的属性从行为上可以分为存储属性计算属性两类。存储属性和计算属性的区别在于:存储属性用于描述存储值,而计算属性用于描述计算过程并获取计算结果;

存储属性

存储属性用来定义或者结构体的某些特性,简单来说就是用变量var或者常量let存储的某些有意义的值;在创建类或者结构体的实例时,必须为所有的存储属性设置一个合适的初始值。 注意:使用var声明的age,在SIL中生成了setget方法;而let声明的sex只生成了get方法;因此再次给sex赋值时实际是调用set方法,但是因为找不到set方法,所以无法再次赋值;

计算属性

存储属性相比,计算属性更像是运算过程,计算属性并不存储值,而是提供getset方法来修改和获取值。存储属性我们可以定义常量或者是变量,但是对于计算属性,必须定义为变量,并且计算属性在定义时必须包含类型;

六、Swift final关键字

  • 限制类的继承:在类的定义前加上final关键字,可以防止其他类继承该类;
  • 限制属性的重写:在属性的定义前加上final关键字,可以防止子类重写该属性;
  • 限制方法的重写:在方法的定义前加上final关键字,可以防止子类重写该方法;

七、class和static区别

  • 只有class对象才允许使用class关键字,结构体、协议、枚举只能使用static关键字;
  • 定义类型存储属性,只能使用static,不允许使用class;
  • class 修饰的计算属性可以被重写,static 修饰的不能被重写;
  • static 可以修饰存储属性,static 修饰的存储属性称为静态变量(常量);
  • static 修饰的静态方法不能被重写,class 修饰的类方法可以被重写;
  • class 修饰的类方法被重写时,可以使用static 让方法变为静态方法;
  • class 修饰的计算属性被重写时,可以使用static 让其变为静态属性,但它的子类就不能被重写了;
  • 有一个比较特殊的是protocol。在Swift中class、struct和enum都是可以实现protocol的。那么如果我们想在protocol里定义一个类型域上的方法或者计算属性的话,应该用哪个关键字呢?答案是使用class进行定义,但是在实现时还是按照规则:在class里使用class关键字,而在struct或enum中仍然使用static,虽然在protocol中定义时使用的是class;

八、runLoop

什么是runLoop?

默认情况下,线程执行完任务就会退出,不再执行任务,我们需要采取一种方式让线程能够不断的执行任务,所以就有了runLoop。

顾名思义,runLoop就是一直不断执行的循环。

runloop实际上是一个对象,这个对象在循环中用来处理程序运行中出现的各种事件(触摸、UI刷新、定时器、Selector等,从而保持程序的持续运行,runLoop在没有事件处理时,会让线程休眠,只有在接收到事件时才会被唤醒,然后处理相应事件。

一条线程对应一个runloop对象,主线程的runloop对象由系统自创建

RunLoop Mode

  • default
  • tracking:界面跟踪mode,用于scrollView跟踪触摸滑动,保证界面滑动不受其他mode影响
  • common

常驻线程

为当前线程添加一个runloop

向该runloop中添加一个prot/Source等维持RunLoop的事件循环

启动该RunLoop

九、Runtime

OC是一门动态语言

动态语言是指程序在运行时可以改变其结构;添加新的函数、属性,删除已有的函数、属性等结构上的变化,在运行时做类型的检查。

OC的动态性由runtime支持的。

runtime是一个C语言的库,提供API创建类,添加方法,删除方法,交换方法等。

十、手势冲突优化

十一、类短视频的搭建方法

十一、线程