我有一个很奇怪的问题,当我根本不明白发生了什么事情时,所以我正在寻找它的解释。情况如下:当数据加载到后台线程时CoreData怪异的行为
我有一个视图控制器scrollview有三个子视图。这三个子视图有方法
-(void)loadContent
它加载在后台线程使用CoreData数据库的内容,创建代表加载的项目,并将其添加为自己的子视图调用子视图[自addSubview:ItemView控件]。该方法被调用为
[self performSelectorInBackground: @selector(loadContent) withObject: nil];
从数据库加载数据我使用的是单例服务类。一切正常,但当这三个视图加载他们的数据部分时,它有时会崩溃应用程序。
我猜测这是因为它为所有读取操作共享一个NSManagedObjectContext实例,所以我重写了该类,以便它只共享NSManagedObjectModel和NSPersistentStoreCoordinator实例并创建它自己的NSManagedObjectContext实例。
突然间,发生了一件非常奇怪的事情。数据加载正常,子视图被创建并添加到视图层次结构中,但从未显示在屏幕上。当我切换回旧的单例服务类(共享一个managedObjectContext)时,它再次像一个魅力一样工作! (但有可能导致应用崩溃)。
我绝对没有明白从数据库加载数据如何与在屏幕上显示项目相关。更多内容 - 当创建子视图并将其添加到视图层次结构中时,为什么它不显示?
来源是这样的:
- (void) loadContent {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSArray *results = [(WLDataService *)[WLDataService service] loadItemsForGDView];
NSUInteger channelPosition = 0;
CGFloat position = 0.0;
CGFloat minuteWidth = ((self.superview.frame.size.width/2.0)/60.0);
for(Item *it in results) {
/// On following lines size and position of the view is computed according to item setup - skipping here...
/// Create item; it's simple subclass of UIView class
WLGDItemView *item = [[WLGDItemView alloc] init];
/// Variables used here are declared above when size and position is computed
item.frame = CGRectMake(itemX, itemY, itemWidth, itemHeight);
[self performSelectorOnMainThread: @selector(addSubview:) withObject: item waitUntilDone: NO];
/// This is just helper macro to release things
WL_RELEASE_SAFELY(item);
}
[pool drain];
}
基本服务类(非单一个)实现如下(只是有趣的部分):
#import "WLLocalService.h"
static NSPersistentStoreCoordinator *sharedPSC = nil;
static NSManagedObjectModel *sharedMOM = nil;
@implementation WLLocalService
@synthesize managedObjectContext;
/// This is here for backward compatibility reasons
+ (WLLocalService *) service {
return [[[self alloc] init] autorelease];
}
#pragma mark -
#pragma mark Core Data stack
- (NSManagedObjectContext *) managedObjectContext {
if (managedObjectContext == nil) {
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
managedObjectContext = [[NSManagedObjectContext alloc] init];
[managedObjectContext setPersistentStoreCoordinator: coordinator];
}
[managedObjectContext setUndoManager: nil];
[managedObjectContext setMergePolicy: NSMergeByPropertyStoreTrumpMergePolicy];
}
return managedObjectContext;
}
- (NSManagedObjectModel *) managedObjectModel {
if(sharedMOM == nil) {
sharedMOM = [[NSManagedObjectModel mergedModelFromBundles: nil] retain];
}
return sharedMOM;
}
- (NSPersistentStoreCoordinator *) persistentStoreCoordinator {
if(sharedPSC == nil) {
NSURL *storeUrl = [self dataStorePath];
NSError *error = nil;
sharedPSC = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];
if (![sharedPSC addPersistentStoreWithType: NSSQLiteStoreType configuration: nil URL: storeUrl options: nil error: &error]) {
WLLOG(@"%@: %@", error, [error userInfo]);
}
}
return sharedPSC;
}
#pragma mark -
#pragma mark Path to data store file
- (NSURL *) dataStorePath {
return [NSURL fileURLWithPath: [WL_DOCUMENTS_DIR() stringByAppendingPathComponent: @"/DB.sqlite"]];
}
- (void)dealloc {
WL_RELEASE_SAFELY(managedObjectModel);
[super dealloc];
}
@end
我真的很想知道这里发生了什么,为什么它表现得如此奇怪(当然 - 为什么它不起作用,特别是)。有人可以解释吗?
感谢所有
是的,我读过那个被人掠过的时代。这就是为什么我试图修改我的单例类,使它不是单例,并为每个实例使用单独的托管对象上下文。我不在线程之间发送托管对象实例,我只是根据参数创建图形表示。而我很困惑为什么UIView对象没有被显示! – Matthes
您错过了“对于完全并发操作,您需要为每个线程使用不同的协调器”的部分。然后。你的非单例的行为就像一个单例,因为它具有全局变量来跟踪PSC和MOM的单例实例。由于您使用的是多个线程中的代码,因此可能存在并发问题。初始化它们时肯定会存在潜在的问题,因为您不会同步访问它们。 –
因此,我修改了我的服务类,因此每个实例都保留它自己的协调器实例和托管对象上下文,两个访问器方法都是同步的。但没有改变 - 视图的内容仍然不显示。我不知道如何可能以及从数据库加载数据和显示其他内容之间的关系是什么。哎呀! – Matthes