【问题标题】:Web service call in background mode - iOS后台模式下的 Web 服务调用 - iOS
【发布时间】:2015-12-17 07:12:28
【问题描述】:

我需要每分钟调用一个网络服务,并在应用处于后台状态时解析数据。

由于APP使用定位服务,我开启了后台模式更新定位。

我尝试使用计时器后台任务调用位置更新,但它不起作用。

- (void)applicationDidEnterBackground:(UIApplication *)application
{
    self.bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
    NSLog(@"ending background task");
    [[UIApplication sharedApplication] endBackgroundTask:self.bgTask];
    self.bgTask = UIBackgroundTaskInvalid;
    }];


    self.timer = [NSTimer scheduledTimerWithTimeInterval:60
                                              target:self.locationManager
                                            selector:@selector(startUpdatingLocation)
                                            userInfo:nil
                                             repeats:YES];
}

有什么方法可以减少电池消耗。

我推荐了this link 我没有得到哪个解决方案更好。

【问题讨论】:

  • 应用程序处于后台模式时是否要上传用户当前位置?
  • 您不能在后台使用任何基于 NSTimer 的代码。您将需要使用“始终”位置模式并使用对您的委托的调用来检查是否是时候调用服务器了。但是,虽然您可以使用位置更新作为轮询服务器的机会,但这对电池或数据使用不友好。更有效的方法是让您的服务器在有新数据时使用推送通知。
  • @BandishDave 是的,我需要根据用户位置进行网络服务调用。
  • @Dev :我认为您必须使用位置管理器类并在委托方法中调用您的网络服务,而不是使用计时器。
  • @BandishDave 我也试过了。但是 didUpdateLocations 每秒都会被调用一次。因此,我正在检查持续时间并在 didUpdateLocations 中每隔一分钟进行一次 Web 服务调用。而且它会消耗更多的电池。

标签: ios iphone background-service location-services


【解决方案1】:

AppDelegate.h

#import <UIKit/UIKit.h>

@interface AppDelegate : NSObject  {
    // Instance member of our background task process
    UIBackgroundTaskIdentifier bgTask; 
}

@end

AppDelegate.m

- (void)applicationDidEnterBackground:(UIApplication *)application {
    NSLog(@"Application entered background state.");

    // bgTask is instance variable
    NSAssert(self->bgTask == UIBackgroundTaskInvalid, nil);

    bgTask = [application beginBackgroundTaskWithExpirationHandler: ^{
        dispatch_async(dispatch_get_main_queue(), ^{
            [application endBackgroundTask:self->bgTask];
            self->bgTask = UIBackgroundTaskInvalid;
        });
    }];

    dispatch_async(dispatch_get_main_queue(), ^{

        if ([application backgroundTimeRemaining] > 1.0) {
            // Start background service synchronously
            [[BackgroundCleanupService getInstance] run];
        }

        [application endBackgroundTask:self->bgTask];
        self->bgTask = UIBackgroundTaskInvalid;

    });
}

在上面的实现中有几个关键行:

第一行是 bgTask = [application beginBackgroundTaskWithExpirationHandler...,它要求额外的时间在后台运行清理任务。

第二个是以dispatch_async开头的委托方法的最后一个代码块。它基本上是通过调用[application backgroundTimeRemaining] 检查是否还有时间运行操作。在此示例中,我希望运行一次后台服务,但您也可以在每次迭代时对 backgroundTimeRemaining 使用循环检查。

[[BackgroundCleanupService getInstance] run] 行将调用我们现在将构建的单例服务类。

随着应用程序委托准备好触发我们的后台任务,我们现在需要一个与 Web 服务器通信的服务类。在以下示例中,我将发布一个虚构的会话密钥并解析 JSON 编码的响应。此外,我正在使用两个有用的库来发出请求并反序列化返回的 JSON,特别是 JSONKit 和 ASIHttpRequest。

BackgroundCleanupService.h

#import <Foundation/Foundation.h>

@interface BackgroundCleanupService : NSObject

+ (BackgroundCleanupService *)getInstance;

- (void)run;

@end

BackgroundCleanupService.m

#import "BackgroundCleanupService.h"
#import "JSONKit.h"
#import "ASIHTTPRequest.h"

@implementation BackgroundCleanupService

/*
 * The singleton instance. To get an instance, use
 * the getInstance function.
 */
static BackgroundCleanupService *instance = NULL;

/**
 * Singleton instance.
 */

+(BackgroundCleanupService *)getInstance {
    @synchronized(self) {
        if (instance == NULL) {
            instance = [[self alloc] init];
        }
    }
    return instance;
}

- (void)run {

    NSURL* URL = [NSURL URLWithString:[NSString stringWithFormat:@"http://www.example.com/user/%@/endsession", @"SESSIONKEY"]];

    __block ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:URL];

    [request setTimeOutSeconds:20]; // 20 second timeout

    // Handle request response
    [request setCompletionBlock:^{
        NSDictionary *responseDictionary = [[request responseData] objectFromJSONData];

        // Assume service succeeded if JSON key "success" returned
        if([responseDictionary  objectForKey:@"success"]) {
                NSLog(@"Session ended");
        }
        else {
             NSLog(@"Error ending session");
        }
    }];

    // Handle request failure
    [request setFailedBlock:^{
        NSError *error = [request error];
        NSLog(@"Service error: %@", error.localizedDescription);
    }];

    // Start the request synchronously since the background service
    // is already running on a background thread
    [request startSynchronous];
}

@end

可能会有所帮助

【讨论】:

  • 鼓励链接到外部资源,但请在链接周围添加上下文,以便您的其他用户了解它是什么以及为什么存在。始终引用重要链接中最相关的部分,以防目标站点无法访问或永久离线
  • @Maulik bgTask 将运行多长时间? Web 服务将执行多少次?
  • 每次去后台运行
  • 我的意思是,它是否会每隔一分钟调用一次服务器,即使应用程序处于后台模式。
  • 好的..所以我需要为位置更新或后台获取指定后台模式?
猜你喜欢
  • 2017-03-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-13
相关资源
最近更新 更多