Class object in NSOperationQueue - with asynchronous method using delegate
I created a subclass NSOperation
named DownloadQueue
. And I add all objects one by one to NSOperationQueue
which is appDelegate.queueDownload
.
The problem is when the object is executed DownloadOperation
, and as soon as the download
method is executed DownloadOperation
, my object DownloadOperation
is removed from the queue.
But I have to keep it in memory, because when I make an asynchronous [using downloadFromPath
] call in DownloadOperation.m
and the server responds with the file data, at that time the object is DownloadOperation
freed and liveOperationSucceeded
never called.
Maybe I think this question is a little tricky, so read it twice before flagging it! It is very important for me. Thank you 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 a subclass
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
source to share
You have an async operation inside an operation.
The operational queue does exactly what it is supposed to do and pops the completed one DownloadOperation
when the method completes download
. Don't care if the operation has callbacks.
You need to retain ownership of it by DownloadOperation
adding it to a tightly bound set like NSArray
or NSSet
, and discard it at a later point when it completes LiveConnectClient
. You can add the BOOL property DownloadOperation
to say.
@property BOOL imReallyReallyFinishedAndCanBeDiscardedOK;
EDIT
The API is async / delegate. One easy way is to loop through the contents of the folder and count the responses. After you have received a number of responses that match the number of requests 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 and background activities for you. An arbitrary block died when it was executed.
source to share