2

I'm struggling to figure out a solution to my problem,

I have a Download class which handles calls to my api, these calls are added to a NSOperationQueue. Each call is assigned a completed and failed notifier which post's when the call completes or fails. I can then handle the completion/failure of a request in my view controller gracefully.

The problem i'm having is this, what is the correct way to alloc/init/release my download class. My first approach was like so:

alloc init a new instance of the download class every time i need to run a request, i can then have a unique instance of the class with unique complete and failed notifiers and other params as i so wish. The problem i had with this approach is when/how to release the object. I cannot simply call the fetch request and then release the object within the same call, as the download call has queue's to complete and notifications to post, i know when the instance of the download class has finished it's calls because of the notification, i just don't know the correct way to implement it's release from another function. e.g:

-(void)downloadLists:(int)page featured:(BOOL)featured {

    NSMutableDictionary *postValues = [NSMutableDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:page],@"page",@"false",@"is_featured", nil];

    if(featured){
        [postValues setValue:@"true" forKey:@"is_featured"];
    }

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *destination = [[paths objectAtIndex:0] stringByAppendingPathComponent:[NSString stringWithFormat:@"lists_%i.json",page]];

    Download *download = [[Download alloc] init];
    [download setCompleteNotifier:@"listsComplete"];
    [download setFailedNotifier:@"listsFailed"];
    [download downloadPOST:[NSURL URLWithString:@"http://blahblah"] values:postValues destination:destination];

}

Then where do i release download, and ensure i'm releasing the correct instance, downloadLists may be called (n) amount of times in quick succession.

My other approach was to use a singleton of Download, which was great until i needed to add userinfo to the notifications, which of course became jumbled up by the singleton class being called from different places.

Any help will be greatly appreciated, here is the downloadPOST function for your reference:

-(void)downloadPOST:(NSURL *)path values:(NSDictionary *)keyValues destination:(NSString *)destination {

    ASIFormDataRequest *formRequest = [ASIFormDataRequest requestWithURL:path];

    for(id key in keyValues){
        [formRequest setPostValue:[keyValues objectForKey:key] forKey:key];
    }

    [formRequest setDownloadDestinationPath:destination];
    [formRequest setDelegate:self];
    [formRequest setDidFinishSelector:@selector(requestDone:)];
    [formRequest setDidFailSelector:@selector(requestWentWrong:)];
    [queue addOperation:formRequest];

}
Alex
  • 2,513
  • 5
  • 27
  • 42

2 Answers2

2

The Queue should be the one that handle the release of the object. There's several options here.

  1. You can use an NSNotification to publish your final state, which the queue listens on and remove instances that sends that notification

  2. You can create private delegation between the download & queue where the queue get notified

  3. You can set a boolean @property in you Download class (i.e BOOL completed). The queue retains the download instance and add a listener to the KVC completed. When completed is set to YES, it release the object

AFAK, you are using ASIHTTPRequest that handles all that for you, so I'm not sure why you are redoing this

Pier-Olivier Thibault
  • 3,907
  • 2
  • 33
  • 33
  • Hmm, my problem though is releasing the object that contains the queue, unless you are suggesting i call [self release] when the queue is complete? – Alex May 18 '11 at 13:20
  • Sorry forgot about this question :( First, you never call release on self, it doesn't make sense. I think you'd be better off with a singleton or a static variable accessible for all your Download class, I made a post on my blog a while back about this exact use case. It might be worth a look: http://pothibo.com/2011/02/06/nsobject-initialize-method-why-useful.html – Pier-Olivier Thibault May 23 '11 at 13:03
0

It seems like you're wrapping functionality already included in ASIHTTPRequest by default. The ASI classes have delegates built in to notify you of completion or failure:

- (void)requestFinished:(ASIHTTPRequest *)request;
- (void)requestFailed:(ASIHTTPRequest *)request;

Is there any other reason you can't just create the request in your main class without creating the download class, then let the delegate let you know when it's done?

Mark Struzinski
  • 32,945
  • 35
  • 107
  • 137
  • I was attempting to make it as flexible and reusable as possible, it appears i have done the opposite though and made it unnecessarily complex. I'll chop out my Download class. – Alex May 19 '11 at 08:41