# Swift学习 # 简单面试题

1.什么是函数式编程?

函数式编程其实是一种编程思想, 代码写出来只是它的表现形式

在面向对象的编程思想中, 我们将要解决的一个个问题, 抽象成一个个类, 通过给类定义属性和方法, 让类帮助我们解决需要处理的问题.(其实面向对象也叫命令式编程, 就像给对象下一个个命令)

而在函数式编程中, 我们则通过函数描述我们要解决的问题, 以及解决问题需要怎样的方案.

RxSwift

2.swift相对于OC有哪些优点?

1、swift语法简单易读、代码更少,更加清晰、易于维护

2、更加安全,optional的使用更加考验程序员对代码安全的掌控

3、泛型、结构体、枚举都很强大

4、函数为一等公民,便捷的函数式编程

5、有命名空间 基于module

6、类型判断

oc的优点、运行时

3.什么是泛型,swift在哪些地方使用了泛型?

泛型(generic)可以使我们在程序代码中定义一些可变的部分,在运行的时候指定。使用泛型可以最大限度地重用代码、保护类型的安全以及提高性能。

例如 optional 中的 map、flatMap 、?? (泛型加逃逸闭包的方式,做三目运算)

4.defer、guard的作用?

defer 包体中的内容一定会在离开作用域的时候执行

guard 过滤器,拦截器

5.swift语法糖 ?!的本质(实现原理)

? 为optional的语法糖

Optional< T > 是一个包含了 nil 和 普通类型的枚举,确保使用者在变量为nil的情况下的处理

!  为optional 强制解包 的语法糖

6.举例swift中模式匹配的作用?

模式匹配: 在switch中体现最明显

通配符模式: _

标识符模式:let i = 1

值绑定模式:case .Student(let name) 或者 case let .Student(name)

元祖模式:case (let code, _)

可选模式:if case let x? = someOptional { }

类型转换模式:case is Int:  或者  case let n as String:

表达式模式:范围匹配 case (0..<2)  case(0...2, 2...4)

条件句中使用where: case (let age) where age > 30

if case let:if case let .Student(name) = xiaoming { }

for case let: for case let x in array where x > 10 {}  或者 for x in array where x > 10

7.swift中closure与OC中block的区别?

1、closure是匿名函数、block是一个结构体对象

2、都能捕获变量

3、closure通过逃逸闭包来在block内部修改变量,block 通过 __block 修饰符

8.什么是capture list,举例说明用处?

捕获列表

weak  unowned

9.swift中private与fileprivate的区别?

private的作用域被约束与被定义的当前类作用域,fileprivate作用域是整个文件

10.Set 独有的方法有哪些?

intersect(_:)// 根据两个集合中都包含的值创建的一个新的集合
exclusiveOr(_:) // 根据只在一个集合中但不在两个集合中的值创建一个新的集合
union(_:) // 根据两个集合的值创建一个新的集合
subtract(_:) //根据不在该集合中的值创建一个新的集合

isSubsetOf(_:) //判断一个集合中的值是否也被包含在另外一个集合中
isSupersetOf(_:) //判断一个集合中包含的值是否含有另一个集合中所有的值
isStrictSubsetOf(:) isStrictSupersetOf(:) //判断一个集合是否是另外一个集合的子集合或者父集合并且和特定集合不相等
isDisjointWith(_:) //判断两个集合是否不含有相同的值

11.实现一个 min 函数,返回两个元素较小的元素

func minNum<T: Comparable>(a: T, b: T) -> T {
    return a > b ? a : b
}

12.map、filter、reduce 的作用

1、map 是Array类的一个方法,我们可以使用它来对数组的每个元素进行转换
let intArray = [1, 3, 5]
let stringArr = intArray.map {
            return "\($0)"
        }
// ["1", "3", "5"]

2、filter 用于选择数组元素中满足某种条件的元素
let filterArr = intArray.filter {
    return $0 > 1
}
//[3, 5]

