永远不要离开while循环

时间:2014-03-10 09:07:04

标签: ios objective-c while-loop parse-platform

我有一个方法需要等待另一个方法来完成从数据存储区加载一些对象。所以我正在使用这样的while循环:

-(void) findAGoodCar {
    [self.indicator startAnimating];

    while(appDelegate.availableCars == nil || [appDelegate.availableCars count] < 1) {
        sleep(0.01);
    }

    // do some stuff
}

当这开始工作时,另一个过程,加载汽车,已经开始。

现在,该指标从未开始制作动画。对象的加载永远不会完成。循环永远不会结束。为什么?

编辑:这是我的loadCars方法。应用程序启动时从appDelegate调用它,从(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions开始,并异步查询Parse.com的云:

+(void) loadCars {
    PFQuery *query = [PFQuery queryWithClassName:kCarObjectKey];
    [query whereKey:kActiveKey equalTo:[NSNumber numberWithInteger:kActiveNumber]];
    NSSortDescriptor *sortByPrice = [[NSSortDescriptor alloc] initWithKey:kPriceKey ascending:YES];
    [query orderBySortDescriptors:[NSArray arrayWithObjects:sortByPrice, nil]];

    [query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
        if(!error) {
            AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
            appDelegate.availableCars = objects;
         } else {
            NSLog(@"Error in loadCars %@", error.localizedDescription);
        }
    }];
}

4 个答案:

答案 0 :(得分:5)

这是更新的帖子,因为它真正的作者的问题不是“无限循环”。

使用Parse

Parse提供了两种获取/将数据放入其服务器的方法:

  • 同步
  • 异步

同步

同步方法的缺点很明显 - 它会阻止UI线程,用户会看到无响应的UI。

那么为什么要生成那组方法?

如果在不知道结果的情况下无法继续工作,您的应用登录中会出现一些情况。在这种情况下,您必须使用同步方法。

异步

异步方法不会阻止UI。但它需要更深入地了解过程。

当然,你可以使用这样的循环:

while(appDelegate.availableCars == nil || [appDelegate.availableCars count] < 1) {
    sleep(0.01);
}

该方法将为您提供结果,但您阻止了UI线程。使用这种方法进行异步操作是不好的。您应该考虑使用block来处理异步请求。

App的架构

以下是我对应用程序架构的看法。 我更喜欢隔离所有代码,使用Parse(和其他API)到单独的类中。 所以我创建了一个类,并使其成为单例

ParseClient.h文件:

@interface ParseClient : NSObject
// singleton
+ (instancetype) sharedInstance;
@end

ParseClient.m文件:

@implementation ParseClient
+ (instancetype) sharedInstance {
    static ParseClient *sharedInstace = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstace = [[ParseClient alloc] init];
    });

    return sharedInstace;
}
@end

所以现在你可以访问整个应用程序中的parse对象了。现在,您可以向此类添加所需的功能。您可以添加缓存(例如,将数组存储为实例变量)并制作自己的缓存策略。

例如,您可以将以下函数添加到ParseClient:

- (void) loadCarsWithCompletionBlock:(void (^)(NSArray *objects, NSError *error))completionBlock {
    PFQuery *query = [PFQuery queryWithClassName:kCarObjectKey];
    [query whereKey:kActiveKey equalTo:[NSNumber numberWithInteger:kActiveNumber]];
    NSSortDescriptor *sortByPrice = [[NSSortDescriptor alloc] initWithKey:kPriceKey ascending:YES];
    [query orderBySortDescriptors:[NSArray arrayWithObjects:sortByPrice, nil]];

    [query findObjectsInBackgroundWithBlock:completionBlock];
}

并在应用中的任意位置调用

- (void) foo {
    ...
    [[ParseClient sharedInstance] loadCarsWithCompletionBlock:^(NSArray *objects, NSError *error){
        // you have array of cars here 
    }];
    ...
}

答案 1 :(得分:2)

似乎'findAGoodCar'在主线程上执行。在这种情况下,您正在阻止应用程序的主线程。它将阻止所有UI事件。

答案 2 :(得分:2)

它仍然很糟糕,但我看不到你的全貌。试试这个:

 while(appDelegate.availableCars == nil || [appDelegate.availableCars count] < 1) {
    [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.01]];
}

这不会阻止主线程

答案 3 :(得分:0)

我认为你在同一个线程中加载汽车。 尝试:

while(0 == appDelegate.availableCars.count) {
    [[NSRunLoop currentRunLoop] runUntilDate:[NSDate distantFuture]];
}