xcode - 仅在存档的 Cocoa 应用程序中内存访问崩溃(EXC_BAD_ACCESS/EXC_I386_GPFLT)

标签 xcode cocoa swift crash

我为 OS X 创建了第一个 Cocoa 应用程序,并很高兴最终将其提交到 iTunes connect。只是因为应用程序崩溃而未获得批准。我很难弄清楚所有事情,直到这里,现在我终于陷入困境,不知道如何解决以下问题:

首先,该应用程序在简单构建和运行时工作得非常好。仅当应用程序存档时才会发生神秘的崩溃。这就是为什么我之前没有注意到现金并将无法运行的应用程序提交到 iTunes Connect 的原因。

我符号化了崩溃日志,应用程序崩溃了(对我来说)没有任何意义。这是相关的(剥离的)代码。

我有一个类Countries,它除了从核心数据(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() 返回实体的所有项目。

现在我有一个模态窗口(beginSheet,我通过以下 this tutorial 实现),它包含一个 NSPopUpButton 并且我正在填充所有 Country 元素添加到此 PopUp:

//
//  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 connect 时,才会发生这种情况。简单构建和运行时零问题。

我很想简单地将 NSLog 留在那里并以这种方式发送,但我想了解发生了什么以及如何适本地解决它。

编辑: 刚刚安装了更新 Xcode 6.2,并且遇到了与 6.1.1 相同的问题。

最佳答案

我尝试了调试发布之间不同的所有build设置。看起来这是一个 Swift 编译器问题。当我将优化级别最快更改为时,问题就消失了。 FastestFastest, Unchecked 都会产生上述错误。 没有有效。

enter image description here

现在我已经确定了问题,我可以搜索并找到更好的解决方法。这个问题在某种程度上与一般的数组有关,我在网上发现了一些关于它的提及。一个简单的解决方法是将数组元素转换为 AnyObject,如下所示:

for country in countryList as [AnyObject] as [Country] {
   //...
}

而不是

for country in countryList as [Country] {
   //...
}

在另一个问题中找到了这个:Swift optimization level breaks converting NSArray to Array

关于xcode - 仅在存档的 Cocoa 应用程序中内存访问崩溃(EXC_BAD_ACCESS/EXC_I386_GPFLT),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29003323/

相关文章:

objective-c - 从 Swift 类获取值到 Objective-C 类

ios - 将图像添加到选项卡栏项目仅显示为 block

c - 需要帮助创建测验应用程序 - 如何放置图像?? Xcode(苹果手机)

objective-c - 如何将对象附加到 NSMutableArray?

cocoa - 我应该如何使用帮助 : URL in a Snow Leopard . 帮助包?

ios - 是否有 API 可以从 iOS 应用程序的文档文件夹中复制文件?

ios - 在 iOS 中,如果固定的 SSL 证书过期,我是否需要重新提交应用程序?

swift - Apollo iOS 代码生成 : Nested use of a fragment in a mutation creates unexpected property types in Fragments struct

iphone - 是否可以执行SegueWithIdentifier 并使发件人成为不同的 View Controller

ios - UISplitView 的 MasterViewController 和导航问题