1.@objc
作用:把函数或属性编译进项目-Swift文件中,这样在OC调用Swift的方法的时候就不会报找不到这个方法了
->1.Swift 的静态语言特性,每个函数的调用在编译期间就可以确定。因此在编译完成后可以检测出没有被调用到的 swift 函数,优化删除后可以减小最后二进制文件的大小。而OC是动态语言,函数的调用在运行时才能确定有没有被调用。所以为了避免OC找不到swift的函数,添加 @objc 的方法表示这个方法是被OC调用的,这样swift在编译的时候,虽然检测到这个函数暂时没有被调用,但是也不会被优化删除,编译进项目-Swift文件中。
->2.类前加上@objcMembers,那么它及其子类、扩展里的方法都会隐式的加上@objc,@nonobjc可以去掉@objc,
->3.Selector中调用的方法需要在方法前声明@objc,目的是允许这个函数在“运行时”通过 Objective-C 的消息机制调用
->4.协议的方法可选时,协议和可选方法前要用@objc,(这个不知道为什么,哪位大神给指点下)
2. _
忽略参数名
3.Struct和Class的区别
https://www.jianshu.com/p/34f253cb19d4
->类是引用类型,结构体为值类型
->结构体不支持继承
->值类型被赋予给一个变量,常量或者被传递给一个函数的时候,其值会被拷贝
->引用类型在被赋予到一个变量,常量或者被传递到一个函数时,其值不会被拷贝,因此引用的是已存在的实例本身而不是其拷贝
4.Swift比Objective-C有什么优势?
->Swift速度更快,运算性能更高
->Swift语法简单易读,代码更少,更加清晰,易于维护
->Swift更加安全,它是类型安全的语言
->Swift泛型,结构体,枚举都很强大
->Swift便捷的函数式编程
->Swift 类型判断
5.Swift是面向对象还是函数式编程语言?
->Swift即是面向对象的,又是函数式的编程语言
->说Swift是面向对象的语言,是因为Swift支持类的封装,继承和多态
->说Swift是函数式编程语言呢,是因为Swift支持map,reduce,filter,flatmap这类去除中间状态,数学函数式的方法,更加强调运算结果而不是中间过程
6.dynamic framework 和 static framework 的区别是什么?
->静态库和动态库,静态库是每一个程序单独打包一份,而动态库则是多个程序之间共享,
->静态库和动态库是相对编译期和运行期的:静态库在程,序编译时会被链接到目标代码中,程序运行时将不再更改静态库;而动态库在程序编译时并不会被链接到目标代码中,只是在程序运行时才被载入,因此在程序运行期间还需要动态库的存在
静态库好处:
模块化,分工合作,提高了代码的复用以及核心技术的保密程度
避免少量改动经常导致大量的重复编译连接
也可以重用,注意不是共享使用
动态库好处:
使用动态库,可以将最终可执行文件体积缩小,将整个应用程序分模块,团队合作,进行分工,影响比较小
使用动态库,多个应用程序共享内存中的同一份库文件,节省资源
使用动态库,可以不重新编译连接可执行程序的前提下,更新动态库文件达到更新应用程序的目的
不同点:
静态库在连接时,会被完整的复制到可执行文件中,如果多个APP都使用了同一个静态库,那么每个App都会拷贝一份,缺点是浪费内存。类似于定义一个基本变量,使用该基本变量是是新复制了一份数据,而不是原来定义的
动态库不会复制,只有一份,程序运行时动态加载到内存中,系统个只会加载一次,多个程序共享一份,节约内存,类似于使用变量的内存地址一样,使用的是同一个变量
共同点:静态库和动态库都是闭源库,只能拿来满足某个功能的使用,不会暴露内部具体的代码信息
7.Swift值类型的写时复制
->只有当一个结构体发生写入行为时才会有复制行为
->在结构体内部用一个引用类型来存储实际的数据,在不进行写入操作的普通传递过程中,都是将内部的reference的引用计数+1,在进行写入操作时,对内部的reference做一次copy操作用来存储新的数据,防止和之前的reference产生意外的数据共享
->swift中提供该[]函数,他能检查一个类的实例是不是唯一的引用,如果是,我们就不需要对该结构体实例进行复制,如果不是,说明对象被不同的结构体共享,这是对他进行更改就需要进行复制
8.defer的用法
->使用defer代码块来表示在函数返回前,函数中最后执行的代码,无论函数是否会跑出错误,这段代码都将执行
->defer语句块中的代码,会在当前作用于结束前调用,每当一个作用于结束,就进行该作用域defer执行
->defer执行的顺序为逆序(栈式)
->defer中捕获的变量的值是可以进行更改的
9.inout输入输出参数
->函数参数默认是常量,试图从函数主题内部更改函数参数的值会导致编译时错误,这意味着您不能错误地更改参数的值,如果您希望函数修改参数的值,并且希望这些更改在函数调用结束后仍然存在,请将该参数定义为输入输出参数
->您可以通过将inout关键词放在参数类型的前面来编写输入输出参数,一个在出参数具有传递的值中,有函数修改的功能,并将该部分送回出的功能来替代原来的值,
->您只能将变量作为输入输出参数的参数传递。您不能将常量或文字值作为参数传递,因为无法修改常量和文字。当您将一个与号(&)作为变量传入in-out参数时,将它放在变量名的前面,以表明该变量可以被函数修改
->其本质是将指向的参数的指针,传入进去了
10.什么是高阶函数
->一个函数如果可以以某一个函数作为参数,或者是返回值,那么这个函数就称之为高阶函数
11.static和calss的区别
->在Swift中static和class都表示“类型范围作用域”的关键词,在所有类中,我们可以使用过static来描述类型作用域,class是专门用来修饰class类型的
1.static可以修饰属性和方法,
->所有修饰的属性和方法不能够被重写
->static修饰的类方法和属性包含final关键字的特性,重写会报错
2.class修饰方法和属性
->我们同样可以使用class修饰方法和计算属性,但是不能够修饰存储属性
->类方法和计算属性都是可以被重写的,可以使用class关键字也可以是static
12.访问修饰符
Swift有5个级别的访问控制权限,从高到低依次Open,Public,internal,fileprivate,private
子类的访问权限不能比父类的访问权限大
open:可以被任何类使用和继承
public:可以背任何人访问,但是其他module中不可以被重写和继承,而module内可以被重写和继承
internal:(默认访问级别,internal修饰符可写可不写)
internal访问级别所修饰的属性或方法在源代码所在的整个模块都可以访问。如果是框架或者库代码,则在整个框架内部都可以访问,框架由外部代码所引用时,则不可以访问如果是App代码,也是在整个App代码,也是在整个App内部可以访问
fileprivate:fileprivate访问级别所修饰的属性或者方法在当前的Swift源文件里可以访问
private:private访问级别所修饰的属性或者方法只能在当前类里访问。
13.Strong,weak,unowned
Swift的内存管理机制与Object-C一样为ARC,它的基本原理是,一个对象在没有任何强指针引用指向它是,其占用的内存会被回收,反之,只要有任何一个强指针指引用指向该对象,它就会一直存在与内存中
Strong代表着强引用,是默认属性,当一个对象被声明为 strong 时,就表示父层级对该对象有一个强引用的指向。此时该对象的引用计数会增加1
weak 代表着弱引用。当对象被声明为 weak 时,父层级对此对象没有指向,该对象的引用计数不会增加1。它在对象释放后弱引用也随即消失。继续访问该对象,程序会得到 nil,不亏崩溃
unowned 与弱引用本质上一样。唯一不同的是,对象在释放后,依然有一个无效的引用指向对象,它不是 Optional 也不指向 nil。如果继续访问该对象,程序就会崩溃
weak 和 unowned 的引入是为了解决由 strong 带来的循环引用问题。简单来说,就是当两个对象互相有一个强指向去指向对方,这样导致两个对象在内存中无法释放
weak 和 unowned 的使用场景有如下差别:
->当访问对象时该对象可能已经被释放了,则用 weak。比如 delegate 的修饰
->当访问对象确定不可能被释放,则用 unowned。比如 self 的引用
->实际上为了安全起见,很多公司规定任何时候都使用 weak 去修饰
->weak的对象,在block块内再次获取值时可能为nil,相当于变成了一个可选值,调用属性或者方法需要加上?或者强制解析!,但是强制解析在对象已经被释放了时肯定会造成强解错误,导致程序崩溃
->unowned的对象,在block块内再次获取值时依然是对象本身,只是该对象可能被释放了,因此调用者必须保证在执行block块时该对象一定依然存在,不然调用对象的方法时会造成崩溃
14.Swift为什么将String,Array,Dictionary设计成值类型?
->值类型相比引用类型,最大的优势在于内存使用的高效。值类型在栈上操作,引用类型在堆身上操作,栈上的操作仅仅是单个指针的上下移动,而堆上的操作则牵涉到合并,移位,重新链接等,也就是说swift这样设计,大幅减少了堆上的内存分配和回收的次数,同时copy-on-write又将值传递和复制的开销降到了最低
->String,Array,Dictionary设计成值类型,也是为了线程安全考虑,通过swift的let设置,使得这些数据达到真正意义上的不变,它从根本上解决了多线程中内存访问和操作顺序的问题
->设计成值类型可以提升API的灵活度,例如通过实现Collection这样的协议,我们可以遍历String,使得整个开发更加灵活高效
15.闭包是引用类型吗
闭包是引用类型,如果一个闭包被分配给一个变量,这个变量复制给另一个变量,那么他们引用的是同一个闭包,他们的捕捉列表也会被复制
16.Swift mutating关键字的使用
类是引用类型,而结构体和枚举是值类型,默认情况下,不能在其实例方法中修改值类型的属性,为了修改值类型的属性,必须在实例方法中使用mutating关键字,使用此关键字,你的方法将能够更改属性的值,并在方法实现结束时将其写回到原始结构
1.纯Swift类的函数调用已经不再是Objective-c的运行时发消息,而是类似C++的vtable,在编译时就确定了调用哪个函数,所以没法通过runtime获取方法、属性
2.TestSwiftVC继承自UIViewController,基类为NSObject,而Swift为了兼容Objective-C,凡是继承自NSObject的类都会保留其动态性,所以我们能通过runtime拿到他的方法。(表示这个类可以被OC使用)
3.可以知道@objc是用来将Swift的API导出给Objective-C和Objective-C runtime使用的,如果你的类继承自Objective-c的类(如NSObject)将会自动被编译器插入@objc标识
4.纯Swift类没有动态性,但在方法、属性前添加dynamic修饰可以获得动态性。 继承自NSObject的Swift类,其继承自父类的方法具有动态性,其他自定义方法、属性需要加dynamic修饰才可以获得动态性。
若方法的参数、属性类型为Swift特有、无法映射到Objective-C的类型(如Character、Tuple),则此方法、属性无法添加dynamic修饰(会编译错误), dynamic破坏swift的静态化 Swift类在Objective-C中会有模块前缀
5.所有运行时方法都依赖TypeEncoding,也就是method_getTypeEncoding返回的结果,他指定了方法的参数类型以及在函数调用时参数入栈所要的内存空间,没有这个标识就无法动态的压入参数(比如testReturnVoidWithaId: Optional("v24@0:8@16") Optional("v"),表示此方法参数共需24个字节,返回值为void,第一个参数为id,第二个为selector,第三个为id),而Character和Tuple是Swift特有的,无法映射到OC的类型,更无法用OC的typeEncoding表示,也就没法通过runtime获取了