3、reduce 把数组元素组合计算为一个值
let result = intArray.reduce(0) {
    return $0 + $1
}
//9

13.map 与 flatmap 的区别

1、map 可以对一个集合类型的所有元素做一个映射操作


2、和map 不同,flatmap 在之前版本有两个定义,分别是:
func flatMap(transform: (Self.Generator.Element) throws -> T?) -> [T]
func flatMap(transform: (Self.Generator.Element) -> S) -> [S.Generator.Element]

swift 4.1 废弃后改为

func flatMap(transform: (Self.Generator.Element) throws -> Sequence) -> [Sequence.Element]
func flatMap<U>(_ transform: (Wrapped) throws -> U?) rethrows -> U?


1) flatMap的第一个作用和map一样,对一个集合类型的所有元素做一个映射操作,但是可以过滤为nil的情况

例如:
let array = [1,2,5,6,7,nil]
let array_map = array.map { $0 }
//[Optional(1), Optional(2), Optional(5), Optional(6), Optional(7), nil]
let array_flatmap = array_map.flatMap { $0 }
//[1, 2, 5, 6, 7]


2) 第二种情况可以进行“降维”操作

let array = [["1", "2"],["3", "4"]]
let array_map = array.map { $0 }
//[["1", "2"], ["3", "4"]]
let array_flatmap = array_map.flatMap { $0 }
//["1", "2", "3", "4"]

14.什么是 copy on write

copy on write, 写时复制,简称COW,它通过浅拷贝(shallow copy)只复制引用而避免复制值;当的确需要进行写入操作时,首先进行值拷贝,在对拷贝后的值执行写入操作,这样减少了无谓的复制耗时。

15.如何获取当前代码的函数名和行号

#function
#line
#file
#column

16.如何声明一个只能被类 conform 的 protocol

protocol:class

17.String 与 NSString 的关系与区别

两者可以随意转换

String为值类型,拷贝赋值需要值拷贝

NSString 传递指针

20.如何截取 String 的某段字符串

substring 已废弃

let star = str.index(str.startIndex, offsetBy: 0)

let end = str.index(str.startIndex, offsetBy: 4)

let substr = str[star..<end]

21.throws 和 rethrows 的用法与作用

当闭包参数会抛出异常时 使用throws

同时外部方法体返回结果需要  rethrows 异常

rethrows 可以用 throws 替换, 反过来不行

22.try? 和 try!是什么意思

不处理错误,抛出异常函数时, 如果函数抛出异常, 则返回 nil, 否则返回函数返回值的可选值,


保证不会出现错误 强制解,抛出异常的时候崩溃, 否则则返会函数返回值

23.associatedtype 的作用

关联类型,关联类型为协议中的某个类型提供了一个别名,其代表的真实类型在实现者中定义


//协议,使用关联类型
protocol TableViewCell {
    associatedtype T
    func updateCell(_ data: T)
}
 
//遵守TableViewCell
class MyTableViewCell: UITableViewCell, TableViewCell {
    typealias T = Model
    func updateCell(_ data: Model) {
        // do something ...
    }
}

24.public 和 open 的区别

是否可以继承

25.声明一个只有一个参数没有返回值闭包的别名

typealias MyBlock = (Int) -> (Void)

26.Self 的使用场景

例如:协议定义的时候,如果需要使用到实现者的上下文怎么办? 我们并不知道谁会实现自己

这个时候可以使用Self进行指代

27.dynamic 的作用

swift中的函数是静态调用,静态调用的方式会更快,但是静态调用的时候没救不能从字符串查找到对于的方法地址,这样 与OC交互的时候,OC动态查找方法就会找不到,这个时候就可以通过使用 dynamic 标记来告诉编译器,这个方法要被动态调用的

swift中如果KVO监听属性,那么属性就需要 dynamic 来标记

28.什么时候使用 @objc

与OC 的交互部分

KOV 监听、动态方法查找等都需要

协议可选方法等

29.Optional(可选型) 是用什么实现的

枚举 一个 为nil,一个为属性值

