This is not a trivial question asked here in StackOverFlow
before, at least I haven’t found anything similar, of course I also googled
it and read most of high ranked results.
BTW, if any folks here don't feel comfortable with Objective C’
s block syntax, visit this page please
http://fuckingblocksyntax.com ,
before throwing any block related issues.
1st part of my question is: the background of declaration of block-parameter, as well as invoking a method which has a block-parameter ( in many cases, a completionBlock )
The “calleE-method
" in MyWorker 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
The “calleR-method
" in MyManager 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
above sudo-code was the NORMAL way, in our custom code, of storing a block inside property, declaring a block parameter and also offering block’s arguments in CALLEE; providing block definition and also “consuming” block’s arguments in the CALLER. I keep 'void' returnType
in writing for clarity of block-syntax. Correct my writing if I did wrong, please!
2nd part of my question:
the routine usage of
- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler {
NSLog(@"Handle events for background url session");
self.backgroundSessionCompletionHandler = completionHandler;
}
then later
- (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");
}
the background callback via the daemon works in above pattern based on NSURLSession framework, right? I did it many times, not a problem on applying such pattern.
Which I have been wondering for a long time is:
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?
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?
If I understand your question correctly, you are asking what implementation is inside the block that is passed to an application's implementation of the UIApplicationDelegate method application:handleEventsForBackgroundURLSession:completionHandler:
by the system.
application:handleEventsForBackgroundURLSession:completionHandler:
is invoked (indirectly) by an external service process. When an application uses NSURLSession
to create a background session, that session is managed by that system service. That service does the actual background transfer and notifies UIKit/Foundation and in turn your application through a mechanism called XPC. XPC is widely used by MacOS developers, but at this time is not directly available to iOS applications - however many of the APIs and services used by developers on iOS are actually communicating with XPC services.
In the case of application:handleEventsForBackgroundURLSession:completionHandler:
, the block passed to the completionHandler
parameter is an opaque callback. The background transfer service needs to know when your application is done handling events for the session. Invoking that block informs the service that the application has completely processing of this set of events and the daemon can move on.
The block is created and owned by the system and as such an application should not attempt to modify or change it (other than copying the block, which is the right thing to do!). Applications should also not provide their own completion blocks - a developer-provided block would have no way to inform the transfer service of completion unless it wrapped the block passed to completionHandler:
itself.
The background transfer service and NSURLSession
were introduced in iOS 7. If you are writing a third party framework or library it can be very beneficial to take advantage of the service, but the framework must provide a way to handle events for any background session it owns. Perhaps because of this only a few third party libraries seem to support background transfers. Supporting this is not difficult to do - the library only needs a method to indicate ownership of the session, and a method to take the completion block and handle the events:
- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler {
if ([someCloudFrameworkObject canHandleEventsForSessionWithIdentifier:identifier]){
[someCloudFrameworkObject handleEventsForBackroundSessionWithIdentifier:identifier completionHandler:completionHandler];
}
}