1、类里有个方法,那么这个方法是存储到哪里?
是在代码段,而不是类的存储空间,因为这个方法在类里边和在类外边本质是一样的
class Person {
var name = "张三"
var age = 26
func show(){
print(self.name,self.age)
}
}
var p = Person()
p.show()
等价于----------------
class Person {
var name = "张三"
var age = 26
}
func show(self : Person){
print(self.name,self.age)
}
var p = Person()
show(self: p)
2、swift 结构体Stuart实例和类class实例分别存储在什么地方
结构体Stuart实例是在栈空间,类class实例是在堆空间
因为
(1)结构体是值类型,而类是引用类型
(2)创建类的实例对象,要向堆空间申请内存,而结构体不用,结构体的本质是值传递
3、在swift中,创建类的实例对象,要向堆空间申请内存,大概流程是什么?
(1) Class._allocating_init()
(2) libswiftCore.dylib:_swift_allocObject_
(3) libswiftCore.dylib:swift_slowAlloc_
(4) libsystem_malloc.dylib:malloc
4、swift 以下函数的打印结果是什么
typealias Fn = (Int) -> Int
func getFn() -> Fn {
//局部变量
var num = 0
func plus(_ i: Int) -> Int {
num += 1
return num
}
return plus
} //返回的plus和num形成了闭包
var fn = getFn()
print(fn(1))
print(fn(2))
print(fn(3))
print(fn(4))
答案分别为 1 3 6 10
var num = 0定义为全局变量或者是局部变量答案都是1 3 6 10
因为num为局部变量时,num会向堆空间申请内存来保存它的值,内层函数会捕获外层函数局部变量的堆空间内存值,所以答案分别为 1 3 6 10
5、swift的inout本质
1)如果实参有物理内存地址,且没有设置属性观察器:
直接将实参的内存地址传入函数(实参进行引用传递)
2)如果实参是计算属性 或者 设置了属性观察器:
采取了Copy in 和 Copy out的做法:
- 调用该函数时,先复制实参的值,产生副本[get]
- 将副本的内存地址传入函数(副本进行引用传递),在函数内部可以修改副本的值
- 函数返回后,再将副本的值覆盖实参的值[set]
总结:inout的本质就是引用传递(地址传递)
6、swift结构体和枚举是值类型,默认情况下,值类型的属性不能被自身的实例方法修改,在什么情况下可以修改?
在func关键字前加mutating可以允许这种修改行为
7、初始化器
(1)类、结构体、枚举都可以定义初始化器
(2)类有2种初始化器:指定初始化器(designated initializer)、便捷初始化器(convenience initializer)
//指定初始化器
init(parameters) {
statements
}
//便捷初始化器
convenience init(parameters) {
statements
}
- 每个类至少有一个指定初始化器,指定初始化器是类的主要初始化器
- 默认初始化器总是类的指定初始化器
- 类偏向于少量指定初始化器,一个类通常只有一个指定初始化器
(3)初始化器的相互调用规则
- 指定初始化器必须从它的直系父类调用指定初始化器
- 便捷初始化器必须从相同的类里调用另一个初始化器
- 便捷初始化器最终必须调用一个指定初始化器
(4)两段式初始化
第1阶段:初始化所有存储属性
① 外层调用指定\便捷初始化器
② 分配内存给实例,但未初始化
③ 指定初始化器确保当前类定义的存储属性都初始化
④ 指定初始化器调用父类的初始化器,不断向上调用,形成初始化器链
第2阶段:设置新的存储属性值
① 从顶部初始化器往下,链中的每一个指定初始化器都有机会进一步定制实例
② 初始化器现在能够使用self(访问、修改它的属性,调用它的实例方法等等)
③ 最终,链中任何便捷初始化器都有机会定制实例以及使用self
注意:
1、指定初始化器必须保证在调用父类初始化器之前,其所在类定义的所有存储属性都要初始化完成
2、指定初始化器必须先调用父类初始化器,然后才能为继承的属性设置新值
3、便捷初始化器必须先调用同类中的其它初始化器,然后再为任意属性设置新值
4、初始化器在第1阶段初始化完成之前,不能调用任何实例方法、不能读取任何实例属性的值,也不能引用self
5、直到第1阶段结束,实例才算
8、访问控制权限
在访问权限控制这块,Swift提供了5个不同的访问级别(以下是从高到低排列, 实体指被访问级别修饰的内容)
① open:允许在定义实体的模块、其他模块中访问,允许其他模块进行继承、重写(open只能用在类、类成员上)
② public:允许在定义实体的模块、其他模块中访问,不允许其他模块进行继承、重写
③ internal:只允许在定义实体的模块中访问,不允许在其他模块中访问
④ fileprivate:只允许在定义实体的源文件中访问
⑤ private:只允许在定义实体的封闭声明中访问
绝大部分实体默认都是internal级别
9、Swift与OC互相调用
(1)Swift调用OC
- 在新建OC类的时候Xcode会给出提示创建桥接文件,这个桥接文件中是OC需要暴露给Swift的内容,如引用OC头文件#import "ZycOCViewController.h"
- 也可手动创建桥接文件,默认格式为 targetName-Bridging-Header.h
(2)OC调用Swift
-
和Swift调用OC一样,在新建Swift类的时候会先提示创建桥接文件,也是用来OC需要暴露给Swift的,如引用OC头文件#import "ZycOCViewController.h"
-
Xcode已经默认生成一个用于OC调用Swift的头文件,文件名格式是: targetName-Swift
-
在使用的地方引入 #import "targetName-Swift.h" 就可以调用Swift (注意:使用Swift的内容要用OC的写法)
-
Swift暴露给OC的类最终继承自NSObject
-
使用@objc修饰需要暴露给OC的成员
-
使用@objcMembers修饰类,(1)代表默认所有成员都会暴露给OC(包括扩展中定义的成员) (2)最终是否成功暴露,还需要考虑成员自身的访问级别
10、函数式编程
- 函数式编程(Funtional Programming,简称FP)是一种编程范式
-
- 主要思想:把计算过程尽量分解成一系列可复用函数的调用
-
- 主要特征:函数是“第一等公民”
-
-
- 函数与其他数据类型一样的地位,可以赋值给其他变量,也可以作为函数参数、函数
-
(1)传统写法
func add1( _ v1:Int , _ v2:Int) -> Int {
v1 + v2
}
add1(1,2) //3
func add2( _ v1:Int , _ v2:Int , _ v3:Int ) -> Int {
v1 + v2 + v3
}
add2(1,2,3) //6
(2)柯里化(Currying)
- 将一个接受多参数的函数变换为一系列只接受单个参数的函数
//两个参数
func add( _ v1:Int , _ v2:Int) -> Int {
v1 + v2
}
//柯里化
func add(_ v1:Int) -> (Int) -> Int {
return { v2 in
v1 + v2
}
}
add(1)(2) // v1=1 v2=2 结果为3
//三个参数
func add1( _ v1:Int , _ v2:Int , _ v3:Int ) -> Int {
v1 + v2 + v3
}
//柯里化
func add1(_ v1:Int) -> (Int) -> (Int) -> Int {
return { v2 in
{ v3 in
v1 + v2 + v3
}
}
}
add1(1)(2)(3) // v1=1 v2=2 v3=3 结果为6
........
- 泛型
//两个参数
func add( _ v1:Int , _ v2:Int) -> Int {
v1 + v2
}
//柯里化泛型
func currying<A, B, C>(_ fn: @escaping (A, B) -> C) -> (A) -> (B) -> C {
{ a in
{ b in
fn(a, b)
}
}
}
currying(add)(1)(2) //a=v1=1 b=v2=2 结果为3
//三个参数
func add1( _ v1:Int , _ v2:Int , _ v3:Int ) -> Int {
v1 + v2 + v3
}
func currying<A, B, C, D>(_ fn: @escaping (A, B, C) -> D) -> (A) -> (B) -> (C) -> D {
{ a in
{ b in
{ c in
fn(a, b, c)
}
}
}
}
currying(add1)(1)(2)(3) //a=v1=1 b=v2=2 c=v3=3 结果为6
prefix func ~<A, B, C, D>(_ fn: @escaping (A, B, C) -> D) -> (A) -> (B) -> (C) -> D { { a in { b in { c in fn(a, b, c) } } } }
(~add1)(1)(2)(3) //a=v1=1 b=v2=2 c=v3=3 结果为6
.......