问题描述
自从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
NSDictionary
→ Dictionary
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编译行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!