非常不寻常的Xcode编译行为 [英] Very unusual Xcode compile behaviour

查看:101
本文介绍了非常不寻常的Xcode编译行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

自从Xcode 6.1和iOS 8.1发布以来,我的一个应用程序停止运行。
只有在我的设备上使用Release而不是Debug的方案进行RUN,我才设法重现问题。

Since the release of Xcode 6.1 and iOS 8.1, one of my apps stopped functioning. I managed to reproduce the problem only if I did "RUN" on my device with a scheme of "Release" instead of "Debug".

现在问题。在调试模式下可以正常工作:

Now for the problem. This works fine in Debug mode:

import Foundation

class CategoryParser {


    var categoriesSettingsDictionary : [String: AnyObject]?


    init() {
        let categoriesURL = NSBundle.mainBundle().URLForResource("CategoriesSettings", withExtension: "plist")
        categoriesSettingsDictionary = NSDictionary(contentsOfURL: categoriesURL!) as? Dictionary<String, AnyObject>
    }
}

但是当我实例化时,它在发布模式中崩溃CategoryParser类型的对象。经过许多尝试和错误,我认为为了阻止这个问题,我可以将字典初始化放在两个println()语句之间。为什么会有区别?

But it crashes in "Release" mode when I instantiate an Object of the CategoryParser type. After many trials and errors, I figured that to stop it from doing the problem I could place the dictionary initialisation between two println() statements. Why would those make any difference?

import Foundation

class CategoryParser {


    var categoriesSettingsDictionary : [String: AnyObject]?


    init() {
        let categoriesURL = NSBundle.mainBundle().URLForResource("CategoriesSettings", withExtension: "plist")
        println("_")
        categoriesSettingsDictionary = NSDictionary(contentsOfURL: categoriesURL!) as? Dictionary<String, AnyObject>
        println("_")
    }
}


推荐答案

它必须是Swift编译器中的优化问题。我想,它是围绕 NSDictionary 字典< String,AnyObject>

It must be a bug around optimizations in Swift compiler. I think, it's around bridging NSDictionary to Dictionary<String,AnyObject>.

我用以下设置重现了这个问题。

I reproduced the problem with following setup.

环境:Xcode 6.1(6A1052d)/ iPhone 6 / iOS 8.1

Environment: Xcode 6.1 (6A1052d) / iPhone 6 / iOS 8.1

模板:单一查看应用程序

Template: Single View Application

CategoriesSettings.plist:

CategoriesSettings.plist:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>ct1</key>
    <string>test</string>
</dict>
</plist>

AppDelegate.swift

AppDelegate.swift

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        let result = loadPlist()
        println("result: \(result)")
        return true
    }

    func loadPlist() -> [String: AnyObject]? {
        let categoriesURL = NSBundle.mainBundle().URLForResource("CategoriesSettings", withExtension: "plist")
        let dict = NSDictionary(contentsOfURL: categoriesURL!)
        println(dict)
        let result = dict as? [String:AnyObject]
        return result
    }
}

// EOF

输出(含 -O ):

Optional({
    ct1 = test;
})
result: nil

输出(含 -Onone ):

Optional({
    ct1 = test;
})
result: Optional(["ct1": test])






虽然我不知道最好的解决方法。


I don't know the best workaround, though.

也许这个工程:

class CategoryParser {
    var categoriesSettingsDictionary : [String: AnyObject]?
    init() {
        let categoriesURL = NSBundle.mainBundle().URLForResource("CategoriesSettings", withExtension: "plist")
        categoriesSettingsDictionary = NSDictionary(contentsOfURL: categoriesURL!) as? Dictionary<String, AnyObject>
        if categoriesSettingsDictionary == nil {
            // NOTICE: to other developers about this workaround
            println("_")
            println("_")
        }
    }
}

将它们封装在 autoreleasepool 也可以:

Encapsulating them in autoreleasepool also works:

class CategoryParser {
    var categoriesSettingsDictionary : [String: AnyObject]?

    init() {
        autoreleasepool {
            let categoriesURL = NSBundle.mainBundle().URLForResource("CategoriesSettings", withExtension: "plist")
            self.categoriesSettingsDictionary = NSDictionary(contentsOfURL: categoriesURL!) as? Dictionary<String, AnyObject>
        }
    }
}

但是,截至目前,我想,你应该使用 NSDictionary ,因为只要你只读它,在 NSDictionary Dictionary< String,AnyObject>

But, as of now, I think, you should use NSDictionary as is, because as long as you only read from it, there is almost no practical difference between NSDictionary and Dictionary<String,AnyObject> in most cases.

class CategoryParser {
    var categoriesSettingsDictionary : NSDictionary?
    init() {
        let categoriesURL = NSBundle.mainBundle().URLForResource("CategoriesSettings", withExtension: "plist")
        categoriesSettingsDictionary = NSDictionary(contentsOfURL: categoriesURL!)
    }
}

或者,这可能太过分了,但是你可以实现自己的 NSDictionary 字典转换器。

OR, this may be too aggressive, but you can implement your own NSDictionaryDictionary converter.

extension Dictionary {
    init?(nsDictionaryOrNil:NSDictionary?) {
        if let dict = nsDictionaryOrNil? {
            self = [Key:Value](minimumCapacity: dict.count)
            for (k,v) in dict {
                if let key = k as? Key {
                    if let val = v as? Value {
                        self[key] = val
                        continue
                    }
                }
                return nil
            }
        }
        else {
            return nil
        }
    }
}

class CategoryParser {
    var categoriesSettingsDictionary : [String:AnyObject]?
    init() {
        let categoriesURL = NSBundle.mainBundle().URLForResource("CategoriesSettings", withExtension: "plist")
        let dict = NSDictionary(contentsOfURL: categoriesURL!)
        categoriesSettingsDictionary = [String:AnyObject](nsDictionaryOrNil: dict)
    }
}

这篇关于非常不寻常的Xcode编译行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