我一直在为一些 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-推荐答案 strong>
MSBSensorUV 类正在启动一些异步连接过程。
如果您要循环等待状态更改,您可以将其分派(dispatch)到后台线程(正如 Luke 隐晦地建议的那样)。这可以防止应用阻塞主线程。
问题是你仍然有一个线程被捆绑在一个浪费的练习中,不断地轮询以查看 isDeviceConnected 是否为真。这就像一个 child 在汽车后座上不断问“我们到了吗?”
更好的是,您可以采用事件驱动模式,例如使用 Matteo 建议的 KVO。这样,您将在 isDeviceConnected 属性更改时收到通知,而不是此代码不断轮询。
如果您遇到一个不提供完成 block 但会异步更改某些属性的类,这会更有效,并且是一种很好的方法。
最好,因为 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/
|