handleEventsForBackgroundURLSession 中的 completionHandler 定义:

completionHandler definition inside handleEventsForBackgroundURLSession:

这不是之前在Whosebug这里问的一个小问题,至少我还没有发现类似的东西,当然我也googled它并且阅读了大部分排名靠前的结果。

顺便说一句,如果这里有人对 Objective C’ 的块语法不满意,请访问此页面 http://fuckingblocksyntax.com ,
在抛出任何与块相关的问题之前。

1st 我的部分问题是:the background of declaration of block-parameter, as well as invoking a method which has a block-parameter ( in many cases, a completionBlock )

MyWorker 中的“calleE-method”class: …………

@implementation MyWorker
-(void) aWorkerMethodNeedsABlockInput: ((void)(^)( NSObject *, double )) blockParam
{
       NSObject *anObj=[[ NSObject alloc] init];
       double *aDouble;
       [self retrieveTimeConsumingResults: anObj withNumberOfTry: aDouble ];
       blockParam ( anObj, * aDouble ); 

}

@end

MyManager 中的“calleR-method”class:

@interface myManager()
@property (nonatomic) MyWorker * mWorker;
@property (nonatomic, copy)  (void)(^mBlockProperty)( NSObject *, double );
@end
@implementation MyManager
-(void) aManagerMethodWhoCallsWorkerWithCompletionHandler
{
    (void)(^ valBlock )( NSObject *, double ) = ^(void)( NSObject * realObj, double realDouble )
     {
                 [realObj performSelector:@SEL( aSelector) withObject: @(realDouble) afterDelay: aTimeInterval];
        } ;
   self.mBlockProperty=[valBlock copy];
   [self.mWorker aWorkerMethodNeedsABlockInput : self.mBlockProperty];

}

@end

上面的 sudo-code 是在我们的自定义代码中将块存储在 属性 中的正常方式,声明块参数并在 CALLEE 中提供块的参数;提供块定义并在 CALLER 中“使用”块的参数。为了块语法的清晰,我保留了 'void' returnType 的书面形式。写错了请指正!

我问题的第二部分:

的常规用法
    - (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler {
    NSLog(@"Handle events for background url session");

    self.backgroundSessionCompletionHandler = completionHandler;
}

然后

- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session {
    WebAppDelegate *appDelegate = (WebAppDelegate *)[[UIApplication sharedApplication] delegate];
    if (appDelegate.backgroundSessionCompletionHandler) {
        void (^completionHandler)() = appDelegate.backgroundSessionCompletionHandler;
        appDelegate.backgroundSessionCompletionHandler = nil;

        completionHandler();
    }
    NSLog(@"All tasks are finished");
}

通过守护进程的后台回调在基于 NSURLSession 框架的上述模式中工作,对吗?我做了很多次,应用这种模式没有问题。

我想了很久的是:

“handleEventsForBackgroundURLSession:”方法的 completionHandler 参数的定义中,当从块属性 存储中调用该方法时,真正的定义是什么? < 在“completionHandler();”的时候被执行 > 我从未见过任何 sample/demo 中 put/copy 任何代码块到 completionHandler... 或者我想知道太多?

What is really inside the definition of the completionHandler parameter of “handleEventsForBackgroundURLSession:” method, when the method is invoked from a block-property storage? < at the time when “ completionHandler();” is executed > I have never seen any sample/demo which put/copy any block-of-code into completionHandler... or I wish to know too much?

如果我对您的问题的理解正确,那么您是在询问系统传递给 UIApplicationDelegate 方法 application:handleEventsForBackgroundURLSession:completionHandler: 的应用程序实现的块内的实现。

application:handleEventsForBackgroundURLSession:completionHandler: 由外部 service process 调用(间接)。当应用程序使用 NSURLSession 创建后台会话时,该会话由该系统服务管理。该服务执行实际的后台传输并通知 UIKit/Foundation,然后通过称为 XPC 的机制通知您的应用程序。 XPC 被 MacOS 开发人员广泛使用,但目前 iOS 应用程序无法直接使用 - 然而 iOS 上开发人员使用的许多 API 和服务实际上与 XPC 服务通信。

application:handleEventsForBackgroundURLSession:completionHandler: 的情况下,传递给 completionHandler 参数的块是一个不透明的回调。后台传输服务需要知道您的应用程序何时完成会话事件处理。调用该块会通知服务应用程序已完全处理这组事件,守护程序可以继续运行。

该块由系统创建和拥有,因此应用程序不应尝试修改或更改它(复制块除外,这是正确的做法!)。应用程序也不应提供自己的完成块 - 开发人员提供的块将无法通知传输服务完成,除非它包装传递给 completionHandler: 本身的块。

后台传输服务和 NSURLSession 已在 iOS 7 中引入。如果您正在编写第三方框架或库,利用该服务可能非常有益,但是框架必须提供一种方法来处理它拥有的任何后台会话的事件。也许正因为如此,似乎只有少数第三方库支持后台传输。支持这一点并不难——库只需要一个方法来指示会话的所有权,以及一个获取完成块和处理事件的方法:

- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler {

    if ([someCloudFrameworkObject canHandleEventsForSessionWithIdentifier:identifier]){
        [someCloudFrameworkObject handleEventsForBackroundSessionWithIdentifier:identifier completionHandler:completionHandler];
    }
}