如何阻止代码等待连接

时间:2015-04-11 00:12:07

标签: ios objective-c

我一直在用一个新的api为一些sensorTag装箱。我需要等待连接解决,否则我的代码片会在第一次运行时失败。我有以下代码段:

- (void)viewDidLoad {
[super viewDidLoad];

self.sensorGyro = [MSBSensorUV createObjectGyro];
if(self.sensorGyro){
    while (!self.sensorGyro.client.isDeviceConnected) {
        NSLog(@"Awaiting connection");
    }//Check that connection has been made

    NSLog(@"connection UP");

        [self.sensorGyro.client.sensorManager startGyroUpdatesToQueue:nil errorRef:nil withHandler:^(MSBSensorGyroData *GyroData, NSError *error) {
            NSLog(@"Starting updates");
            self.currentGyroLabel.text = [NSString stringWithFormat:@"%lu", GyroData.GyroIndexLevel];
        }];

最初我没有while循环。我用了2-3秒的dispatch_after电话。但我觉得等待一段固定的时间并不好,最好是在连接时继续。但是,当我使用while循环时,我的应用程序只是停止并停止工作。没有崩溃,只是停下来。任何人都可以告诉我为什么会这样。因为我已经验证连接只花了2秒钟,所以我没有看到做while循环的问题?还有,有更好的方法来等待"用于完成/干燥的东西。

提前致谢

3 个答案:

答案 0 :(得分:2)

MSBSensorUV类正在启动一些异步连接过程。

  1. 如果您要循环等待状态更改,您可以将其发送到后台线程(如Luke加密建议的那样)。这可以防止应用程序阻塞主线程。

    问题是你仍然有一个线程被捆绑在一个浪费的练习中不断轮询,看看isDeviceConnected是否真实。这是一个程序相当于一个汽车后座的孩子不断询问"我们在那里吗?"

  2. 更好的是,您可以采用事件驱动模式,例如使用Matteo建议的KVO。这种方式而不是此代码不断轮询,当isDeviceConnected属性更改时,您将收到通知。

    这样做效率更高,如果您遇到一个没有提供完成块的类,但确实异步更改某些属性,这是一个很好的方法。

  3. 最好,因为MSBSensorUV是您自己的类,您可以重构它以提供连接完整处理程序块。这样,您就可以避免上述方法引入的复杂情况。


  4. 离线,您分享了MSBSensorUV实施的一些内容:

    + (MSBSensorUV *)createObjectUV{
        static MSBSensorUV *UVObject;
        static dispatch_once_t once_token;
        dispatch_once(&once_token, ^{
            UVObject = [[MSBSensorUV alloc]init];
        });
        return UVObject;
    }
    
    - (MSBSensorUV *)init{
        self = [super init];
        if(self){
            [MSBClientManager sharedManager].delegate = self;
            NSArray *clients = [[MSBClientManager sharedManager] attachedClients];
            self.client = [clients firstObject];
            if(self.client == nil){
                //no bands attached
                return nil;
            }
            [[MSBClientManager sharedManager] connectClient:self.client];
        }
        return self;
    }
    

    首先,createObjectUV正在创建一个单身,因此您应该将其重命名为sharedSensor(使用前缀shared,以明确您正在处理单身人士):

    + (instancetype)sharedSensor {
        static MSBSensorUV *uvObject;
        static dispatch_once_t once_token;
        dispatch_once(&once_token, ^{
            uvObject = [[MSBSensorUV alloc] init];
        });
        return uvObject;
    }
    

    其次,init不应该开始连接。

    - (instancetype)init {
        self = [super init];
        if (self) {
            [MSBClientManager sharedManager].delegate = self;
            NSArray *clients = [[MSBClientManager sharedManager] attachedClients];
            self.client = [clients firstObject];
            if(self.client == nil){
                //no bands attached
                return nil;
            }
            // [[MSBClientManager sharedManager] connectClient:self.client];
        }
        return self;
    }
    

    坦率地说,在单身人士的背景下,如果没有附加乐队,返回nil的概念可能没有意义(因为一旦你将它设置为nil在终止应用程序之前,你永远不能再次访问这个单例。所以你可能也想把这个逻辑从init中拉出来,但我会让你自己解决这个问题。

    第三,您将为连接完成处理程序声明一个属性:

    @property (nonatomic, copy) void (^connectionCompletionHandler)(BOOL success, NSError *);
    

    第四,您将创建一个connectionWithCompletionHandler方法,例如:

    - (void)connectWithCompletionHandler:(void (^)(BOOL success, NSError *error))block
    {
        self.connectionCompletionHandler = block;
    
        [[MSBClientManager sharedManager] connectClient:self.client];
    }
    

    您的连接委托方法将调用此完成处理程序,例如clientDidConnect会致电:

    if (self.connectionCompletionHandler) {
        self.connectionCompletionHandler(TRUE, nil);
        self.connectionCompletionHandler = nil;
    }
    

    didFailToConnectWithError会报告失败:

    if (self.connectionCompletionHandler) {
        self.connectionCompletionHandler(FALSE, error);
        self.connectionCompletionHandler = nil;
    }
    

    最后,回到原始代码示例,它看起来像:

    - (void)viewDidLoad {
        [super viewDidLoad];
    
        self.sensorGyro = [MSBSensorUV sharedSensor];
        [self.sensorGyro connectWithCompletionHandler:^(BOOL success, NSError *error) {
            if (success) {
                NSLog(@"connection UP");
                [self.sensorGyro.client.sensorManager startGyroUpdatesToQueue:nil errorRef:nil withHandler:^(MSBSensorGyroData *GyroData, NSError *error) {
                    NSLog(@"Starting updates");
                    self.currentGyroLabel.text = [NSString stringWithFormat:@"%lu", GyroData.GyroIndexLevel];
                }];
            } else {
                NSLog(@"Error connecting: %@", error);
            }
        }];
    }
    

答案 1 :(得分:1)

您可以使用 KVO ,然后观察变量:

self.sensorGyro.client.isDeviceConnected

变量时,观察者会收到通知。

所以你最初应该显示一个微调器(加载),并设置:

self.view.userInteractionEnabled = NO;

然后,当您收到通知时,您应该删除微调器并将用户交互设置为启用(YES)。

添加观察者很容易:

[self.sensorGyro.client addObserver:self forKeyPath:@"isDeviceConnected" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];

您必须添加此方法,该方法将在变量更改时调用:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if ([keyPath isEqualToString:@"isDeviceConnected"]) {
        // Your code here
    }
}

最后记得删除方法-dealloc中的观察者:

- (void)dealloc
{
    [self.self.sensorGyro.client removeObserver:self ....];
}

重要: 如果使用访问者方法设置属性isDeviceConnected,则会自动发送通知,因此:self.isDeviceConnected

有关详细信息,建议您阅读Apple documentation about KVO

答案 2 :(得分:1)

我建议使用dispatch_async命令。

基本上,您将为代码添加一定级别的多线程功能。我可能错了,但我会重写你的代码:

- (void)viewDidLoad {
[super viewDidLoad];

self.sensorGyro = [MSBSensorUV createObjectGyro];
if(self.sensorGyro){
    while (!self.sensorGyro.client.isDeviceConnected) {
        NSLog(@"Awaiting connection");
    }//Check that connection has been made

    NSLog(@"connection UP");

    dispatch_async(dispatch_get_main_queue(), ^{
         [self.sensorGyro.client.sensorManager startGyroUpdatesToQueue:nil errorRef:nil withHandler:^(MSBSensorGyroData *GyroData, NSError *error) {
         NSLog(@"Starting updates");
         self.currentGyroLabel.text = [NSString stringWithFormat:@"%lu", GyroData.GyroIndexLevel];
    });
}];