Swift 面试 3

523 阅读6分钟

1.类和结构体的区别是什么

类和结构体的 创建方式一个在堆一个在栈(结构体一般会被优化存储到栈上,但不是绝对的),或者类是引用类型 结构体是值类型 这种只要是Swifter都懂得答案。(个人测试过结构体和类的创建速度,因为结构体创建一般不涉及到堆内存分配,创建速度比类快了10w倍不止,早期的swift版本效果可能没这么大,10w这个数字也是不准的,但的确快了好几个量级。当然类创建速度也不慢,只不过是相对而言)

但是其实也可以深入的问一下,比如类和结构体的 编译方式区分,分类和类的编译方式区分,Swift为什么要在有类的同时又设计了结构体和枚举。等等

1.内存管理不一样,类引用类型,分配在堆上。结构体是值类型,分配在栈上。

(解释:引用类型是讲一个对象赋值给另一个对象时系统不会进行此对象的拷贝,而是将指向这个对象的指针赋值给另一个对象,当修改其中一个对象的值时,另一个对象的值也会改变。值类型是将一个对象赋值给另一个对象时,会对此对象进行拷贝,复制出一份副本给另一个对象,在修改其中一个对象的值时,不影响另外一个对象。)

2.类,有析构函数。结构体不能有析构函数。

(解释:析构函数(destructor) 与构造函数相反,当对象结束其生命周期,如对象所在的函数已调用完毕时,系统自动执行析构函数。析构函数往往用来做“清理善后” 的工作(例如在建立对象时用new开辟了一片内存空间,delete会自动调用析构函数后释放内存))

3.结构体构造函数会自动生成带参数的构造器。类不会对有初始化赋值生成带参数的构造器。

4.类有继承特性,结构体没有继承特性。结构体无继承特性,则无法对成员属性、成员方法、类属性、类方法进行重载。结构体的函数操作符需要static,不能使用class。

5.类中的每一个成员变量都必须被初始化,否则编译器会报错。而结构体不需要,编译器会自动帮我们生成init函数,给变量赋一个默认值。

2.写时拷贝机制

Swift本身是很建议程序员少用类 多用结构体 枚举。但是使用结构体的时候,写时拷贝如果不清楚的话,很容易写出性能不是很好的代码。如果是对算法要求高的公司写时拷贝机制是必问的。

指的是Swift 中的值类型,并不会在一开始赋值的时候就开辟新的内存空间,只有在需要改变这个值的时候才去开辟新的内存空间,以达到优化内存的目的. 

var arr1 = [1,2,3]
var arr2 = arr1//[1,2,3]
print1(address: arr1)
print1(address: arr2)
arr2.append(4)// 改变数组 arr2
print1(address: arr1)
print1(address: arr2)
 
arr1的地址:0x137e2f930
arr2的地址:0x137e2f930
改变arr2 之后:
arr1的地址:0x137e2f930
arr2的地址:0x139901670

Swift 中采用了如上所述的写时复制技术. 即当一个结构体发生了写入行为时才会有复制行为.

3.模式匹配

其他语言使用Switch语法或多或少 都有这样那样的限制,
Swift的Switch就不一样,除了对枚举 数字 字符串 Switch,
还可以对任意的实现了~=运算符的对象 Switch。
还支持where子句、匹配范围、类型推断转换。。。等等。如此强大的Switch,

4.协议

Swift的一大亮点就是面向协议开发,程序员可以 对协议扩展默认实现。
不但能实现其他语言的类似多继承的效果、而且面向协议开发能对代码带来极大的扩展性。

class ViewCotroller: UIViewController
{
    func testMethod() {
        print("测试方法")
    }
}


class tableViewContoller:UITableViewController{
    func testMethod() {
        print("测试方法")
    }
}

以上是常见的面向对象编程,如果我们像这不同的继承关系里抽出相同的代码,

1、用新的类型来提供这个功能
class testTool{
    func testMethod() {
        print("测试方法")
    }
    
}

class ViewCotroller: UIViewController
{
    var testtool:testTool?
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        self.testtool = testTool()
        self.testtool?.testMethod()
    }
}

class tableViewContoller:UITableViewController{
    var testtool:testTool?
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
     self.testtool = testTool()
     self.testtool?.testMethod()
    }
}
  • 依赖注入引入额外的依赖关系,可能也是我们不太愿意看到的。
2、UIViewController 上添加 extension
extension UIViewController{
    func testMethod() {
        print("测试方法")
    }
}
let v = ViewCotroller()
v.testMethod()

let t = tableViewContoller()
t.testMethod()
  • 看起来这是一个稍微靠谱的做法,但是给任何UIViewController类都添加了testMethod,这种添加代码影响也是不可估计 的,不想看到的。
3、面向协议编程
import UIKit

protocol test{

   func testMethod()
}


extension test{

    func testMethod(){
        print("测试方法")
    }
    
}


class ViewCotroller: UIViewController,test
{
  
}


class tableViewContoller:UITableViewController,test{

}

let  v = ViewCotroller()

let  t = tableViewContoller()

v.testMethod()
t.testMethod()
  • 通过易个协议扩展,我们只需要简单地声明 ViewController 和 tableViewContoller 遵守 test,就可以直接使用 testMethod 的实现了:

5.泛型

Swift的泛型感觉真的是做到了极致了,Swift标准库里面用到了大量的协议和泛型。

6. 运算符、下标、字面量协议、尾随闭包

7. Optional、变量常量、类型检查、扩展

现代语言设计有很多必选项。Kotlin和Swift有很多相似之处,各有所长。 但是他们不约而同的设计了类似于Optional这些特性,主要还是因为这些特性都是太多人

8.函数式编程

什么函子、单子 使劲问、函数是第一公民之类的也都是必问的。

9.响应式编程

可以问问RxSwift、也可以问问苹果新出的Combine,思想都一样。 比如响应式编程在网络请求,数据解析,UI响应 等等各个方面的表现

10.单向数据流模式

结合Redux问问单项数据流的一些流程原理。(Swift版的有个ReSwift或者RxFeedback等等)

11.MVC、MVVM、Coordinator、单向数据流

这些模式用法千人千面,没有标准答案,都可以深入探讨

12.SwiftUI

苹果新出的UI库,结合Flutter,讨论两者之间各自的好处

13.Swift5.1新特性

比如@propertyWrapper、@_functionBuilder、@dynamicMemberLookup每一个都值得探讨

14.Swift在其他领域的扩展

比如探讨下Swift在Web、后端开发上面的思路、探讨下Swift在人工智能上面有什么语法的优越性、以及Swift在直接使用其他语言所写的库的可行性思路。