gpt4 book ai didi

ios - 实现可重用线程安全核心数据模式时的问题/问题

转载 作者:行者123 更新时间:2023-11-28 22:51:04 25 4
gpt4 key购买 nike

我在实现 this tutorial 中概述的线程安全核心数据概念时遇到了问题。 .我的目标是拥有一段可重用的代码,可以接受参数,执行核心数据操作(添加、更新、删除),然后在完成后异步回调。

所以这是“安全”修改核心数据对象的 block :

+ (void)saveDataInContext:(void(^)(NSManagedObjectContext *context))saveBlock
{
NSManagedObjectContext *context = [NSManagedObjectContext context];
[context setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];
[defaultContext setMergePolicy:NSMergeObjectByPropertyStoreTrumpMergePolicy];
[defaultContext observeContext:context];
 
block(context);
if ([context hasChanges])
{
[context save];
}
}

根据我的理解,这会执行一段代码?我不明白“上下文”是如何在数字中传递的。这是 block 签名的一部分吗?

所以这是在后台执行操作并添加完成调用的包装器:
+ (void)saveDataInBackgroundWithContext:(void(^)(NSManagedObjectContext *context))saveBlock completion:(void(^)(void))completion
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
[self saveDataInContext:saveBlock];

dispatch_sync(dispatch_get_main_queue(), ^{
completion();
});
});
}

这是一个使用它的例子:
NSArray *listOfPeople = ...;
[NSManagedObjectHelper saveDataInBackgroundWithContext:^(NSManagedObjectContext *localContext){
for (NSDictionary *personInfo in listOfPeople)
{
PersonEntity *person = [PersonEntity createInContext:localContext];
[person setValuesForKeysWithDictionary:personInfo];
}
} completion:^{
self.people = [PersonEntity findAll];
}];

这里传入的“localContext”是什么?我认为我在这里的大部分问题都围绕着不理解 block 。

最佳答案

对该教程的简要介绍表明它正在谈论神奇的记录。我从来没有用过,所以我不能说它。

// This declares a class method that returns void and takes a block as parameter.
// The block returns void and has one parameter, namely, a pointer to an
// NSManagedObjectContext object.
+ (void)saveDataInContext:(void(^)(NSManagedObjectContext *context))saveBlock;

你会这样调用那个方法......
[SomeClass saveDataInContext:^(NSManagedObjectContext *context){
// Some code
}];

这意味着您正在将一段代码传递给该函数。在某些时候,它会执行你给它的代码块。当它这样做时,它会将托管对象上下文传递到 block 中,以便它可以用它做一些事情。

现在,看看该方法的实现......
+ (void)saveDataInContext:(void(^)(NSManagedObjectContext *context))saveBlock
{
// Create a MOC - note there is no concurrency type, so it will get
// NSConfinementConcurrencyType, which means it must be used exclusively
// from the thread in which it was created. Since it is a local variable
// and it gets destroyed after this function is called, that should be cool
// PROVIDED the using block does not do anything untoward with it.
NSManagedObjectContext *context = [NSManagedObjectContext context];

// Set the merge policy
[context setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];

// MR must set some default context...
// Some how the above context needs a persistent store to save...
[defaultContext setMergePolicy:NSMergeObjectByPropertyStoreTrumpMergePolicy];

// Probably setting up notification handler for DidSave
[defaultContext observeContext:context];


// Now, this is where the block you passed in gets called.
// Note, that the managed object context has already been setup for you.
// Now that it's setup, the block of code that you passed in is going
// to be called, and it will be given a context that it can use to execute
// code in the calling thread.
block(context);

// If you changed something to the context in your block of code, the save.
if ([context hasChanges])
{
[context save];
}
}

让我们回顾一下调用这个方法的代码......
[SomeClass saveDataInContext:^(NSManagedObjectContext *context){
// Now, the saveDataInContext method has been called. However, inside
// that method, a call was made to the block that was passed in.
// That would be this here block of code. So, if you look up in
// the method, where is calls "block(context)" this block of code will
// be executed right there. Mentally, you can cut and paste this code
// in that spot.
// The context parameter is the context that was passed to this block.
// you can use it to do any Core Data stuff...
}];

现在,这段代码非常相似,但它需要两个 block 。一个用于在上下文中执行一些代码,另一个是异步保存完成后将执行的 block 。

saveBlock 应该很熟悉。这与上面示例中的概念相同。

