【问题标题】:Memory Access Crash ONLY in Archived Cocoa Application (EXC_BAD_ACCESS/EXC_I386_GPFLT)仅存档 Cocoa 应用程序中的内存访问崩溃 (EXC_BAD_ACCESS/EXC_I386_GPFLT)
【发布时间】: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() 返回一个实体的所有项目。

现在我有一个模态窗口(@98​​7654327@,我通过关注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 有同样的问题。

【问题讨论】:

    标签: xcode cocoa swift crash


    【解决方案1】:

    我尝试了DebugRelease 之间不同的所有构建设置。看起来这是一个 Swift 编译器问题。当我将Optimization LevelFastest 更改为None 时,问题就消失了。 FastestFastest, Unchecked 都产生上述错误。 None 有效。

    现在我已经确定了问题,我能够搜索并找到更好的解决方法。这个问题通常与数组有关,我在网上发现了几次提到它。一个简单的解决方法是将数组元素转换为AnyObject,如下所示:

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

    而不是

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

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

    【讨论】:

    • 我遇到了同样的问题。这让我很头疼。感谢一百万!
    猜你喜欢
    • 2017-01-27
    • 1970-01-01
    • 1970-01-01
    • 2012-07-01
    • 1970-01-01
    • 2023-03-26
    • 1970-01-01
    • 2018-04-04
    • 1970-01-01
    相关资源
    最近更新 更多