答《卓同学的 Swift 面试题》下

原文链接 卓同学的 Swift 面试题
上篇回答 http://www.jianshu.com/p/23d99f434281

dynamic 的作用

由于 swift 是一个静态语言, 所以没有 Objective-C 中的消息发送这些动态机制, dynamic 的作用就是让 swift 代码也能有 Objective-C 中的动态机制, 常用的地方就是 KVO 了, 如果要监控一个属性, 则必须要标记为 dynamic, 可以参考我的文章http://www.jianshu.com/p/ae26100b9edf

什么时候使用 @objc

@objc 用途是为了在 Objective-C 和 Swift 混编的时候, 能够正常调用 Swift 代码. 可以用于修饰类, 协议, 方法, 属性.
常用的地方是在定义 delegate 协议中, 会将协议中的部分方法声明为可选方法, 需要用到@objc

@objc protocol OptionalProtocol {
    @objc optional func optionalFunc()
    func normalFunc()
}
class OptionProtocolClass: OptionalProtocol {
    func normalFunc() {
    }
}
let someOptionalDelegate: OptionalProtocol = OptionProtocolClass()
someOptionalDelegate.optionalFunc?()

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

Optional 是一个泛型枚举
大致定义如下:

enum Optional<Wrapped> {
  case none
  case some(Wrapped)
}

除了使用 let someValue: Int? = nil 之外, 还可以使用let optional1: Optional<Int> = nil 来定义

如何自定义下标获取

实现 subscript 即可, 如

extension AnyList {
    subscript(index: Int) -> T{
        return self.list[index]
    }
    subscript(indexString: String) -> T?{
        guard let index = Int(indexString) else {
            return nil
        }
        return self.list[index]
    }
}

索引除了数字之外, 其他类型也是可以的

?? 的作用

可选值的默认值, 当可选值为nil 的时候, 会返回后面的值. 如
let someValue = optional1 ?? 0

lazy 的作用

懒加载, 当属性要使用的时候, 才去完成初始化

class LazyClass {
    lazy var someLazyValue: Int = {
        print("lazy init value")
        return 1
    }()
    var someNormalValue: Int = {
        print("normal init value")
        return 2
    }()
}
let lazyInstance = LazyClass()
print(lazyInstance.someNormalValue)
print(lazyInstance.someLazyValue)
// 打印输出
// normal init value
// 2
// lazy init value
// 1

一个类型表示选项,可以同时表示有几个选项选中(类似 UIViewAnimationOptions ),用什么类型表示

需要实现自 OptionSet, 一般使用 struct 实现. 由于 OptionSet 要求有一个不可失败的init(rawValue:) 构造器, 而 枚举无法做到这一点(枚举的原始值构造器是可失败的, 而且有些组合值, 是没办法用一个枚举值表示的)

struct SomeOption: OptionSet {
    let rawValue: Int
    static let option1 = SomeOption(rawValue: 1 << 0)
    static let option2 =  SomeOption(rawValue:1 << 1)
    static let option3 =  SomeOption(rawValue:1 << 2)
}
let options: SomeOption = [.option1, .option2]

inout 的作用

输入输出参数, 如:

func swap( a: inout Int, b: inout Int) {
    let temp = a
    a = b
    b = temp
}
var a = 1
var b = 2
print(a, b)// 1 2
swap(a: &a, b: &b)
print(a, b)// 2 1

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

其实直接转换就可以, 例如 SomeError.someError as NSError 但是这样没有错误码, 描述等等, 如果想和 NSError 一样有这些东西, 只需要实现 LocalizedErrorCustomNSError 协议, 有些方法有默认实现, 可以略过, 如:

enum SomeError: Error, LocalizedError, CustomNSError {
    case error1, error2
    public var errorDescription: String? {
        switch self {
        case .error1:
            return "error description error1"
        case .error2:
            return "error description error2"
        }
    }
    var errorCode: Int {
        switch self {
        case .error1:
            return 1
        case .error2:
            return 2
        }
    }
    public static var errorDomain: String {
        return "error domain SomeError"
    }
    public var errorUserInfo: [String : Any] {
        switch self {
        case .error1:
            return ["info": "error1"]
        case .error2:
            return ["info": "error2"]
        }
    }
}
print(SomeError.error1 as NSError)
// Error Domain=error domain SomeError Code=1 "error description error1" UserInfo={info=error1}

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

