ios:队列在后台阻塞,并在网络可用时执行

时间:2022-05-07 16:54:47

I am developing an app using parse.com API (hosted backend which provides API to save data on their servers). I want to be able to use the app seamlessly online and offline. For this I would need to use a queue where I can place blocks that require network access. When network does become available, the blocks should be executed serially and when the network goes offline, then the queue processing should be suspended.

我正在使用parse.com API开发一个应用程序(托管后端提供API以在其服务器上保存数据)。我希望能够在线和离线无缝使用该应用程序。为此,我需要使用一个队列,我可以放置需要网络访问的块。当网络确实可用时,应该串行执行这些块,当网络脱机时,应该暂停队列处理。

I was thinking of using GCD with suspend/resume as the network becomes available/unavailable. I was wondering if there are any better options? Will this work if the app is put in the background? Case in point here is that a user saves some data when the network is unavailable (which gets queued) and then puts the app in the background. Now when the network becomes available, is it possible to do the saving in the background automagically?

当网络变得可用/不可用时,我正在考虑将GCD用于暂停/恢复。我想知道是否有更好的选择?如果将应用程序放在后台,这会起作用吗?这里的一个例子是,当网络不可用(排队等待)然后将应用程序置于后台时,用户会保存一些数据。现在,当网络可用时,是否可以自动在后台进行保存?

5 个解决方案

#1


15  

I do exactly what you're aiming for using an NSOperationQueue. First, create a serial queue and suspend it by default:

我完全按照你的目标使用NSOperationQueue。首先,创建一个串行队列并默认将其挂起:

self.operationQueue = [[[NSOperationQueue alloc] init] autorelease];
self.operationQueue.maxConcurrentOperationCount = 1;
[self.operationQueue setSuspended:YES];

Then, create a Reachability instance and register for the kReachabilityChangedNotification:

然后,创建一个Reachability实例并注册kReachabilityChangedNotification:

[[NSNotificationCenter defaultCenter] addObserver:manager
                                         selector:@selector(handleNetworkChange:) 
                                             name:kReachabilityChangedNotification 
                                           object:nil];

[self setReachability:[Reachability reachabilityWithHostName:@"your.host.com"]];
[self.reachability startNotifier];

Now, start and stop your queue when the network status changes:

现在,在网络状态更改时启动和停止队列:

-(void)handleNetworkChange:(NSNotification *)sender {
    NetworkStatus remoteHostStatus = [self.reachability currentReachabilityStatus];

    if (remoteHostStatus == NotReachable) {
        [self.operationQueue setSuspended:YES];
    }
    else {
        [self.operationQueue setSuspended:NO];
    }
}

You can queue your blocks with:

您可以使用以下内容排队块:

[self.operationQueue addOperationWithBlock:^{
    // do something requiring network access
}]; 

Suspending a queue will only prevent operations from starting--it won't suspend an operation in progress. There's always a chance that you could lose network while an operation is executing, so you should account for that in your operation.

挂起队列只会阻止操作启动 - 它不会挂起正在进行的操作。在执行操作时,您总是有可能丢失网络,因此您应该在操作中考虑到这一点。

#2


2  

Check out -[PFObject saveEventually]. This should do what you're trying to do automatically and has the additional benefit of being resilient against app termination.

退房 - [PFObject saveEventually]。这应该做你想要自动执行的操作,并具有抵御应用程序终止的额外好处。

#3


1  

Have you looked at using the AFNetworking library? I believe it has hooks into Reachabiltiy and can behave exactly as you want.

您是否看过使用AFNetworking库?我相信它已经与Reachabiltiy挂钩,可以完全按照你的意愿行事。

#4


0  

I'm a big fan of GCD and Blocks but for this I would build a solution using NSOperationQueue. GCD is in my opinion more for the low level stuff. With NSOperationQueue you have the ability to cancel certain operations. Also you can express dependencies to other operations (if this is needed in you your application).

我是GCD和Blocks的忠实粉丝,但为此我会使用NSOperationQueue构建一个解决方案。对于低级别的东西,GCD在我看来更多。使用NSOperationQueue,您可以取消某些操作。您还可以表达对其他操作的依赖关系(如果您的应用程序需要这些操作)。

#5


0  

We had a similar issue on our internal projects, so I wrote a pod called OfflineRequestManager that wraps any network request and allows it to be enqueued regardless of connectivity. If you wrap the Parse request (or whatever) in an object conforming to OfflineRequest, the manager will enqueue it and ensure that it goes out whenever connectivity allows.

我们在内部项目中遇到了类似的问题,所以我编写了一个名为OfflineRequestManager的pod,它包装了任何网络请求,并允许它在不考虑连接的情况下排队。如果将Parse请求(或其他)包装在符合OfflineRequest的对象中,则管理器会将其排入队列并确保在连接允许时将其熄灭。

The simplest use case would look something like

最简单的用例看起来像

import OfflineRequestManager

class SimpleRequest: OfflineRequest {
    func perform(completion: @escaping (Error?) -> Void) {
        doMyParseThing(withCompletion: { response, error in
            handleResponse(response)
            completion(error)
        })
    }
}
///////
OfflineRequestManager.defaultManager(queueRequest: SimpleRequest())

#1


15  

I do exactly what you're aiming for using an NSOperationQueue. First, create a serial queue and suspend it by default:

我完全按照你的目标使用NSOperationQueue。首先,创建一个串行队列并默认将其挂起:

self.operationQueue = [[[NSOperationQueue alloc] init] autorelease];
self.operationQueue.maxConcurrentOperationCount = 1;
[self.operationQueue setSuspended:YES];

Then, create a Reachability instance and register for the kReachabilityChangedNotification:

然后,创建一个Reachability实例并注册kReachabilityChangedNotification:

[[NSNotificationCenter defaultCenter] addObserver:manager
                                         selector:@selector(handleNetworkChange:) 
                                             name:kReachabilityChangedNotification 
                                           object:nil];

[self setReachability:[Reachability reachabilityWithHostName:@"your.host.com"]];
[self.reachability startNotifier];

Now, start and stop your queue when the network status changes:

现在,在网络状态更改时启动和停止队列:

-(void)handleNetworkChange:(NSNotification *)sender {
    NetworkStatus remoteHostStatus = [self.reachability currentReachabilityStatus];

    if (remoteHostStatus == NotReachable) {
        [self.operationQueue setSuspended:YES];
    }
    else {
        [self.operationQueue setSuspended:NO];
    }
}

You can queue your blocks with:

您可以使用以下内容排队块:

[self.operationQueue addOperationWithBlock:^{
    // do something requiring network access
}]; 

Suspending a queue will only prevent operations from starting--it won't suspend an operation in progress. There's always a chance that you could lose network while an operation is executing, so you should account for that in your operation.

挂起队列只会阻止操作启动 - 它不会挂起正在进行的操作。在执行操作时,您总是有可能丢失网络,因此您应该在操作中考虑到这一点。

#2


2  

Check out -[PFObject saveEventually]. This should do what you're trying to do automatically and has the additional benefit of being resilient against app termination.

退房 - [PFObject saveEventually]。这应该做你想要自动执行的操作,并具有抵御应用程序终止的额外好处。

#3


1  

Have you looked at using the AFNetworking library? I believe it has hooks into Reachabiltiy and can behave exactly as you want.

您是否看过使用AFNetworking库?我相信它已经与Reachabiltiy挂钩,可以完全按照你的意愿行事。

#4


0  

I'm a big fan of GCD and Blocks but for this I would build a solution using NSOperationQueue. GCD is in my opinion more for the low level stuff. With NSOperationQueue you have the ability to cancel certain operations. Also you can express dependencies to other operations (if this is needed in you your application).

我是GCD和Blocks的忠实粉丝,但为此我会使用NSOperationQueue构建一个解决方案。对于低级别的东西,GCD在我看来更多。使用NSOperationQueue,您可以取消某些操作。您还可以表达对其他操作的依赖关系(如果您的应用程序需要这些操作)。

#5


0  

We had a similar issue on our internal projects, so I wrote a pod called OfflineRequestManager that wraps any network request and allows it to be enqueued regardless of connectivity. If you wrap the Parse request (or whatever) in an object conforming to OfflineRequest, the manager will enqueue it and ensure that it goes out whenever connectivity allows.

我们在内部项目中遇到了类似的问题,所以我编写了一个名为OfflineRequestManager的pod,它包装了任何网络请求,并允许它在不考虑连接的情况下排队。如果将Parse请求(或其他)包装在符合OfflineRequest的对象中,则管理器会将其排入队列并确保在连接允许时将其熄灭。

The simplest use case would look something like

最简单的用例看起来像

import OfflineRequestManager

class SimpleRequest: OfflineRequest {
    func perform(completion: @escaping (Error?) -> Void) {
        doMyParseThing(withCompletion: { response, error in
            handleResponse(response)
            completion(error)
        })
    }
}
///////
OfflineRequestManager.defaultManager(queueRequest: SimpleRequest())