Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Iphone CoreData在后台线程上加载数据时的奇怪行为_Iphone_Multithreading_Core Data - Fatal编程技术网

Iphone CoreData在后台线程上加载数据时的奇怪行为

Iphone CoreData在后台线程上加载数据时的奇怪行为,iphone,multithreading,core-data,Iphone,Multithreading,Core Data,我有一个非常奇怪的问题,当我完全不明白发生了什么,所以我在寻找解释。情况如下: 我有一个带有scrollview的视图控制器,其中有三个子视图。这三个子视图具有相同的方法 -(void)loadContent 它在后台线程中使用CoreData从数据库加载内容,创建表示加载项的子视图,并将它们添加为自己的子视图,调用[self-addSubview:itemView];该方法被调用为 [self performSelectorInBackground: @selector(loadConten

我有一个非常奇怪的问题,当我完全不明白发生了什么,所以我在寻找解释。情况如下:

我有一个带有scrollview的视图控制器,其中有三个子视图。这三个子视图具有相同的方法

-(void)loadContent
它在后台线程中使用CoreData从数据库加载内容,创建表示加载项的子视图,并将它们添加为自己的子视图,调用[self-addSubview:itemView];该方法被调用为

[self performSelectorInBackground: @selector(loadContent) withObject: nil];
为了从DB加载数据,我使用了一个单例服务类。一切正常,但当这三个视图加载各自部分的数据时,有时会使应用程序崩溃

我猜这是因为它为所有读取操作共享一个NSManagedObjectContext实例,所以我重写了该类,使其仅共享NSManagedObjectModel和NSPersistentStoreCoordinator实例,并创建了自己的NSManagedObjectContext实例

突然,非常奇怪的事情发生了。数据加载正常,子视图被创建并添加到视图层次结构中,但它永远不会显示在屏幕上。当我切换回旧的singleton服务类(共享一个managedObjectContext)时,它又像一个符咒一样工作了!(但有可能导致应用程序崩溃)

我完全不明白从DB加载数据与在屏幕上显示项目之间的关系。更多信息-创建子视图并将其添加到视图层次结构时,为什么不显示它

源代码如下所示:

- (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];
}
基本服务类(非单例服务类)实现如下(只是有趣的部分):

我真的很想知道这里发生了什么,为什么它的行为如此奇怪(当然,为什么它不起作用,尤其是)。有人能解释一下吗


多亏了所有的

你读了两遍了吗?

你意识到
[WLDataService service]
实际上并没有返回单例吗?它每次都创建一个新实例。因此,您可以有效地处理核心数据组件的多个实例

那么:

static WLDataService* gSharedService = NULL;

@implementation WLDataService

+ (id) service
{
    @synchronized (self) {
        if (gSharedService == NULL) {
            gSharedService = [[self alloc] init];
        }
    }
    return gSharedService;
}

@end

每次都会创建相同的实例。您还需要使用
@synchronized
块使
managedObjectContext
managedObjectModel
persistentStoreCoordinator
方法具有线程安全性。否则,多个线程将同时初始化这些元素,从而导致意外行为。

首先,不要在后台线程上加载或构造UI元素。UI(无论是在桌面上还是在iPhone上)是单线程的,在多线程上操作它是一个非常糟糕的主意

其次,加载到一个上下文中的数据在另一个上下文中不会立即可见。这就是造成你部分问题的原因


解决方案是将所有UI代码移动到主线程,并在后台线程上预热核心数据缓存。这意味着加载后台线程上的数据(到单独的缓存中)以将其加载到
NSPersistentStoreCoordinator
缓存中。完成后,您的主线程可以非常快地访问该数据,因为它现在位于内存中。

是的,我读了数百次。这就是为什么我试图修改我的singleton类,使其不是singleton,并为每个实例使用单独的托管对象上下文。我不是在线程之间发送托管对象实例,我只是根据其参数创建图形表示。我不明白为什么UIView对象没有被显示!您错过了“对于完全并发的操作,每个线程需要不同的协调器”的部分。非单例的行为确实像单例,因为它有全局变量来跟踪PSC和MOM的单例实例。由于您使用的代码来自多个线程,因此可能存在并发问题。初始化它们时肯定会有一个潜在的问题,因为您没有同步对它们的访问。因此,我修改了我的服务类,因此每个实例都保留自己的协调器实例和托管对象上下文,这两个访问器方法都是同步的。但没有更改-视图的内容仍不显示。我不知道这是怎么可能的,从数据库加载数据和完全显示其他内容之间的关系是什么。啊!!!我告诉过我,我改变了它的方式,使它不再是单一的,所以这正是我想要的——每次都有新实例,每个实例都有单独的托管对象上下文,共享持久存储协调器和托管对象模型,以避免线程并发访问一个托管上下文。这导致了我所描述的情况——不是在屏幕上绘制内容,尽管它是创建并附加到视图层次结构的。
static WLDataService* gSharedService = NULL;

@implementation WLDataService

+ (id) service
{
    @synchronized (self) {
        if (gSharedService == NULL) {
            gSharedService = [[self alloc] init];
        }
    }
    return gSharedService;
}

@end