完成是一个 block ,它返回 void,并且不接受参数。完成所有工作后,它将被调用。
+ (void)saveDataInBackgroundWithContext:(void(^)(NSManagedObjectContext *context))saveBlock completion:(void(^)(void))completion
{
// Dispatch some work on one of the global concurrent queues. It will
// get done on some thread, nobody knows which one, but it does not matter
// because the code in this block calls saveDataInContext, and passes the
// block it was given that does some modifications to the context.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
[self saveDataInContext:saveBlock];

// Now, when the above work is done, we are still running in some random
// thread. I guess the library wants all callbacks to happen on the main
// thread, so this block is dispatched on the main thread. Note that it
// calls the second bock passed in as the completion block.
// So the <saveBlock> will be run on some random thread, and then, when
// it is done, the <completion> block will be called on the main thread.
dispatch_sync(dispatch_get_main_queue(), ^{
completion();
});
});
}

像之前一样,当您调用该方法时,您可以在脑海中将 替换为您传入的第一个 block ,然后替换为第二个 block 。
[NSManagedObjectHelper saveDataInBackgroundWithContext:^(NSManagedObjectContext *localContext){
// This is the first block. It gets executed where you see <saveBlock>
// being used in the earlier method. You are being given the already
// prepared MOC, and it's name is <localContext>. Do your managed object
// context stuff with it. Note that it will be running in some unknown thread.
for (NSDictionary *personInfo in listOfPeople)
{
PersonEntity *person = [PersonEntity createInContext:localContext];
[person setValuesForKeysWithDictionary:personInfo];
}
} completion:^{
// Now, this is the second block, which is run when all the core data saving
// has been completed. It will run on the main thread.
self.people = [PersonEntity findAll];
}];

希望这可以帮助您了解正在发生的事情,即使我不知道神奇唱片在幕后的真正作用。

编辑

回应这个评论...

I don't think I understand how these blocks work. If a block has this method signature "+ (void)saveDataInContext:(void(^)(NSManagedObjectContext *context))saveBlock" why is the block NOT using "context" or "saveBlock"? Which is the return value for a block and which is the passed in value? – Mike S



首先,该 block 没有这个签名......
+ (void)saveDataInContext:(void(^)(NSManagedObjectContext *context))saveBlock;

那是一个类方法。让我们一 block 一 block 地分解。然而,首先,让我们忘记 block 参数,并使用一些简单的东西来进行比较。
+ (void)foo:(NSInteger)someInteger;

即a是一个类方法, foo: ,返回 void并接受一个论点。该单个参数的类型是 NSInteger .如果我想调用它,我会这样做:
[SomeClass foo:42];

同样地...
+ (void)saveDataInContext:(void(^)(NSManagedObjectContext *context))saveBlock;

是一个类方法, saveDataInContext: ,它返回 void 并接受一个参数。该单个参数的类型是 void(^)(NSManagedObjectContext *context) .

现在,不要让那个狼吞​​虎咽的人愚弄你。它只是一种类型(尽管如果您不太了解 C,解析起来会有些困惑)所以, void(^)(NSManagedObjectContext *context) 是什么?

首先,它是一个 block .如果是 (^)void 之后是 (*)这将是一个函数指针。

基本上,这意味着该参数的类型是 block返回 void并且有一个参数,即指向 NSManagedObjectContext 的指针(名称为 context)。

所以,如果我们大声读出来...
+ (void)saveDataInContext:(void(^)(NSManagedObjectContext *context))saveBlock;

是一个类方法,带有选择器 saveDataInContext:返回 void并且有一个参数,其名称为 saveBlock并且属于“返回 void 并具有一个 NSManagedObjectContext * 类型参数的 block ”类型。

就像我们这样称呼第一个例子......
[SomeClass foo:42];

我们这样称呼后一个例子......
[SomeClass saveDataInContext:^(NSManagedObjectContext *context){
// We are creating a bock of code, so stuff some code in here.
}];

现在,就像你传递整数 42foo:您正在 {} 之间传递 block 作为 saveDataInContext: 的参数.

现在,请注意 saveDataInContext: 的签名方法需要一个本身有参数的 block 。所以,当你提供你的代码块时,你基本上是在说,“嘿,这里有一段代码供你调用,当你这样做时,请确保给我一个指向我可以使用的 NSManagedObjectContext 对象的指针.

这意味着当您的 block 被调用时,调用代码将调用您的 block 并提供 NSManagedObjectContext *给你变量名 context .

可以这样想,作为 saveDataInContext: 的一个简单示例.
+ (void)saveDataInContext:(void(^)(NSManagedObjectContext *context))saveBlock {
// Create a context to give the block we are going to call..
NSManagedObjectContext *moc = //
saveBlock(moc);
}

现在,当您的代码被调用时,您将得到 moc对象作为你的论据。基本上,该方法创建一个托管对象上下文,执行所有线程安全工作,然后调用您的代码块,并为您提供指向它已安全创建的托管对象上下文的指针。您的代码在该安全环境的范围内执行,使用作为函数( block )参数传递给它的 MOC。

我希望这没有让事情变得更糟......

关于ios - 实现可重用线程安全核心数据模式时的问题/问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11997181/

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