30.如何自定义下标获取

extension Demo {
   subscript(index: Int) -> Int {
      get {
        // 返回一个适当的 Int 类型的值
      }
      set(newValue) {
        // 执行适当的赋值操作
      }
    }
}

31.inout 的作用

让输入参数可变 类似__block 的作用

32.Error 如果要兼容 NSError 需要做什么操作

Error是一个协议, swift中的Error 都是enum, 可以转 NSError

如果需要Error有NSError的功能,实现 LocalizedError CustomNSError 协议

33.下面的代码都用了哪些语法糖

[1, 2, 3].map{ $0 * 2 }

array语法糖

尾部闭包语法糖

$0

34.什么是高阶函数

map、flatMap、filter、reduce?

35.下面的代码会不会崩溃,说出原因

var mutableArray = [1,2,3]
for _ in mutableArray {
    mutableArray.removeLast()
}

不会,值类型

36.给集合中元素是字符串的类型增加一个扩展方法,应该怎么声明

extension Array where Element == String { }

37.定义静态方法时关键字 static 和 class 有什么区别

非class类型 一般 统一用 static  例如  枚举 结构体

protocol中 使用 static ,实现协议的 枚举 结构体 用 static

class 中使用  class static 都可以

38.一个 Sequence 的索引是不是一定从 0 开始?


39.数组都实现了哪些协议

Decodable Encodable Equatable Hashable  CustomStringConvertible, CustomDebugStringConvertible RandomAccessCollection, MutableCollection RangeReplaceableCollection CustomReflectable ExpressibleByArrayLiteral

40.如何自定义模式匹配

infix operator =~

func =~ (str: String, pattern: String) -> Bool {
    
}

infix、  prefix、  postfix  用于自定义表达式的声明, 分别表示 中缀、前缀、后缀  

41.autoclosure 的作用

自动闭包,将参数自动封装为闭包参数

42.下面代码中 mutating 的作用是什么

struct Person {

    var name: String {
        mutating get {
            return store
        }
    }
}

结构体中的 属性可能发生改变

43.如何让自定义对象支持字面量初始化

ExpressibleByArrayLiteral


ExpressibleByStringLiteral

44.为什么数组索引越界会崩溃,而字典用下标取值时 key 没有对应值的话返回的是 nil 不会崩溃。

struct Array<Element> {
    subscript(index: Int) -> Element
}

struct Dictionary<Key: Hashable, Value> {
    subscript(key: Key) -> Value?
}

45.一个函数的参数类型只要是数字(Int、Float)都可以,要怎么表示。

Int、Float 都有一个协议

func myMethod<T>(_ value: T) where T: Numeric {
    print(value + 1)
} 

或者 ExpressibleByIntegerLiteral 协议也行

46.Swift的静态派发

很显然静态派发是一种更高效的方法,因为静态派发免去了查表操作。

不过静态派发是有条件的,方法内部的代码必须对编译器透明,并且在运行时不能被更改,这样编译器才能帮助我们。

Swift 中的值类型不能被继承,也就是说值类型的方法实现不能被修改或者被复写,因此值类型的方法满足静态派发的要求。

默认静态派发,如果需要满足动态派发,需要 dymanic修饰

47.Swift有哪些修饰符

open、public 、internal、fileprivate、private

48、实现一个函数,输入是任一整数,输出要返回输入的整数 + 2

func plusTwo(one: Int) -> (Int) -> Int {
    return { (two: Int) in return two + one }
}

plusTwo(one: 4)(2)

49、Swift 到底是面向对象还是函数式的编程语言?

Swift 既是面向对象的,又是函数式的编程语言。
说 Swift 是 Object-oriented,是因为 Swift 支持类的封装、继承、和多态,从这点上来看与 Java 这类纯面向对象的语言几乎毫无差别。
说 Swift 是函数式编程语言,是因为 Swift 支持 map, reduce, filter, flatmap 这类去除中间状态、数学函数式的方法,更加强调运算结果而不是中间过程。

持续更新