gpt4 book ai didi

ios - 使用 NSPrivateQueueConcurrencyType 和自定义 setter 的核心数据延迟加载不起作用

转载 作者:行者123 更新时间:2023-11-29 01:32:44 25 4
gpt4 key购买 nike

问题:当相关的 NSManaged 对象具有自定义 setter 时,使用后台线程获取托管对象不会正确延迟加载 NSManaged 对象关系。在具有主并发类型的主线程上执行提取没有问题。这是为什么?

解决方法:如果我在关系对象上创建自定义 getter 并检查是否为 nil,我可以通过调用没有自定义 setter 方法的其他变量来强制加载 NSManaged 对象。

背景核心数据布局非常简单。我有一个 Game 托管对象和一个 Turn 托管对象。 turn 对象与游戏对象是一对一的关系。我总是获取游戏对象以访问回合对象。 TurnImp 和 GameImp 是继承自 Game 和 Turn 对象的实现类,因此我不会将 getter/setter 方法放在自动生成的代码中。

代码

获取

//
//Stick command on background
//
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^ {
//
//Load Game
//
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
CoreDataHelper *coreDataHelper = appDelegate.coreDataHelper;
NSManagedObjectContext *childMOC = [coreDataHelper createChildManagedObjectContext];

//the request
NSFetchRequest *fetchRequest = [NSFetchRequest new];

//the object entity we want
NSEntityDescription *entity = [NSEntityDescription entityForName:GAMEIMP_GAME inManagedObjectContext:childMOC];
[fetchRequest setEntity:entity];

//the predicate rules, the what
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"gameId == %@", @"1404110671234567"];
[fetchRequest setPredicate:predicate];

//the sorting rules
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc]initWithKey:GAMEIMP_OBJECT_ID ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc]initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];

//Fetch results
NSFetchedResultsController *resultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:childMOC sectionNameKeyPath:nil cacheName:nil];
NSError *error;
BOOL success = [resultsController performFetch:&error];
GameImp *game;
if (success) {
game = [resultsController.fetchedObjects objectAtIndex:0];
} else {
NSLog(@"Unable to get game. Error: %@", error);
}
TurnImp *turnImp = game.turn;

//Issue is here!!! Should be 3, instead 0 because lastRoundReward is nil.
int lastRoundReward = [turnImp.lastRoundReward intValue];

//Work around, call custom getter method. Now 3 is returned.
lastRoundReward = [turnImp getLastRoundReward];
}

这个 childMOC 创作

-(NSManagedObjectContext*) createChildManagedObjectContext {
NSManagedObjectContext *childMOC = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
childMOC.parentContext = self.mainManagedObjectContext;

return childMOC;
}

TurnImp header

@interface TurnImp : Turn

@property(atomic) BOOL isValid;
- (void) setLastRoundReward: (int) lastRoundReward;
- (int) getLastRoundReward;
@end

TurnImp M

@implementation TurnImp

@synthesize isValid;
@synthesize lastRoundReward = _lastRoundReward;

/**
* Set the last round reward
* @param -
* @return -
*/
- (void) setLastRoundReward: (int) lastRoundReward {
_lastRoundReward = [NSNumber numberWithInt:lastRoundReward];
}

/**
* Get the int value of lastRoundReward
*/
- (int) getLastRoundReward {
//Note - HACK! Lazy loading not working, try another member
if (self.lastRoundReward == nil) {
//Force load
NSString *objectId = self.objectId;
}
return [self.lastRoundReward intValue];
}

将 childMoc 更改为 mainMoc 即可。 MainMoc 代码

 //create the main MOC
_mainManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];

修复并发问题后的更多内容

[childMOC performBlock:^{

// Execute the fetch on the childMOC and do your other work.
NSError *error;
NSArray *results = [childMOC executeFetchRequest:fetchRequest error:&error];
if (results == nil) {
// Handle error
} else if (results.count == 1) {
GameImp *game = [results firstObject];
TurnImp *turnImp = game.turn;

//Issue is here!!! Should be 3, instead 0 because lastRoundReward is nil.
int lastRoundReward = [turnImp.lastRoundReward intValue];

//Work around, call variable objectId (not same as ObjectId)
NSString *objectId = turnImp.objectId;
//not it's 3...
lastRoundReward = [turnImp.lastRoundReward intValue];

}
}];

变通

我从 TurnImp 中删除了以下内容,它按预期方式处理关系。

@synthesize lastRoundReward = _lastRoundReward;

最佳答案

首先,我必须承认,我不知道您的问题陈述是什么意思 - 关系的延迟加载到底应该做什么?

但是,快速浏览一下您的代码就会发现您正在使用 NSPrivateQueueConcurrencyType 创建 MOC但是您没有将其使用正确地包装在适当的 performBlock 中调用。

当您明显违反核心数据并发准则时,您就是在危险的水域中玩耍,并且会出现未定义的行为。

此外,为什么要创建 NSFetchedResultsController 的实例?只是为了执行获取?那太过分了。只需使用获取请求。像这样...

[childMOC performBlock:^{
// Execute the fetch on the childMOC and do your other work.
NSError *error;
NSArray *results = [childMOC executeFetchRequest:fetchRequest error:&error];
if (result == nil) {
// Handle error
} else if (results.count == 1) {
GameImp *game = [results firstObject];
TurnImp *turnImp = game.turn;
int lastRoundReward = [turn2.lastRoundReward intValue];
}
}];

关于ios - 使用 NSPrivateQueueConcurrencyType 和自定义 setter 的核心数据延迟加载不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33283900/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com