应用程序检查更新

时间:2013-02-27 16:06:16

标签: ios objective-c methods

我正在为内部企业应用创建更新方法。我想要创建的是一个可以快速放入应用程序的类,它将检查服务器是否需要更新。这是我到目前为止,它正确检查,但它在完成方法之前返回NO

在我的checkUpdate.h中

@interface checkForUpdate : NSObject

+ (BOOL)updateCheck;


@end

在我的checkUpdate.m

#import "checkForUpdate.h"

@implementation checkForUpdate

BOOL needsUpdate
NSDictionary *versionDict;


#define kBgQueue dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)


+ (BOOL)updateCheck {

    NSString *urlStringVersion = [[NSString alloc] initWithFormat:@"http://URL/app_info?app=app"];
    NSURL *urlVersion = [NSURL URLWithString:urlStringVersion];

    dispatch_async(kBgQueue, ^{
        NSData* data =[NSData dataWithContentsOfURL:urlVersion];

        if (data){
            NSError* error;
            NSArray* json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
            if (json != nil && [json count] != 0) {
                versionDict = [json objectAtIndex:0];

                CGFloat serverVersion = [[versionDict valueForKey:@"version"]floatValue];
                CGFloat appVersion = [[[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString*)kCFBundleVersionKey] floatValue];
                NSLog(@"Server Version %f",serverVersion);
                NSLog(@"App Version %f",appVersion);

                if ([versionDict count] != 0){
                    if (serverVersion > appVersion){
                        [[UIApplication sharedApplication] setApplicationIconBadgeNumber:1];
                        needsUpdate = YES;
                    }else{
                        [[UIApplication sharedApplication] setApplicationIconBadgeNumber:0];
                        needsUpdate = NO;
                    }
                }

            }
        }

    });

    return needsUpdate;

}


@end

我称之为

NSLog(@"Needs Update %@",[checkForUpdate checkForUpdateWithResponse] ? @"Yes":@"No");

这是我的日志

 Needs Update No
 Server Version 2.000000
 App Version 1.000000

我不确定为什么它甚至会在检查之前返回NO。我需要它是异步的,因为应用程序将检查的服务器位于我们的防火墙后面。因此,如果此人在防火墙之外,则应用程序需要在无法访问服务器时继续。我是朝着正确的方向前进,还是有更好的方法?

2 个答案:

答案 0 :(得分:3)

由于dispatch_async是非阻塞的,因此您的方法会在更新信息返回之前返回(发送并继续)。由于needsUpdate默认为NO,这就是您所看到的内容。您可以在日志时间中看到这一点 - 在服务器和应用程序版本之前显示“需要更新否”。

您需要某种回调(例如委托方法或第二个dispatch_async)以确保获得正确的结果,或者您需要阻止。我建议查看NSURLConnectionsendAsynchronousRequest:queue:completionHandler: - 它将在完成时执行完成处理程序,您可以在其中获得处理更新所需的任何代码。

答案 1 :(得分:3)

您正在异步检查更新,但希望通过您的方法设计立即响应。您可以将方法重新设计为类似下面的示例,以便在操作完成时通知处理程序:

注意:未经检查且未经测试的错误;但是,从示例中收集的教训是使用各种回调:

UpdateChecker类

typedef void (^onComplete)(BOOL requiresUpdate);

@interface UpdateChecker : NSObject
-(void)checkForUpdates:(onComplete)completionHandler;
@end

@implementation UpdateChecker
-(void)checkForUpdates:(onComplete)completionHandler
{
    NSString *urlStringVersion = [[NSString alloc] initWithFormat:@"http://URL/app_info?app=app"];
    NSURL *urlVersion = [NSURL URLWithString:urlStringVersion];
    dispatch_block_t executionBlock = 
    ^{
         /*
             Your update checking script here
             (Use the same logic you are currently using to retrieve the data using the url)
          */
         NSData* data = [NSData dataWithContentsOfURL:urlVersion];
         BOOL requiresUpdate = NO; 
         if (data)
         { 
             ...
             ...
             ...
             requiresUpdate = ...; //<-whatever your outcome
         }

         //Then when completed, notify the handler (this is our callback)
         //Note: I typically call the handler on the main thread, but is not required.  
         //Suit to taste.
         dispatch_async(dispatch_get_main_queue(),
         ^{
             if (completionHandler!=NULL)
                 completionHandler(requiresUpdate);
         });
    };
    dispatch_async(kBgQueue, executionBlock);
}
@end

这是您使用UpdateChecker检查整个应用中的更新时的样子

UpdateChecker *checker = [UpdateChecker alloc] init];
[checker checkForUpdates:^(BOOL requiresUpdate)
{
     if (requiresUpdate)
     {
        //Do something if your app requires update
        [[UIApplication sharedApplication] setApplicationIconBadgeNumber:1];
     }
     else         
        [[UIApplication sharedApplication] setApplicationIconBadgeNumber:0];
}];