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。 –

相關問題