0

我在构建我的代码时遇到了问题。 我有view,创建并取决于model类。模型类负责所有计算和逻辑。这意味着它有很多事情要计算,并从Core数据中获取对象。在不同线程中获取和使用NSManagedObject

enter image description here

关于enter link description here,即在一个线程中获得的每个NSManagedObject,需要在相同的线程中使用。

我的问题是,创建对象需要在不同的线程中获取,因为它需要一些时间来建立模型,但在此之后,我需要从View的主线程中获取对象和属性(例如cellForIndex ...)

我知道,我不是唯一一个拥有这种设计的人。别人如何解决这个问题?


编辑:

要使用代码混凝土这一点。

让我们说我们有UIView对象MyUIView和模型对象Model

MyUIView

@interface MyUIView() 

@property(nonatomic) Model * model; 

@end 

@implementation MyUIView 

- (void) createModel 
{ 
    // privateManagerContext is context manager created with 
    // NSPrivateQueueConcurrencyType, connected to persistent store 
    // and sync with "main thread" manager context with 
    // NSManagedObjectContextDidSaveNotification and NSManagedObjectContextDidSaveNotification 

    [self.model createWithManagadContext:privateManagerContext]; 
} 

// ASSUME THAT THIS CODE IS CALLED AFTER 
- (void) getNumberOfSomeProperties 
{ 
    int number = [self.model getNumberOfProperties]; 
} 

- (void) getProperties 
{ 
    NSArray *array = [self.model properties] 
} 

// OR WE HAVE TO TRIGGERED SOME LONG CALCULATION 

- (void) triggerLongCalculation 
{ 
    [self.model longCalculation]; 
} 

- (void) afterNotifyModelIsCompletedCalculating 
{ 
    [self doSomeWork]; 
    [self getProperties]; 
    .... 
} 
@end 

型号

@interface Model() 

@property(nonatomic) NSArray * cashedProperties; 

@end 

@implementation MyUIView 

- (void) createWithManagadContext:(NSManagedObjectContext *) privateManagerContext 
{ 
    dispatch_async(self.model_queue, ^(void){ 

     // Here we fetch objects and do some calculations 
     [self populateModel]; 

     /// Model is complete 
     [Notifications notifyModelIsCompletedCreating:self]; 
    }); 
} 


- (void) longCalculation 
{ 
    dispatch_async(self.model_queue, ^(void){ 
     // NO CORE DATA FETCH INVOLVED 
     [Notifications notifyModelIsCompletedCalculating:self]; 
    }); 
} 

- (int) getNumberOfProperties 
{ 
    return self.cashedProperties.count; 
} 

- (NSArray) properties 
{ 
    NSMutableArray * a = [[NSMutableArray alloc]init]; 
    for (Property * p in self.cashedProperties) { 
     [a addObject:p.name]; 
    } 

    return a; 
} 

@end 

所以在这个假设的类中,你将如何处理所有的NSManagedObject和NSManagedObjectContext?

编辑2:


我使用,我创建的appdelegate两个托管对象上下文,一个私人,一个主要的模式,并在它们之间建立同步。

- (NSManagedObjectContext *)managedObjectContext 
{ 
    if (__managedObjectContext != nil) { 
     return __managedObjectContext; 
    } 

    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator]; 
    if (coordinator != nil) { 
     __managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; 
     [__managedObjectContext setPersistentStoreCoordinator:coordinator]; 
    } 
    return __managedObjectContext; 
} 

- (NSManagedObjectContext *) privateQueueContext 
{ 
    if (_privateQueueContext != nil) { 
     return _privateQueueContext; 
    } 

    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator]; 
    if (coordinator != nil) { 
     _privateQueueContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; 
     [_privateQueueContext setPersistentStoreCoordinator:coordinator]; 
    } 
    return _privateQueueContext; 
} 


- (id)init 
{ 
    self = [super init]; 
    if (self) { 
     [[NSNotificationCenter defaultCenter] addObserver:self 
               selector:@selector(contextDidSavePrivateQueueContext:) 
               name:NSManagedObjectContextDidSaveNotification 
               object:[self privateQueueContext]]; 
     [[NSNotificationCenter defaultCenter] addObserver:self 
              selector:@selector(contextDidSaveMainQueueContext:) 
               name:NSManagedObjectContextDidSaveNotification 
                object:[self managedObjectContext]]; 
    } 
    return self; 
} 

#pragma mark - Notifications 

