Take the 2-minute tour ×

I am rather new to iOS and Objective-C.

I am developing a project aiming to make a composition of complex (or "composite") operations as easy as possible: https://github.com/stanislaw/SACompositeOperations

I have four kinds of operations there: two single operations (sync and async) and two complex operations (cascaded and "transactional"). Single operations are used as "atoms" for complex operations, so I want to make them as good as possible in compliance with Objective-C best practices.

What I am interested in is: what code should I choose for these single operations?

By calling the first of two single operations "sync" I mean: run something probably asynchronous with completion handler and lock the flow waiting until it is done. "Async" means truly asynchronous operation - just run operation block in asynchronous fashion.

Here is the single operations code I currently use:

Sync operation

- (void)run:(syncOperationBlock)block {
    self.semaphore = dispatch_semaphore_create(0);


    while (dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_NOW))
        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
                                                       beforeDate:[NSDate dateWithTimeIntervalSinceNow:10]];

- (void)finish {


Async operation

- (void)run:(asyncOperationBlock)block {
    dispatch_queue_t queue = dispatch_queue_create("async_operation.queue", 0);

    dispatch_async(queue, ^{

I will be thankful, if someone can suggest any solutions for these single sync- and async- operations: more generic, more common, just better for the cases I've described

Shortly: what is the best code for forced-synchronous operation, for async operation?


share|improve this question
add comment

1 Answer

up vote 0 down vote accepted

My project did evolve significantly since I've asked this question.

From the structural point of view, I can't say much interesting about asynchronous operations: in my project they are all based on dispatch_async and the most valuable functionality is implemented with intensive usage of blocks (mainly: yielding operations themselves to the blocks they execute, allows to control a flow of these operations).

The more interesting thing to note here is the code I currently use for synchronous (or "forced-synchronous") operations - though their usage should be avoided in real apps, they are still applicable in unit tests: one example is a need to straighten the curly asynchronous flow of asynchronous net request to test its result in place, in the context of unit test case.

Though I am posting this as an answer to my non-specific question I would still really like to see any authoritative answer about whether my SASyncOperation is good enough for forced-sync operations (in the sense I've described it in this question) or maybe it could be improved more.

SASyncOperation as it currently written

  • Does not block main thread if it is run on main thread.
  • Does not produce excessive CPU polling as simple approaches with while(!completed){}; do.

This is the most important part of the code:

#import "SASyncOperation.h"

@interface SASyncOperation () {
    BOOL _isOnMainThread;
    dispatch_semaphore_t _semaphore;

@implementation SASyncOperation

// …

- (void)start {
    _semaphore = dispatch_semaphore_create(0);


    if (_finished) return;

    if ((_isOnMainThread = [NSThread isMainThread])) {
        while (dispatch_semaphore_wait(_semaphore, DISPATCH_TIME_NOW)) {
            CFRunLoopRunInMode(kCFRunLoopDefaultMode, [[NSDate distantFuture] timeIntervalSinceNow], NO);
    } else {
        dispatch_semaphore_wait(_semaphore, DISPATCH_TIME_FOREVER);

    _finished = YES;

- (void)run:(^(void)(SASyncOperation *)block {
    _operation = [block copy];

    [self start];

- (void)finish {
    _finished = YES;


    if (_isOnMainThread) {
        dispatch_async(dispatch_get_main_queue(), ^{

// …

This is how SASyncOperation should be used:

SASyncOperation *syncOperation = [[SASyncOperation alloc] init];

[syncOperation run:^(SASyncOperation *so) {
        soOver = YES;
        [so finish];
}]; // <- (*)

// (*) The flow will be stopped at this point waiting when 'so' operation will finish itself
share|improve this answer
add comment

Your Answer


