objective c block that waits for another delegate

纵然是瞬间 提交于 2019-12-08 13:41:28

问题


I have a watchkit app that calls a viewcontroller on an iphone app. I have a delegate for a network connection. I'm trying to use a block so that I don't tightly couple my AppDelegate and my view controller too closely. How can I notify my block when the delegate is finished?

ViewController.m

-(void)getWatchDataWithCompletion:(void(^)(BOOL gotData))completion{
   [self setUpAppForWatch];
   completion(YES);
}

-(void)finishedMessageParse:(NSMutableData *)messageData{
   //the delegate is finish tell the block completion is done.

}

-(void)setUpAppForWatch{
   [network call];
}

AppDelegate.m

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

[vc getWatchDataWithCompletion:^(BOOL gotData){
    if (gotData){
       //I'm done reply dictionary
       reply(@{@"data":serlizedData})
}];

回答1:


add new property in viewcontroller:

@property (nonatomic, strong) void(^completion)(BOOL gotData);


-(void)getWatchDataWithCompletion:(void(^)(BOOL gotData))completion{
   [self setUpAppForWatch];
   self.completion = completion;
}

-(void)finishedMessageParse:(NSMutableData *)messageData{
    if (self.completion){
        self.completion(YES);
    }
}



回答2:


There're three possible ways.

;tldr - refer to the third one. Else - read everything, it might be useful.

First one

Use private serial queue for performing tasks of finished... method and your block. It will suffice you in case, if finished... always called before block. If not - take a look at the Second one

Use private @property dispatch_queue_t privateSerialQueue; of View Controller.

privateSerialQueue = dispatch_queue_create("PrivateQueue", DISPATCH_QUEUE_SERIAL);

Than, use it like this

-(void)getWatchDataWithCompletion:(void(^)(BOOL gotData))completion{
    [self setUpAppForWatch];
    dispatch_async(privateSerialQueue, ^(){
       completion(YES);
    });
}

-(void)finishedMessageParse:(NSMutableData *)messageData{
    dispatch_sync(privateSerialQueue, ^(void){
            //Here goes whatever you need to do in this method before block start
    });
    //the delegate is finish tell the block completion is done.
}

Second one

Take a look at dispatch_semaphore_t. Make it a public property of your View Controler

@property (readonly) dispatch_semaphore_t semaphore

Create it with starting value 0. It will let you wait in case your block runs before delegate finished... method and run immediately, if finished has already completed before block. Like this

self.semaphore = dispatch_semaphore_create(0); 

Then you can use it this way

-(void)finishedMessageParse:(NSMutableData *)messageData{
  //the delegate is finish tell the block completion is done.
  dispatch_semaphore_signal(self.semaphore);
}

[vc getWatchDataWithCompletion:^(BOOL gotData){
    if (gotData){
       //I'm done reply dictionary
       dispatch_semaphore_wait(vc.semaphore, DISPATCH_TIME_FOREVER);
       reply(@{@"data":serlizedData})
}];

Third one

Came to my mind while writing the two above =) Some kind of combination of previous two

Use private property of your view controller @property (readonly) dispatch_semaphore_t semaphore

Initialize it the same way, as in the second (with starting value 0)

self.semaphore = dispatch_semaphore_create(0); 

And use it privately like this

-(void)getWatchDataWithCompletion:(void(^)(BOOL gotData))completion{
    [self setUpAppForWatch];
    dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);
    completion(YES);
}

-(void)finishedMessageParse:(NSMutableData *)messageData{
  //the delegate is finish tell the block completion is done.
  dispatch_semaphore_signal(self.semaphore);
}

P. S. Hope, it helps you to get to the point. Feel free to ask anything not clear



来源:https://stackoverflow.com/questions/31119789/objective-c-block-that-waits-for-another-delegate

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