- (void)contextDidSavePrivateQueueContext:(NSNotification *)notification 
{ 
    @synchronized(self) { 
     [self.managedObjectContext performBlock:^{ 

      NSArray* objects = [notification.userInfo valueForKey:NSUpdatedObjectsKey]; 
      for (NSManagedObject* obj in objects) { 
       NSManagedObject* mainThreadObject = [self.managedObjectContext objectWithID:obj.objectID]; 
       [mainThreadObject willAccessValueForKey:nil]; 
      } 

      [self.managedObjectContext mergeChangesFromContextDidSaveNotification:notification]; 
     }]; 
    } 
} 

- (void)contextDidSaveMainQueueContext:(NSNotification *)notification 
{ 
    @synchronized(self) { 
     [self.privateQueueContext performBlock:^{ 

      NSArray* objects = [notification.userInfo valueForKey:NSUpdatedObjectsKey]; 
      for (NSManagedObject* obj in objects) { 
       NSManagedObject* mainThreadObject = [self.privateQueueContext objectWithID:obj.objectID]; 
       [mainThreadObject willAccessValueForKey:nil]; 
      } 

      [self.privateQueueContext mergeChangesFromContextDidSaveNotification:notification]; 
     }]; 
    } 
} 
+0

您可以在主线程中加载对象,也可以在计算完成后创建该对象的非受管版本并将其传递给主线程。 – Avi

回答

1

你可以在父/子配置中使用两个不同的NSManagedObjectContext。用于UI的父级,主队列中的子级,专用队列中的繁重子级。一旦孩子背景完成后,他的繁重工作就会节省下来,然后将其变化传播到主要背景中。你可以在你使用视图控制器中的表格视图的情况下使用NSFetchedResultsController,它观察主要的上下文。一旦主要上下文接收并合并来自其子上下文的更改,NSFetchedResultsController就会相应地更新UI,只要它的委托方法得到实现。

如果你不使用NSFRC,你可以注册你的主要上下文来通知“名称:NSManagedObjectContextObjectsDidChangeNotification”或“名称:NSManagedObjectContextObjectsDidSaveNotification”并查看哪些对象已被添加/删除/更新,从而更新UI。

如果您在父/子使用线程约束(过去由Apple过时),您可能希望在线程之间传递对象ID并在上下文中获取对象,因为NSManagedObjects不是线程安全的。

代码:

首先,我不会在视图中引用您的模型。视图应该是愚蠢的,并暴露出网点或方法被填充。我会有一个ViewController与模型和视图进行通信。

比方说,你有一个util方法来创建一个工作者上下文(作为你父母在主队列中的子上下文),每次你需要执行一个繁重的工作。

func newWorkerContext() -> NSManagedObjectContext { 
    let workerContext = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType) 
    workerContext.parentContext = self.mainContext 
    return workerContext 
} 

在模型中,你将有

//Lets say you have a reference to your workerContext 
func longCalculation() { 
    workerContext.performBlock({() -> Void in 
      //Heavy process of information 
      //Once finished you save the worker context and changes are propagated to the parent context  
    }) 

} 

在你的ViewController你会

class MyViewController: UIViewController { 

    func viewDidLoad() { 
     super.viewDidLoad() 

     NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(handleDataModelChange(_:)), name: NSManagedObjectContextObjectsDidChangeNotification, object: REFERENCE_TO_MAIN_CONTEXT) 
    } 

    func deinit { 
     NSNotificationCenter.defaultCenter().removeObserver(self, name: NSManagedObjectContextObjectsDidChangeNotification, object: REFERENCE_TO_MAIN_CONTEXT) 
    } 

func handleDataModelChange(notification: NSNotification) { 

    //Check changes are relevant for the UI you are updating and if so update. 
    if let changedObjects = changes[NSUpdatedObjectsKey] as? NSSet { 
    } 
    if let insertedObjects = changes[NSInsertedObjectsKey] as? NSSet { 
    } 
    if let deletedObjects = changes[NSDeletedObjectsKey] as? NSSet { 
    } 
} 
} 

记住要坚持持久性存储,你必须保存在主的变化上下文。 这是一个简单的例子,但我希望它给你现在做什么的想法。

+0

谢谢你的回答。理论上我明白你的意思,但我更新我的问题,如果你能够回答更具体的问题。 –

+0

@MarkoZadravec你尝试过我建议的方法吗? – ubiAle

+0

我看到你的答案,谢谢。我更新我的问题。我在应用程序委托中使用NSManagedObjectContextDidSaveNotification而不是UIViewController中的NSManagedObjectContextObjectsDidChangeNotification。 –

相关问题