Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/115.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
Ios 关于使用完成块排队_Ios_Core Data_Asynchronous_Thread Safety_Objective C Blocks - Fatal编程技术网

Ios 关于使用完成块排队

Ios 关于使用完成块排队,ios,core-data,asynchronous,thread-safety,objective-c-blocks,Ios,Core Data,Asynchronous,Thread Safety,Objective C Blocks,所以,在前一段时间学习了完成块之后,我非常喜欢使用完成块。我喜欢闭包,我喜欢在任何地方传递任何东西的能力 作为一个线程编程新手,我一直远离GCD和NSOperation——但最近我不得不对核心数据进行异步更新编程,我开始怀疑我的“所有时间完成块”方法 这里有一个我质疑自己的例子:我有一系列潜在的相当大的数据(图像、声音、视频,你有什么)要上传到某个服务器上。这些数据的元数据存储在核心数据中,我有一个时间戳,用来决定应该上传哪些对象。所有这些上传都应该按顺序进行 我编写的基本上只是一个函数,其中包

所以,在前一段时间学习了完成块之后,我非常喜欢使用完成块。我喜欢闭包,我喜欢在任何地方传递任何东西的能力

作为一个线程编程新手,我一直远离GCD和NSOperation——但最近我不得不对核心数据进行异步更新编程,我开始怀疑我的“所有时间完成块”方法

这里有一个我质疑自己的例子:我有一系列潜在的相当大的数据(图像、声音、视频,你有什么)要上传到某个服务器上。这些数据的元数据存储在核心数据中,我有一个时间戳,用来决定应该上传哪些对象。所有这些上传都应该按顺序进行

我编写的基本上只是一个函数,其中包含一个完成块,在块的末尾有一个对自身的调用,如下所示:

(void)uploadAllAsynchronously {
  ... // First figure out what to upload based on core data
  // Here comes the completion block in question
  void(^blk)(BOOL) = ^(BOOL)uploadSuccess {
    ... // if upload successful, update core data to mark what has been uploaded
    [self uploadAllAsynchronously]; // Recursively calls the function that contains this block.  I actually have a weak self, or if that fails to break a retain cycle, I should be able to pass in a NSManagedObjectContext as an argument.
  }
  [NSURLConnection sendAsynchronousRequest:... queue:... completionHandler:blk];


}
这应该管用,对吧?这里是否有完全危险的东西建议我必须使用GCD并处理我自己的队列?我问这个问题是因为我现在遇到了一些问题,可能是因为异步调用导致不同的线程无法正确更新其中的数据,尽管不确定我的代码的哪一部分是罪魁祸首


提前感谢。

是的,此代码应该可以工作。。注意:我将重命名该方法。。uploadIfNeeded可能——因为它并不总是盲目地上传东西…

您的块类型错误

至于

如图所示,完成类型为黑色

void (^) (NSURLResponse *, NSData *, NSError *)
不是

您应该将
blk
更改为

void (^blk) (NSURLResponse *, NSData *, NSError *) = ^ (NSURLResponse *response, NSData *data, NSError *error) {
    //...
};

写作会更时尚

[NSURLConnection sendAsynchronousRequest:theRequest queue:theQueue completionHandler:^ (NSURLResponse *response, NSData *data, NSError *error) {
    //...
}];
与完井块的方法一致


关于在完成处理程序中对
NSManagedObjectContext
执行操作的问题:只要传递给
sendsynchronousrequest:queue:completionHandler:
NSOperationQueue
与创建托管对象上下文的
。但作为国家

核心数据使用线程(或序列化队列)限制来保护托管对象和托管对象上下文(请参阅“与核心数据的并发”)。这样做的结果是,上下文假定默认所有者是分配它的线程或队列,这由调用其init方法的线程确定。因此,您不应该在一个线程上初始化上下文,然后将其传递给另一个线程。相反,您应该将一个引用传递给持久性存储协调器,并让接收线程/队列创建一个由此派生的新上下文

如果传递的队列不是在其上创建托管对象上下文的队列,则必须执行以下操作之一

  • 在创建托管对象上下文的队列上调用
    -[NSOperationQueue addOperation::

  • 在正在进行核心数据操作的队列上创建第二个托管对象上下文(具有相同的持久存储协调器)

  • 在正在进行核心数据操作的队列上创建第二个托管对象上下文和第二个持久存储协调器

  • 使用锁定

  • 上的文档明确指出,必须使用线程限制(上面的选项1-3)或锁定(上面的选项4)

    这就是文档中关于使用锁的内容:

    如果您选择不使用线程包含模式,也就是说,如果您尝试在线程之间传递托管对象或上下文,等等,那么您必须非常小心锁定,因此您可能会否定从多线程中获得的任何好处

    这就是文档所说的,不仅要有每线程管理的对象上下文,还要有每线程持久存储协调器:

    这种方法提供了更高的并发性,但代价是更高的复杂性(特别是当您需要在不同上下文之间传递更改时)和更高的内存使用率


    因此,我在文档中的主要内容是:在WWDC 2012会话214视频中,似乎“因此,您不应该在一个线程上初始化上下文,然后将其传递给另一个线程”不再适用,因为每个上下文(只要它是MainQueue或PrivateQueue中的一个)实际上管理着自己的队列,不管是什么线。我不知道您是否看过该视频,但如果看过,我是否正确解释了视频中的演示者?我目前无法访问该WWDC视频,但上的文档非常清楚,如果您使用多线程/队列,则必须使用线程限制(具有每个线程管理的对象上下文)(可能是每个线程的持久存储协调器)或使用锁定。(请参阅我的编辑。)是的,这正是我所困惑的——文档似乎与我在WWDC视频中的解释不一致。我对视频的印象是,我认为这是最近的视频,它说现在核心数据负责自己的队列,所以除非绝对必要,否则不要在核心数据调用中使用GCD。或者我认为——我是一个新手任何操作系统中的线程。请记住,完成处理程序通常不会在后台线程上运行。通常(包括
    [NSURLConnection sendsynchronousrequest:queue:completionHandler:
    )完成块是在主线程上执行的。因此,您根本不需要担心线程安全。如果后台线程完成下载时主线程正忙,它会等到主线程空闲后再执行完成块。我发现有一种情况下嵌套的完成块会出问题tic并可能导致死锁:
    void (^blk) (NSURLResponse *, NSData *, NSError *) = ^ (NSURLResponse *response, NSData *data, NSError *error) {
        //...
    };
    
    [NSURLConnection sendAsynchronousRequest:theRequest queue:theQueue completionHandler:^ (NSURLResponse *response, NSData *data, NSError *error) {
        //...
    }];