iOS swift知识点

304 阅读7分钟

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 inCopy 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
.......