美文网首页
CS193笔记 第六讲 多重MVC,控制器的生命周期和内存管理

CS193笔记 第六讲 多重MVC,控制器的生命周期和内存管理

作者: 默默熊 | 来源:发表于2017-03-23 11:16 被阅读17次

    我开始用Markdown方式来记笔记了。现在第十一讲的视频都已经放出来了。为了提速,内容会记得比较简单,以记录核心内容为主,后面再逐步进行补充。对本讲有任何疑问,请留言,我会优先进行更新。

    <h4>本讲简介:</h4> 本讲通过演示来介绍,最后几分钟时间介绍了内存管理,主要是对引用类型对象的管理。

    演示:
    为FaceIt增加 Master-Detail View

    Navigation View

    View Controller 的生命周期

    Instantiated
    awakeFromNib
    segue preparation happens
    outlets get set
    viewDidLoad
    viewWillAppear
    viewWillLayoutSubviews
    viewDidLayoutSubviews
    viewWillDisappear

    内存管理
    简单来讲,内存管理是自动的或对开发者透明的。

    ARC vs MRC vs GC
    自动引用计数
    手动引用计数
    垃圾回收技术

    Strong Weak unOwned

    闭包 (Closures)

    Closures: 一等公民,是引用类型,居住在堆上
    <pre>addUnaryOperation("✅", operation: { (x: Double) -> Double in
    display.textColor = UIColor.green
    return sqrt(x)
    } )</pre>

    <pre>addUnaryOperation("✅") {
    self.display.textColor = UIColor.green
    return sqrt($0)
    } </pre>

    <pre>addUnaryOperation("✅") { [ unowned me = self ] in
    me.display.textColor = UIColor.green
    return sqrt($0)
    } </pre>

    这个例子有几个知识点:
    1,闭包做为最后一个参数的简化写法
    2,介绍了一种可能产生内存引用互锁的情况
    3,引入一个unowned 变量 打破循环

    更容易想到的打破循环引用的
    <pre>addUnaryOperation("✅") { [ weak weakSelf = self ] in
    weakSelf?.display.textColor = UIColor.green
    return sqrt($0)
    } </pre>

    但还可以这样写

    <pre>
    addUnaryOperation("✅") { [ weak self ] in
    self?.display.textColor = UIColor.green
    return sqrt($0)
    }
    </pre>

    第十三讲结尾介绍了一个需要避免memory cycle 的情况

    @escaping 用于修饰闭包。闭包默认是非逃逸的。@escaping修饰表示逃逸,即闭包的执行会产生对闭包外部的访问,或某种形式上的副效果。在Swift 3以前,闭包默认是逃逸的, 非逃逸闭包要用@noescaping修饰。

    <h4>再谈!</h4>
    上一讲里面提到过,因为在声明faceView时使用了!,在使用它时是不需要加?的。但在本讲中,如果在下面访问faceView时不加?,应用会出错。

    <pre>
    //FaceViewController.swift
    @IBOutlet weak var faceView: FaceView!

    private func updateUI() {
        switch  expression.eyes {
        case .open:
            faceView?.eyesOpen = true
        case .closed:
            faceView?.eyesOpen = false
        case .squinting:
           faceView?.eyesOpen = false
        }
        faceView?.mouthCurvature = mouthCurvature[expression.mouth] ?? 0.0
    }</ol>
    

    </pre>

    原因在于,Segue总会建立新的MVC实例。而在 prepare(for segue) 中<code> faceViewController.expression = expression </code>引发了对上面的updateUI()的调用,而此时faceView还没有被建立,仍然为nil。所以需要加?。这说明使用!后,只是对编译器来说可以接受没有unwrapping。但像本例的情况仍然需要。

    <pre>
    <ol> //EmotionsViewController.swift
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    let destinationViewController = segue.destination
    if let faceViewController = destinationViewController as? FaceViewController,
    let identifier = segue.identifier,
    let expression = emotionalFaces[identifier] {
    faceViewController.expression = expression
    }
    }<ol>
    </pre>

    <h4>课后练习</h4>
    <p>在增加了navigation Controller 后,应用启动后直接显示了 Face View。老师留了一个练习,是希望启动后显示带有三个按钮的emotion 选择页面。老师还给了个提示,要用到后面讲的delegate的内容。在这儿我们自己实现一下。</p>
    <ol><li>打开帮助文档,在输入框敲入 Navig,这时提示列表就回显示出一些推荐的结果,选取 navigationController(_:willShow:animated:)
    <li>根据帮助内容我们确定这个方法会在每一页显示前被调用。而且从帮助页面的顶部我们可以知道这个方法属于协议 UINavigationControllerDelegate
    <li>创建一个新的 Cocoa Touch Class 文件,将其命名为EmotionsNavViewController,父类先不用动,后面再改。
    <li>打开Main.storyboard, 选中Navigation Controller 查看 identity inspector 中的 class 为 UINavigationController。因而我们打开新建的文件,将
    <pre><code>class EmotionsNavViewController: ... { </code></pre> 替换为
    <pre><code>class EmotionsNavViewController: UINavigationController, UINavigationControllerDelegate {</code></pre>回到 identity inspector 中将Navigation Controller 的 class 的值改为 EmotionsNavViewController
    <li>在类中添加我们在第1步找到的方法
    <pre> func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
    }</pre><li>在这儿我们该怎么做呢?查看UINavigationController的帮助
    “A navigation controller coordinates its behavior with its delegate object. The delegate object can override the pushing or popping of a view controller ... "
    我们看到了 override,所以有戏。我们在willShow 方法中加入
    <pre><code>popViewController(animated: true)</code></pre>运行一下,没有效果。在新加的代码上设一个断点,会发现根本没有被调用。
    <li>在viewDidLoad()里面加入
    <pre><code>delegate = self</code></pre>再次执行程序,成功地显示了我们想要的页面。
    <li>点一下 sad 按钮,oops! FaceView 出现后又收回了。看来willShow中的代码还在起作用。增加一个属性
    <pre>private var displayed = false</pre>然后将 willShow的内容改为
    <pre>if displayed == false {
    displayed = true
    popViewController(animated: true)
    }</pre> command+R 运行程序。一切OK。</ol>

    官方答案在第八讲。

    相关文章

      网友评论

          本文标题:CS193笔记 第六讲 多重MVC,控制器的生命周期和内存管理

          本文链接:https://www.haomeiwen.com/subject/hunwnttx.html