2013-03-05 110 views
0

我們得到的錯誤是這樣的:奇怪的Xcode 4.6相關的錯誤

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[_CDSnapshot_Widget_ unlockObjectStore]: unrecognized selector sent to instance 0x1c5a4350' 

有時Widget類被髮送的選擇,有時是__NSCFString,有時死機是這樣的:

[NSManagedObjectContext unlockObjectStore]: message sent to deallocated instance 0x1ec658c0 

我想我已經縮小了發生問題的位置,但我不知道爲什麼這個代碼會導致它。 這是我們的數據訪問類的典型結構:

// DataController.m 
static NSPersistentStoreCoordinator  *_persistentStoreCoordinator; 
static NSManagedObjectModel    *_managedObjectModel; 
static NSManagedObjectContext   *_mainManagedObjectContext; 

@implementation DataController 
- (NSManagedObjectContext *) privateManagedObjectContext { 
    return [DataController buildManagedObjectContextForConcurrencyType:NSPrivateQueueConcurrencyType]; 
} 

- (NSManagedObjectContext *) defaultManagedObjectContext { 
    return [self managedObjectContextForConcurrencyType: self.defaultConcurrencyType]; 
} 

- (NSManagedObjectContext *) managedObjectContextForConcurrencyType: (NSManagedObjectContextConcurrencyType) type { 
    if (type == NSMainQueueConcurrencyType) 
     return [self mainManagedObjectContext]; 
    else if (type == NSPrivateQueueConcurrencyType) 
     return [self privateManagedObjectContext]; 

    return nil; 
} 

// calling _dataController.defaultManagedObjectContext from within the Widgets class 
// essentially calls this method for a new context using NSPrivateQueueConcurrencyType as 
// the type parameter 
+ (NSManagedObjectContext *) buildManagedObjectContextForConcurrencyType: (NSManagedObjectContextConcurrencyType) type { 
    NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType: type]; 
    [context setUndoManager: nil]; 
    [context setMergePolicy: NSMergeByPropertyObjectTrumpMergePolicy]; 
    [context setPersistentStoreCoordinator: _persistentStoreCoordinator]; 
    return context; 
} 

@end 

,我們的小部件類

// Widgets.m 
static DataController *_dataController; 

@implementation Widgets 
+ (void) initialize { 
    _dataController = [[DataController alloc] init]; 
} 

+ (NSArray *)certainWidgets { 
    return [self certainWidgetsInManagedObjectContext:_dataController.defaultManagedObjectContext]; 
} 

+ (NSArray *) certainWidgetsInManagedObjectContext: (NSManagedObjectContext *) context { 
    // boiler plate CoreData fetching code 
} 
@end 

這是用來取得部件

dispatch_async(dispatch_get_global_queue(0, 0), ^{ 
    for (Widget *w in [Widgets certainWidgets]) { 
     if ([w.isValid intValue]) { 
      // do something extraoridarily fantastic with the widget 
     } 
    } 
}); 

這只是發生的代碼示例在Xcode 4.6中,釋放模式(不在Debug中)。我們沒有看到Xcode 4.6發行說明中的​​任何內容,它們會給我們提供有關正在發生的事情的線索。

我懷疑這個問題與我們如何構建數據訪問類(DataController)以及我們使用類方法處理Widgets類中的所有數據訪問有關。我懷疑的原因是,當我們從Widgets類中移除類方法並改爲使用實例方法時,擺脫了+ initialize方法,併爲Widgets類的每個實例設置了一個NSManagedObjectContext,問題似乎就此消失遠。

只是爲了澄清,我認爲我已經解決了這個問題,但我不太願意推出修復程序,直到我明白爲什麼上述修改能夠修復它。看起來好像存在着某種內存問題或者糟糕的編程範例,我們沒有注意到。任何指針?

回答

0

原來,這是一個與CLang優化相關的錯誤。我們發現一些其他人遇到同樣的問題。關閉所有優化似乎解決了這個問題。

對於我們來說,創建一個靜態數據管理實例,產生一個新線程,並使用該靜態實例創建一個託管對象上下文時,情況就會發生。

我們的修補程序將重新考慮我們的數據管理範例。

-1

如果您在此應用上使用此屏幕,或者第二次出現&崩潰,請檢查您在此屏幕上的內存管理。可能是這種情況,當你在內存中保存好幾個屏幕副本。例如,檢查通知中心刪除觀察者。