IOS on dispatch_semaphore_t, dispatch_source_t and dispatch_group_t simple and practical for multi network asynchronous callback notification

The source of the problem: recently met a multi network asynchronous callback, in fact is we requested data is asynchronous, we use a method with a return value, we first obtain the result is empty, this is actually for the novice, may not know what will be the result, this is actually a little use Baidu Search will be able to find the answer, but to write about, as we deal with a blind spot

We mainly introduce 3 methods to obtain the callback results in the asynchronous method

First, the use of semaphores dispatch_semaphore_t control request

  • We look at some examples of the practical application, we try to simulate the real network request we see how code work:
* * @author Raybon.Lee, 16-04-07 10:04:02! * * @brief request data from the server, asynchronous return data, and update the UI, we are here to high imitation of real network environment request returns an array of @return * * * * @since < #1.0#> * / - (__kindof * NSArray) fetchDataFromServe{/ / if the array is used to store the data of NSMutableArray * array = [NSMutableArray arrayWithCapacity:0]; / / this instead of our usual asynchronous network commonly requested dispatch_async (dispatch_get_global_queue (0, 0), ^{for (int i=0; i< 10; i++) {[array addObject:[NSNumber numberWithInt:i]]}; NSLog (@ array =% @ ", array);}); return array;}

Under normal circumstances, we may have this kind of writing, because we did not notice the return data is asynchronous
we look down with the return:

NSArray * resultArray = [self fetchDataFromServe]; NSLog (resultArrsy =% @, @ resultArray);

* console output:

2016-04-07 10:30:45.868 resultArrsy = (2016-04-07) 10:30:45.875 array = (0, 1, 2, 3, 4, 5, 7, 8, 9, ABNumDemo[4129:1394441])

We feel the first sight is generally very clear, this value must exist, why eventually acquire value is wrong, sometimes considered easily messy, the above results will give us feedback information, the result is empty

  • Now let’s change the method, using semaphore control, by the way how the semaphore is working
(__kindof * NSArray) - fetchDataFromServe{/ / modify the following code, the use of signal to a synchronous data / / we pass a parameter 0, said no resources, 0 said there is resources, it needs to make clear: / / shaping parameters here if non dispatch_semaphore_t semaoh = 0 is the total resources dispatch_semaphore_create (0); / / if the array is used to store the data of NSMutableArray * array = [NSMutableArray arrayWithCapacity:0]; / / this instead of our usual asynchronous network commonly requested dispatch_async (dispatch_get_global_queue (0, 0), ^{for (int i=0; i< 10; i++) {[array} (addObject:[NSNumber numberWithInt:i]]; NSLog @ "% @ array =" a Rray); / / thank God leaves corrective correction: transmitting signal, signal management resource number +1 vehicle if the green lights, waiting for the vehicle will be reduced, which is to reduce the number of resources, has been reduced to dispatch_semaphore_wait this function returns 0 will continue, until there is a problem / comment, this is equivalent to the release by operation the implementation of signal number +1, the place must trigger signal, you will notice the function wait -1 is behind the operation, also can continue to use dispatch_semaphore_signal (semaoh);}); / / wait for the signal when the number of resources -1 blocking the current thread to understand this can be understood as to wait for the traffic lights of the vehicle, the vehicle / vehicle is waiting for a red light the cumulative waiting, no resources, will always trigger signal Control dispatch_semaphore_wait (semaoh, DISPATCH_TIME_FOREVER); return array;}
  • Signal understanding:
    when we initialize will first set up a total signal, if the signal is 0 of the total plastic parameters, so that there is no need to wait for resources, if we are following the wait operation as Yu Xiancheng congestion, -1 performs signal operation, if there is a green light, we will set the sigle signal +1, perform a signal operation, tell the current thread, a signal can be released, probably can understand
    modified after we look at the console output: 2016-04-07 10:36:17.361 ABNumDemo[4136:1395451] so array = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9) 2016-04-07 10:36:17.364 ABNumDemo[4136:1395425] = resultArrsy (0, 1, 2, 3, 4, 5, 6, 7, 8, 9) is not see We want to effect, in fact, we are to have an asynchronous callback results after the release of the number of resources

Two, below we look at the use of dispatch_group_t method

  • We also write a simulation request network
- (NSArray *) fetchTheNetUserData{dispatch_group_t group (NSMutableArray) = dispatch_group_create; array = [NSMutableArray * array]; for (int i=0; i< 5; i++) {dispatch_async (dispatch_get_global_queue (0, 0), ^{[array addObject:[NSNumber numberWithInt:i]]; return array;}});}

We now call the function to see the output:

NSArray * groupArray = [self fetchTheNetUserData]; NSLog (grouparray = @% @ ", groupArray); 2016-04-07 11:17:53.508 (grouparray = ABNumDemo[4143:1400362])

This result is not the desired results, we modify a little

- (NSArray *) fetchTheNetUserData{/ / GCD create a group group, this fact is not very well understood, we can understand, create a group, and then add the task to the group, after all the task group all end up in a ceremony, this is what we need dispatch_group_t group = dispatch_group_create (NSMutableArray * array); [NSMutableArray = array]; for (int i=0; i< 5; i++) {//group into a dispatch_group_leave group and the two must be paired, indispensable, if the thread is blocked will not correspond, dispatch_group_enter (Group); dispatch_async (dispatch_get_global_queue (0, 0 ^{), [array addObject:[NSNumber numberWithInt:i]]; //dispatch_group_leave left a group, and in fact the detoxification is similar to dispatch_group_leave (Group));};} //dispatch_group_wait this function returns 0 will continue, otherwise wait for all members of the task in group group is completed, this is also a function of the increase in the number of resources, waiting for the end of the thread (group, dispatch_group_wait DISPATCH_TIME_FOREVER (NSLog); @ array =% @ ", array); return array;}
  • Increase, look at the equivalent of two forms, but the use of different ways to see their needs
The two is a little bit different, one is to set up resources (group DISPATCH_TIME_FOREVER, dispatch_group_wait thread waits); the following is the notification form, can do some does not return a value method to update the UI operation dispatch_group_notify (group, dispatch_get_main_queue), ^{(//[tableView reloadData];});

Modified output environment:

2016-04-07 11:22:25.251 array = (0, 1, 3, 4) 2016-04-07 ABNumDemo[4149:1401314] grouparray = (0, 1, 2, 3, 4) 11:22:25.258 ABNumDemo[4149:1401314]

Through the above two methods, perhaps we have seen the desired results.

  • There is a need to pay attention to, when we use the above two, if you use AF AF when nested, the default is the main thread, and our wait function is the main thread, this will result in deadlock, to note that when using. This is the two day in the commissioning of the discovery of this, show

Three, use block to obtain the results of asynchronous callback

  • We still look at the code, intuitive:
- (void) queryTheDataRequestWithCompletion: (void (^) (NSString * string) block{(dispatch_get_global_queue) dispatch_async (0, 0), ^{block (@ test-block);};}) - (void) requestDataFormServe: (CallBlock) block{block (@{@ @ "name": "raybon"});}

Call these two methods:

[self requestDataFormServe:^ (NSDictionary *dict) {NSString = dict[@ * name "name"]; NSLog (@ name =% @ ", name);}]; [self queryTheDataRequestWithCompletion:^ (NSString *string) {NSLog (@ string = ^%@", string);}];

Then we look at the results of the output console:

2016-04-07 11:33:25.153 name = raybon 11:33:25.160 string = ^test-block = ABNumDemo[4155:1402877] 2016-04-07 = ABNumDemo[4155:1402837]

Using this block method, I think it is not a better understanding of it, okay, but this should adopt different methods according to different situation, is not fixed, here only to provide several ideas that have a better idea of the message are added to the technology, of course, is better.

Dispatch_semaphore_t control request
  • Add a request through the source control, is a thread safe, this is GCD API, we use the code analysis / / create a source DISPATCH_SOURCE_TYPE_DATA_ADD dispatch_source_t source data source type is increased (DISPATCH_SOURCE_TYPE_DATA_ADD, dispatch_source_create = 0, 0, dispatch_get_global_queue (0, 0)); / / set the event callback (dispatch_source_set_event_handler source, ^{/ / data execution is completed, let me update UI dispatch_async (dispatch_get_main_queue), NSLog (^{(“## @ I have received data, begin to update the UI operation ##”); dispatch_source_cancel (source);});}); //source is the default suspend suspension, we continue to perform dispatch_resume (dispatch_resume source; dispatch_async) ((dispatch_get_main_queue), ^{/ / here is the network request after the request to the data, we update a source NSLog (@ ## update notification data with ## “); dispatch_source_merge_data (source, 1);}); unsigned long num = dispatch_source_get_data (source); NSLog (@ data =%ld, Num); / / get the dispatch source, is to get the dispatch_source_create third parameters, unsigned long num1 = dispatch_source_get_mask (source); / / get access to the dispatch source is the second parameter position information of dispatch_create unsigned long num2 = dispatch_source_get_handle (source); / / source cancellation callback, to close the stream processing (source, dispatch_source_set_cancel_handler ^{NSLog (@ ## if source is cancelled, is to perform this function ##”);}); / / Detection of the source is cancelled, if is 0 said to cancel long cancelNum = dispatch_source_testcancel (source); / / call source block can be used to start, after the call to release the block, also in the implementation of the block is called the dispatch_source_set_registration_handler source (source, NSLog ^{(@ “I received is a registered callback”);} here we look at the role);
    API API is the main monitoring data updated the block callback, the easiest way is to update the UI network request has been completed, we will execute blockvoid dispatch_source_set_event_handler in it (dispatch_source_t source, dispatch_block_t handler); and data source APIdispatch_source_merge_data (source, 1); the API provides the data updated when a call second Parameters can not be set to 0, otherwise block is no response to other API is to cancel the source of the API, we do not need to cancel.


The above method is suitable when we do some simple traversal of the suits, according to some asynchronous data request, or a reminder that this must pay attention to whether there is a nested main thread, the thread blocking, as long as clear thinking, dealing with these problems is still no problem

  • Finally, we extend the problem of resource sharing, and we also use semaphore control

This is a thread safe, each time only allow a thread to read and write operations, read and write problems can refer to here oh

/ / here we specify an wait resource return value will not execute 0 signal operation dispatch_semaphore_t SeMAT = dispatch_semaphore_create (1); NSMutableArray * array = [NSMutableArray array]; dispatch_async (dispatch_get_global_queue (0, 0), ^{for (int i=0; i< 1000; i++) {dispatch_semaphore_wait (SeMAT, DISPATCH_TIME_FOREVER); [array addObject:[NSNumber numberWithInt:i]]; dispatch_semaphore_signal (SeMAT);}});
  • : the use of signal control AF request, we will encounter obstruction, this time in addition to control the use of group signal, recommended here leaves God’s runloopObserve, simple to understand is through the entry of runloop, to the end of the runloop, the release signal, temporarily without the completion of the study, this article will continue to study additional completion. Also hope to have the use of the great God, direct message, will be added in this article.