在发布版本配置

时间:2016-11-27 23:28:03

标签: ios swift

是编译器错误,还是有人知道代码可能出错? 此单一视图应用程序模板的新项目代码。 要使应用程序崩溃,您可以将AppDelegate.swift中的默认代码替换为以下代码:

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow? = UIWindow(frame: UIScreen.main.bounds)

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        window?.rootViewController = UINavigationController(rootViewController: CrashController())
        window?.makeKeyAndVisible()
        return true
    }
}

//======================================================================================================================

class CrashController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = UIColor.white
        navigationItem.title = "Optimisation is not always Good"

        let button = UIButton(type: .system)
        button.setTitle("Crash the App Under Release", for: .normal)
        button.frame = CGRect(x: 20, y: 200, width: 300, height: 50)
        button.addTarget(self, action: #selector(onCrashButton), for: .touchUpInside)
        view.addSubview(button)
    }

    @IBAction func onCrashButton(_ sender: UIButton) {

        let goodItem = SomeItem(text: "1") // This Item will BE stored properly
        let badItem = SomeItem(textWithCrash: "2") // This Item will NOT be stored properly

        DispatchQueue.main.async() {
            print(goodItem.text)
            print(badItem.text) // EXC_BAD_ACCESS under Release
        }

        print(goodItem.text)
        print(badItem.text)
    }
}

//======================================================================================================================

class SomeItem {
    var text = ""

    deinit {
        print("deinit \(self.text)")
    }

    // required initializer
    required init(textWithoutCrash: String) {
        self.text = textWithoutCrash
        print("required init \(self.text)")
    }

    // designated initializer
    init(text: String) {
        self.text = text
        print("designated init \(self.text)")
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // DANGEROUS convenience initializer !!! App will BE crashed under Release Build Configeration
    //
    // calling required initializer inside convenience initializer is DANGEROUS under release with optimization:
    // ENABLE_TESTABILITY = NO
    // SWIFT_OPTIMIZATION_LEVEL = -Owholemodule
    //
    // There is NO crash Under Debug Build Configeration without optimisation:
    // ENABLE_TESTABILITY = YES
    // SWIFT_OPTIMIZATION_LEVEL = -Onone
    //
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    convenience init(textWithCrash: String) {

        // App will NOT be crashed calling designated initializer
//        self.init(text: textWithCrash)

        // App will be CRASHED later due to calling required initializer inside convenience initializer
        self.init(textWithoutCrash: textWithCrash)
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Optimisation causes crash ONLY if
// - the class has convenience init
// - the required initializer is calling inside the convenience init
// - the class has any children, (anyone inherits from the class) even if children does not use at all
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

class SomeChildItem: SomeItem {
//    // implementing required initializer does not help - App will be crashed anyway
//    required init(textWithoutCrash: String) {
//        super.init(textWithoutCrash: textWithoutCrash)
//    }
//
//    // overriding designated initializer does not help - App will be crashed anyway
//    override init(text: String) {
//        super.init(text: text)
//    }
//
//    // implementing convenience initializer does not help - App will be crashed anyway
//    convenience init(textWithCrash: String) {
//        self.init(textWithoutCrash: textWithCrash)
//    }
}

Debug下没有崩溃,但只有在菜单栏中选择Build configuration Release时才会发生崩溃:Product - &gt;方案 - &gt;编辑方案或只需按下Cmd-Shift-<热键。或者在生产版本中,如果您创建存档。

我发现该应用程序在发布时默认设置崩溃了

  • ENABLE_TESTABILITY = NO
  • SWIFT_OPTIMIZATION_LEVEL = -Owholemodule

应用程序未在Debug:

下使用默认设置崩溃
  • ENABLE_TESTABILITY = YES
  • SWIFT_OPTIMIZATION_LEVEL = -Onone

崩溃的一些条件:

  • 班级有方便的初始化;
  • 所需的初始化程序在Conven init内部调用;
  • 班上有孩子甚至空着没用过的孩子;

我没有在Apple文档中找到从便捷初始化程序调用所需初始化程序的任何禁忌。此外,Apple的文档&#34; The Swift Programming Language(Swift 3.0.1)&#34;有短语&#34;当覆盖所需的指定初始化程序时,你不会写覆盖修饰符&#34;这意味着还需要指定。因此,可以从便利性中调用它。 我使用Xcode版本8.1(8B62)和Swift 3.0.1。 有什么想法吗?

UPDATE1: 不带DispatchQueue.main.async的onCrashButton版本,所以如果你访问下一个runloop中的坏项,它将是BAD_ACCESS并崩溃。

var someItems = [SomeItem]()

@IBAction func onCrashButton(_ sender: UIButton) {
    print("someItems: \(someItems.count)")

    if let someItem = someItems.last {
        // Any Access to someItem is BAD_ACCESS and crashes the App. Why?
        let text = someItem.text
        print("text: \(text)")
    }

    // This Item will BE stored properly.
    someItems += [SomeItem(text: "Some text \(someItems.count)")]

    // This Item will NOT be stored into array properly. Why?
    someItems += [SomeItem(textWithCrash: "Some text \(someItems.count)")]
}

0 个答案:

没有答案