0

Help me out here or just shed some light on the problem.

I have a scenario where I perform a sync of archived messages on a openfire server and I handle and store all incoming messages with NSOperations and NSOperationQueue.

I want to get notified when the NSOperationQueue is done, but I can't simply count the number of operations it has running. At times the NSOperationQueue has 0 operations because it depends on data to arrive form the server.

The NSOperations start methods

- (void)startArchiveSyncStore:(XMPPIQ *)iq operationID:(NSString *)xmlID {

   @autoreleasepool {

      if (![self.pendingOperations.archiveStoreInProgress.allKeys containsObject:xmlID]) {

          ArchiveStoreOperation *storeOperation = [[ArchiveStoreOperation alloc] initWithMessagesToArchive:iq withID:xmlID delegate:self];

          [self.pendingOperations.archiveStoreInProgress setObject:storeOperation forKey:xmlID];
          [self.pendingOperations.archiveStoreQueue addOperation:storeOperation];

      }
   }
}

 - (void)startArchiveSycnDownload:(XMPPIQ *)iq operationID:(NSString *)xmlID {

   @autoreleasepool {

      if (![self.pendingOperations.archiveDownloadInProgress.allKeys containsObject:xmlID]) {

          ArchiveDownloadOperation *downloadOperation = [[ArchiveDownloadOperation alloc] initWithMessagesToDownload:iq withID:xmlID delegate:self];

          [self.pendingOperations.archiveDownloadInProgress setObject:downloadOperation forKey:xmlID];
          [self.pendingOperations.archiveDownloadQueue addOperation:downloadOperation];

      }
   }
}

And this is the main thread callback performed by the NSOperation:

- (void)archiveStoreDidFinish:(ArchiveStoreOperation *)downloader {

    NSString *xmlID = downloader.xmlnsID;
    DDLogInfo(@"%@ %@", THIS_METHOD, xmlID);

    [self.pendingOperations.archiveStoreInProgress removeObjectForKey:xmlID];

}

These operations start when I receive iq stanzas containing lists of the chat history from the openfire server. Then I handle these lists like so:

- (BOOL)xmppStream:(XMPPStream *)sender didReceiveIQ:(XMPPIQ *)iq { 

    if ([iq isResultIQ]) {

        if ([iq elementForName:@"list" xmlns:@"urn:xmpp:archive"]) {

             [self startArchiveSycnDownload:iq operationID:[[iq attributeForName:@"id"] stringValue]];
        }
        if ([iq elementForName:@"chat" xmlns:@"urn:xmpp:archive"]) {

            [self startArchiveSyncStore:iq operationID:[[iq attributeForName:@"id"] stringValue]];
        }
    }

   return NO;
}

Any ideas folks ? Thanks in advance...

Marcos Curvello
  • 873
  • 13
  • 25

3 Answers3

0

From my understanding each NSOperation has an isFinished property that you can check for. But, there is a caveat - isFinished doesn't guarantee that the operation has completed successfully. It is set to true if it succeeds but also if it has been cancelled or an error has occurred.

Obviously each queue has a count of the operations [queue.operations count] but as you've said that won't be of use here.

One alternative is to use KVO. You could try setting this up between the other object that you're using and the NSOperationQueue. You could add an observer to the queue and check that no other operations are in effect.


Also, check this SO post here if you haven't already.

Community
  • 1
  • 1
Gordonium
  • 3,389
  • 23
  • 39
0

I use NSNotificationCenter and post whenever a NSOperation in the last queue finishes. I assume that there is a "last" queue, aka the one that gets spun up after other queue operations have finished.

When you receive the notification check the count of all your NSOperationQueues to see if they are empty.

random
  • 8,568
  • 12
  • 50
  • 85
0

It's not clear from your question exactly what condition you do consider to be "done" (no operations in the queue and… what?).

One approach is to create a completion operation. As you create the other operations, add each as a dependency of the completion operation. The completion operation can be in some other queue, possibly [NSOperationQueue mainQueue]. When there are no other operations outstanding, the completion operation will execute.

If you have some other condition than other operations outstanding that means the queue is not "done", then you need to explain. If it's that network downloading is in progress, then maybe you need to wrap such downloading in an operation.

You could also use a custom subclass of NSOperation for the completion operation and override -isReady to use whatever criteria it wants to augment the superclass's notion of readiness. Of course, if you do that, you need to generate KVO change notifications when those other criteria change.

Ken Thomases
  • 88,520
  • 7
  • 116
  • 154
  • No operations in the queue and no more messages coming from the server allocating new operations. The operations are allocated by the messages coming so I will never know when their done. I like the completion operation as a dependency I will look into that. – Marcos Curvello Feb 26 '15 at 00:38
  • How do you know whether there are any more messages coming from the server? – Ken Thomases Feb 26 '15 at 00:48
  • I guess it would be by checking if the `- (BOOL)xmppStream:(XMPPStream *)sender didReceiveIQ:(XMPPIQ *)iq;` method isn't being called ? – Marcos Curvello Feb 26 '15 at 00:55
  • You mean that some period of time passes since the last time it was called? Or do you expect the stream to be closed? I think you need to nail down what you consider "done" concretely and specifically (not high-level concepts but stuff which can be expressed in code). – Ken Thomases Feb 26 '15 at 01:28
  • No the stream won't close, I think the best thing would be your first alternative, even though I don't think this is a neat solution is the only one I can think at the time =\ – Marcos Curvello Feb 26 '15 at 01:45