2015-12-21 46 views
2

我正在使用CoreBluetooth与使用低功耗蓝牙的外围设备连接和交换数据。要连接到我的外设,我使用以下方法(为了清晰起见,managerCBCentralManager类的一个实例)。获取使用GCD和信号量的异步方法

- (void)connectPeripheral:(CBPeripheral *)peripheral { 
    // Connects with the peripheral 
    [manager connectPeripheral:peripheral options:nil]; 
} 

现在我想用Grand Central Dispatch,blocks和信号量来编写这个方法的异步版本。我希望有一个版本在特定的时间间隔内超时。首先,我所限定的本方法:

void dispatchAsyncWithCompletionAndTimeout(dispatch_queue_t queue, int64_t timeoutInNanoseconds, 
              dispatch_block_t block, dispatch_block_t completionBlock, 
              dispatch_block_t timeoutBlock) { 
    NSCParameterAssert(queue); 
    NSCParameterAssert(timeoutInNanoseconds >= 0); 
    NSCParameterAssert(block); 

    dispatch_async(queue, ^{ 
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); 
    dispatch_time_t timeoutTime = dispatch_time(DISPATCH_TIME_NOW, timeoutInNanoseconds); 

    dispatch_async(queue, ^{ 
     long timedOut = dispatch_semaphore_wait(semaphore, timeoutTime); 
     if (timedOut) { 
      if (timeoutBlock) { 
       timeoutBlock(); 
      } 
     } else if (completionBlock) { 
      completionBlock(); 
     } 
    }); 

    block(); 
    dispatch_semaphore_signal(semaphore); 
    }); 
} 

该函数基本上包含3个部分:第一是动作块(例如连接),而第二和第三个是处理程序块,其应该被称为是否进行了动作代码在超时过期之内或之后。

我所做其次是通过包装它下面的方法里面把我的connectPeripheral:方法为异步方法:

- (void)connectPeripheralAnsync:(CBPeripheral *)peripheral withinTimeout:(NSInteger)timeout { 
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 

    dispatchAsyncWithCompletionAndTimeout(queue, (int64_t)timeout * NSEC_PER_SEC, ^{ 
     [self connectPeripheral:peripheral]; 
    }, ^{ 
     NSLog(@"Peripheral discovered"); 
    }, ^{ 
     NSLog(@"Time runned out"); 
    }); 
} 

不幸的是我的第三块不会被调用,即使没有外围设备可以由被发现经理,直到超时过期。我在哪里失败?

回答

1

貌似有一个与GCD没有问题

我给你的代码重拍它一点点检查超时的东西容易,所以改变secsForTask和secsForTimeout我可以检查什么叫做:

unsigned int secsForTask  = 3; 
unsigned int secsForTimeout = 2; 

    dispatch_queue_t queue = dispatch_queue_create("com.test.111", DISPATCH_QUEUE_CONCURRENT); 

    int64_t timeoutInNanoseconds = secsForTimeout * NSEC_PER_SEC; 

    dispatch_async(queue, ^{ 

     dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); 
     dispatch_time_t timeoutTime = dispatch_time(DISPATCH_TIME_NOW, timeoutInNanoseconds); 

     dispatch_block_t timeoutBlock = ^{ 
      NSLog(@"timeout"); 
     }; 
     dispatch_block_t completionBlock = ^{ 
      NSLog(@"completion"); 
     }; 
     dispatch_block_t block = ^{ 
      NSLog(@"block start"); 
      sleep(secsForTask); 
      NSLog(@"block end"); 
     }; 

     dispatch_async(queue, ^{ 
      long timedOut = dispatch_semaphore_wait(semaphore, timeoutTime); 
      if (timedOut) { 
       if (timeoutBlock) { 
        timeoutBlock(); 
       } 
      } else if (completionBlock) { 
       completionBlock(); 
      } 
     }); 

     block(); 
     dispatch_semaphore_signal(semaphore); 

    }); 

上secsForTask = 3和secsForTimeout = 2

块开始
超时
块结束

上secsForTask = 1和secsForTimeout = 2

块开始
块结束 完成

可能你要检查,如果一切都确定了你的超时,所以你不通过方法connectPeripheralAnsync:withinTimeout:以纳秒为单位的超时。