WatchKit return reply() inside a block in handleWatchKitExtensionRequest:

本小妞迷上赌 提交于 2019-12-02 05:55:12

问题


I saw this SO post where apparently data was being fetched and returned to the Watch extension like so:

- (void)application:(UIApplication *)application handleWatchKitExtensionRequest:(NSDictionary *)userInfo reply:(void ( ^)( NSDictionary * ))reply
{
  if ( [[userInfo objectForKey:@"request"] isEqualToString:@"getData"] )
 {
  // get data
  // ...
  reply( data );
 }
}

But when I try to call 'reply()' inside a block after getting network data like so:

__block UIBackgroundTaskIdentifier watchKitHandler;

watchKitHandler = [[UIApplication sharedApplication] beginBackgroundTaskWithName:@"backgroundTask"
                                                               expirationHandler:^{
                                                                   watchKitHandler = UIBackgroundTaskInvalid;
                                                               }];   
- (void)application:(UIApplication *)application handleWatchKitExtensionRequest:(NSDictionary *)userInfo reply:(void ( ^)( NSDictionary * ))reply
{ 

NSMutableDictionary *response = [NSMutableDictionary dictionary];
[ClassObject getDataWithBlock:^(BOOL succeeded, NSError *error){

        if (succeeded)
        {
            [response setObject:@"update succeded" forKey:@"updateKey"];
            reply(response);

        }
        else
        {
            if (error)
            {
                [response setObject:[NSString stringWithFormat:@"update failed: %@", error.description] forKey:@"updateKey"]; 
                reply(response);
            }
            else
            {
                [response setObject:@"update failed with no error" forKey:@"updateKey"];
                reply(response);
            }
        }
    }];
}

dispatch_after(dispatch_time( DISPATCH_TIME_NOW, (int64_t)NSEC_PER_SEC * 180), dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    [[UIApplication sharedApplication] endBackgroundTask:watchKitHandler];
});

I get this error:

"The UIApplicationDelegate in the iPhone App never called reply() in -[UIApplicationDelegate application:handleWatchKitExtensionRequest:reply:]"

So I guess I have to call reply() immediately and the only way to send fresh network data after WatchKit wakes up the parent app is to use MMWormhole?


回答1:


To make sure that your asynchronous data fetch does not return immediately (without calling reply), you may try the following:

- (void)application:(UIApplication *)application handleWatchKitExtensionRequest:(NSDictionary *)userInfo reply:(void ( ^)( NSDictionary * ))reply
{ 
    __block UIBackgroundTaskIdentifier watchKitHandler;

    watchKitHandler = [[UIApplication sharedApplication] beginBackgroundTaskWithName:@"backgroundTask"
                                                               expirationHandler:^{
                                                                   watchKitHandler = UIBackgroundTaskInvalid;
                                                               }];  

   NSMutableDictionary *response = [NSMutableDictionary dictionary];

   dispatch_semaphore_t sema = dispatch_semaphore_create(0);

   [ClassObject getDataWithBlock:^(BOOL succeeded, NSError *error){

        if (succeeded)
        {
            [response setObject:@"update succeded" forKey:@"updateKey"];
            reply(response);

        }
        else
        {
            if (error)
            {
                [response setObject:[NSString stringWithFormat:@"update failed: %@", error.description] forKey:@"updateKey"]; 

                dispatch_semaphore_signal(sema);

                reply(response);
            }
            else
            {
                [response setObject:@"update failed with no error" forKey:@"updateKey"];

                dispatch_semaphore_signal(sema);

                reply(response);
            }
        }
    }];

    dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);

    dispatch_after(dispatch_time( DISPATCH_TIME_NOW, (int64_t)NSEC_PER_SEC * 1), dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    [[UIApplication sharedApplication] endBackgroundTask:watchKitHandler];
  });
}



回答2:


Always refer to official documentation. Official Documentation

The following code works for me.

__block UIBackgroundTaskIdentifier bgTask = [application beginBackgroundTaskWithName:@"MyTask" expirationHandler:^{
                // Clean up any unfinished task business by marking where you
                // stopped or ending the task outright.
                [application endBackgroundTask:bgTask];
                bgTask = UIBackgroundTaskInvalid;
        }];

// Start the long-running task and return immediately.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

// Do the work associated with the task, preferably in chunks.

    [ClassObject getDataWithBlock:^(BOOL succeeded, NSError *error){

        if (succeeded)
        {
            [response setObject:@"update succeded" forKey:@"updateKey"];
            reply(response);

        }
        else
        {
            if (error)
            {
                [response setObject:[NSString stringWithFormat:@"update failed: %@", error.description] forKey:@"updateKey"]; 

                reply(response);
            }
            else
            {
                [response setObject:@"update failed with no error" forKey:@"updateKey"];

                reply(response);
            }
        }
    }];
    [application endBackgroundTask:bgTask];
    bgTask = UIBackgroundTaskInvalid;
});



回答3:


I think you got your code mixed up. You need to move the beginBackgroundTaskWithName to be inside your handleWatchKitExtensionRequest Make it the first thing you do, then call your function.

Simplified example:

-(void)application:(UIApplication *)application handleWatchKitExtensionRequest:(NSDictionary *)userInfo reply:(void (^)(NSDictionary *replyInfo))reply{


    UIApplication *app = [UIApplication sharedApplication];

    UIBackgroundTaskIdentifier bgTask __block = [app beginBackgroundTaskWithName:@"watchAppRequest" expirationHandler:^{

        NSLog(@"Background handler called. Background tasks expirationHandler called.");
        [[UIApplication sharedApplication] endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;

    }];

    //do your background task(s) here
    if([requestString isEqualToString:@“myRequest"]){

            //send reply back to watch
            reply();
    }

    //end background task
    [app endBackgroundTask:bgTask];
    bgTask=UIBackgroundTaskInvalid;

}


来源:https://stackoverflow.com/questions/30137019/watchkit-return-reply-inside-a-block-in-handlewatchkitextensionrequest

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!