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})
}];
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);
}
}
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