[1, 2, 3].map{ $0 * 2 }
[1, 2, 3] 使用了, Array 实现的ExpressibleByArrayLiteral 协议, 用于接收数组的字面值
map{xxx} 使用了闭包作为作为最后一个参数时, 可以直接写在调用后面, 而且, 如果是唯一参数的话, 圆括号也可以省略
闭包没有声明函数参数, 返回值类型, 数量, 依靠的是闭包类型的自动推断
闭包中语句只有一句时, 自动将这一句的结果作为返回值
$0 在没有声明参数列表的时候, 第一个参数名称为$0, 后续参数以此类推

什么是高阶函数

一个函数如果可以以某一个函数作为参数, 或者是返回值, 那么这个函数就称之为高阶函数, 如 map, reduce, filter

如何解决引用循环

  1. 转换为值类型, 只有类会存在引用循环, 所以如果能不用类, 是可以解引用循环的,
  2. delegate 使用 weak 属性.
  3. 闭包中, 对有可能发生循环引用的对象, 使用 weak 或者 unowned, 修饰

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

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

不会, 原理不清楚, 就算是把 removeLast(), 换成 removeAll() ,这个循环也会执行三次, 估计是在一开始, for
in 就对 mutableArray 进行了一次值捕获, 而 Array 是一个值类型 , removeLast() 并不能修改捕获的值.

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

使用 where 子句, 限制 Element 为 String

extension Array where Element == String {
    var isStringElement:Bool {
        return true
    }
}
["1", "2"].isStringElement
//[1, 2].isStringElement// error

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

static 定义的方法不可以被子类继承, class 则可以

class AnotherClass {
    static func staticMethod(){}
    class func classMethod(){}
}
class ChildOfAnotherClass: AnotherClass {
    override class func classMethod(){}
    //override static func staticMethod(){}// error
}

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

不一定, 两个 for in 并不能保证都是从 0 开始, 且输出结果一致, 官方文档如下

Repeated Access

The Sequence protocol makes no requirement on conforming types regarding
whether they will be destructively consumed by iteration. As a
consequence, don't assume that multiple for-in loops on a sequence
will either resume iteration or restart from the beginning:

for element in sequence {
    if ... some condition { break }
}

for element in sequence {
    // No defined behavior
}

有些同学还是不太理解, 我写了一个demo 当作参考

class Countdown: Sequence, IteratorProtocol {
    var count: Int
    init(count: Int) {
        self.count = count
    }
    func next() -> Int? {
       if count == 0 {
           return nil
       } else {
           defer { count -= 1 }
           return count
       }
   }
}

var countDown = Countdown(count: 5)
print("begin for in 1")
for c in countDown {
    print(c)
}
print("end for in 1")
print("begin for in 2")
for c in countDown {
    print(c)
}
print("end for in 2")

最后输出的结果是

begin for in 1
5
4
3
2
1
end for in 1
begin for in 2
end for in 2

很明显, 第二次没有输出任何结果, 原因就是在第二次for in 的时候, 并没有将count 重置.

数组都实现了哪些协议

MutableCollection, 实现了可修改的数组, 如 a[1] = 2
ExpressibleByArrayLiteral, 实现了数组可以从[1, 2, 3] 这种字面值初始化的能力
...

如何自定义模式匹配

这部分不太懂, 贴个链接吧
http://swifter.tips/pattern-match/

autoclosure 的作用

自动闭包, 会自动将某一个表达式封装为闭包. 如

func autoClosureFunction(_ closure: @autoclosure () -> Int) {
   closure()
}
autoClosureFunction(1)

详细可参考http://swifter.tips/autoclosure/

编译选项 whole module optmization 优化了什么

编译器可以跨文件优化编译代码, 不局限于一个文件.
http://www.jianshu.com/p/8dbf2bb05a1c

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

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

让不可变对象无法访问 name 属性

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

有几个协议, 分别是
ExpressibleByArrayLiteral 可以由数组形式初始化
ExpressibleByDictionaryLiteral 可以由字典形式初始化
ExpressibleByNilLiteral 可以由nil 值初始化
ExpressibleByIntegerLiteral 可以由整数值初始化
ExpressibleByFloatLiteral 可以由浮点数初始化
ExpressibleByBooleanLiteral 可以由布尔值初始化
ExpressibleByUnicodeScalarLiteral
ExpressibleByExtendedGraphemeClusterLiteral
ExpressibleByStringLiteral
这三种都是由字符串初始化, 上面两种包含有 Unicode 字符和特殊字符

dynamic framework 和 static framework 的区别是什么

静态库和动态库, 静态库是每一个程序单独打包一份, 而动态库则是多个程序之间共享

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容