OGeek|极客世界-中国程序员成长平台

标题: ios - 如何阻止代码等待连接 [打印本页]

作者: 菜鸟教程小白    时间: 2022-12-13 10:34
标题: ios - 如何阻止代码等待连接

我一直在为一些 sensorTag 提供新的 API。我需要等待连接解决,否则我的代码将在第一次运行时失败。我有以下代码片段:

- (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 循环的问题?另外,有没有更好的方法来“等待”东西完成/变干。

提前致谢



Best Answer-推荐答案


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

  1. 如果您要循环等待状态更改,您可以将其分派(dispatch)到后台线程(正如 Luke 隐晦地建议的那样)。这可以防止应用阻塞主线程。

    问题是你仍然有一个线程被捆绑在一个浪费的练习中,不断地轮询以查看 isDeviceConnected 是否为真。这就像一个 child 在汽车后座上不断问“我们到了吗?”

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

    如果您遇到一个不提供完成 block 但会异步更改某些属性的类,这会更有效,并且是一种很好的方法。

  3. 最好,因为 MSBSensorUV 是您自己的类,您可以重构它以提供一个连接完整的处理程序 block 。这样,您就可以避免上述方法带来的复杂性。


离线,您分享了一点 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)connectWithCompletionHandlervoid (^)(BOOL success, NSError *error))block
{
    self.connectionCompletionHandler = block;
    
    [[MSBClientManager sharedManager] connectClient:self.client];
}

然后您的连接委托(delegate)方法将调用此完成处理程序,例如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);
        }
    }];
}

关于ios - 如何阻止代码等待连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29572544/






欢迎光临 OGeek|极客世界-中国程序员成长平台 (http://sqlite.in/) Powered by Discuz! X3.4