【发布时间】:2015-03-12 06:37:50
【问题描述】:
我为 OS X 创建了我的第一个 Cocoa 应用程序,并且很高兴最终将它提交到 iTunes connect。只是因为应用程序崩溃而没有获得批准。直到现在我都很难弄清楚所有事情,现在我终于卡住了,不知道如何解决以下问题:
首先,应用程序在简单构建和运行时运行良好。神秘的崩溃只会在应用程序存档时发生。这就是为什么我之前没有注意到现金并将不工作的应用程序提交给 iTunes Connect。
我对崩溃日志进行了符号化,应用程序在一个没有任何意义的地方崩溃(对我来说)。这是相关的(剥离的)代码。
我有一个 Countries 类,它除了从 Core Data (SQLite) 中加载一组项目外,并没有做更多的事情:
//
// Countries.swift
//
import Cocoa
let appCountries = Countries()
class Countries {
lazy var items: [Country] = {
if let list = self.load() {
return list
}
else {
return []
}
}()
func load() -> [Country]? {
if let countryList = coreDataHelper.fetchEntitiesForClass("Country") as? [Country] {
return countryList
}
else {
return nil
}
}
}
Country 是我的数据模型的一个实体。 coreDataHelper 类仅包含用于创建数据存储、托管对象上下文和获取实体的所有相关方法。该代码不相关,在同一个应用程序的许多其他用例中肯定可以工作。假设coreDataHelper.fetchEntitiesForClass() 返回一个实体的所有项目。
现在我有一个模态窗口(@987654327@,我通过关注this tutorial 实现了它),其中包含一个NSPopUpButton,我正在将所有Country 元素填充到此弹出窗口:
//
// ModalWindow.swift
//
import Cocoa
class ModalWindow: NSWindowController {
var mainW: NSWindow = NSWindow()
let locale = NSLocale.currentLocale()
@IBOutlet weak var countries: NSPopUpButton!
override init() {
super.init()
}
override init(window: NSWindow!) {
super.init(window: window)
//Initialization code here.
}
required init?(coder: (NSCoder!)){
super.init(coder: coder);
}
override func windowDidLoad() {
super.windowDidLoad()
// Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
}
//method called to display the modal window
func beginSheet(mainWindow: NSWindow){
self.mainW = mainWindow
NSApp.beginSheet(self.window!, modalForWindow: mainWindow, modalDelegate: self, didEndSelector:nil, contextInfo: nil)
if let countryList = appCountries.items as NSArray? {
for country in countryList as [Country] {
if let localized = self.locale.displayNameForKey(NSLocaleCountryCode, value: country.name) {
self.countries!.addItemWithTitle(localized)
}
}
}
}
//method called to slide out the modal window
func endSheet(){
NSApp.endSheet(self.window!)
self.window!.orderOut(mainW)
}
}
符号化的崩溃日志告诉我,崩溃确实发生在我循环 countryList 的那一行:
for country in countryList as [Country] {
崩溃日志摘录:
Crashed Thread: 0 Dispatch queue: com.apple.main-thread
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: EXC_I386_GPFLT
Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0 libobjc.A.dylib 0x00007fff8b863064 objc_retain + 20
__TFC8MyApp18Modalwindow13windowDidLoadfS0_FT_T_ ModalWindow.swift:35
2 com.apple.AppKit 0x00007fff95dcee07 -[NSWindowController _windowDidLoad] + 586
据我了解,这是一个内存访问问题。但我不明白为什么。问题是,当我 NSLog countryList 它开始工作时:
if let countryList = appCountries.items as NSArray? {
NSLog("[TEST] %@", countryList)
for country in countryList as [Country] {
//...
}
}
我尝试以其他方式与countryList 进行交互,但是存档时其他所有内容都会导致崩溃,除非我首先将NSLog 与上面完全一样。即使这样也会崩溃:NSLog("[TEST] %@", "\(countryList)"),尽管根据我的理解它应该是完全相同的。同样,这仅在应用程序被归档以准备将其发送到 iTunes 连接时发生。只需构建和运行即可实现零问题。
我很想简单地将NSLog 留在那里并以这种方式发送,但我想了解发生了什么以及如何适当地解决它。
编辑: 刚刚安装了更新 Xcode 6.2 和 6.1.1 有同样的问题。
【问题讨论】: