I have created a subclass of NSOperation
named DownloadQueue
. And i'm adding all objects one by one to NSOperationQueue
which is appDelegate.queueDownload
.
Problem is when object of DownloadOperation
is executed and as soon as download
method of DownloadOperation
executes, my object of DownloadOperation
is removed from the queue.
But i have to keep it in memory because when i make an async call [using downloadFromPath
] in DownloadOperation.m
and server responds with file data, at that time the DownloadOperation
object is released and liveOperationSucceeded
never called.
May be i think that this question is a bit complex, So before flagging it please read it twice !! It's very important to me. Thanks for understanding.
// Adding to queue
DownloadOperation *operation = [[DownloadOperation alloc] init];
operation.delegate = self;
[operation operationWithFileOrFolderID:dictDocument[@"id"] withParentPath:self.strParentPath download:NO withFileName:dictDocument[@"name"] withDictionary:dictDocument];
[operation download];
[operation setQueuePriority:NSOperationQueuePriorityVeryHigh];
[appDelegate.queueDownload addOperation:operation];
DownloadOperation.m (which is Subclass of
NSOperation
)
@implementation DownloadOperation
-(void)main
{
[self download];
}
- (void)operationWithFileOrFolderID: (NSString *)strID withParentPath: (NSString *)strParentPath download: (BOOL)isDownload withFileName: (NSString *)strFileName withDictionary: (NSMutableDictionary *)dictInfoLocal
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
self.documentsDirectory = paths[0];
self.strFileName = strFileName;
self.strID = strID;
self.strParentPath = strParentPath;
self.dictInfo = dictInfoLocal;
if (self)
{
}
}
- (void)download
{
self.liveClient = [[LiveConnectClient alloc] initWithClientId:CLIENT_ID delegate:self];
[self.liveClient downloadFromPath:[self.strID stringByAppendingString:@"/content"] delegate:self];
NSLog(@"DownloadFilesVC : Downloading : %@",self.strFileName);
}
- (void) liveOperationSucceeded:(LiveOperation *)operation
{
}
- (void) liveOperationFailed:(NSError *)error
operation:(LiveOperation *)operation
{
}
- (void) liveDownloadOperationProgressed:(LiveOperationProgress *)progress data:(NSData *)receivedData operation:(LiveDownloadOperation *)operation
{
}
@end
You have an async operation inside an operation.
The operation queue is doing exactly what it is supposed to do and is ejecting the finished DownloadOperation
once the method download
completes. It doesn't care that the operation has callbacks.
You need to retain ownership of the DownloadOperation
operation by adding it to strongly referenced collection such as NSArray
or NSSet
and discarding it at a later point when LiveConnectClient
completes. You may wish to add a BOOL property to DownloadOperation
to say.
@property BOOL imReallyReallyFinishedAndCanBeDiscardedOK;
EDIT
The API is an async / delegate based. One simple way is to iterate over the folder contents and count the return responses. Once you have received the number of responses that matches the number of request you know you have completed.
As a very simplified version that doesn't care about recursion or errors.
@interface DownloadManager : NSObject
@property NSArray *fileRefList;
@property NSUInteger count;
@property (strong) void (^completionBlock)();
@end
@implementation DownloadManager
-(void)downloadAllTheFiles {
self.count = 0;
for(NSString *strID in self.fileRefList) {
LiveConnectClient *liveClient = [[LiveConnectClient alloc] initWithClientId:CLIENT_ID delegate:self];
[liveClient downloadFromPath:[strID stringByAppendingString:@"/content"] delegate:self];
}
}
- (void) liveOperationSucceeded:(LiveOperation *)operation
{
self.count++;
[self haveIFinished];
}
- (void) liveOperationFailed:(NSError *)error
operation:(LiveOperation *)operation
{
self.count++;
[self haveIFinished];
}
-(void)haveIFinished {
if (self.count == self.fileRefList.count) {
if (self.completionBlock) {
self.completionBlock();
}
}
}
Let the API do the queue operations and backgrounding for you. Fire off an arbitrary block when its done.