1

I would like to do the following: In a class (shared instance) I will have a method that takes as parameters a data object (nsstring) and a delegate. This will create a new background thread and dispatch some calculations on that thread. The thing is that the method may be called hundreds of times with different data and possibly different delegates passed in . I would like the results to go to the correct delegate (I will need to keep the delegates in an array right? or can I just pass them to the background thread as they come and when that thread finishes it will send the result only to that delegate?).

One more thing... all this methods will use a very large data structure (an array with 10000 nsstring objects,they only need to read from it). How do I make sure this is not duplicated on each thread? And is only allocated when needed and deallocated when no thread uses it?

Here is the code I decided to use:

   if (!self.dictPasswords) {
        // read everything from text
        NSString* fileContents = [NSString stringWithContentsOfFile:fileRoot
                                                           encoding:NSUTF8StringEncoding error:nil];

        //  separate by new line
        self.dictPasswords = [fileContents componentsSeparatedByCharactersInSet:
                                   [NSCharacterSet newlineCharacterSet]];

    }

    __weak id<PSPasswordDictionaryVerificationDelegate> wdelegate = delegate;

    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        [wdelegate willBeginPasswordVerificationForPassword:password];
        for (NSString *posiblePass in self.dictPasswords) {
            if ([password isEqualToString:posiblePass]) {
                dispatch_async(dispatch_get_main_queue(), ^{
                    [wdelegate password:password isInDictionary:YES];
                });

                 return;
            }
        }
        dispatch_async(dispatch_get_main_queue(), ^{
            [wdelegate password:password isInDictionary:NO];
        });

    });

However... after this runs I get a permanent 24MB added to the used memory. I would like to detect when no threads are using the self.DIctPasswords array and deallocate it. It will be read from the file again later if somebody calls this method again... Thanks for the help guys.

user1028028
  • 6,323
  • 9
  • 34
  • 59

3 Answers3

2

Just let the block capture the delegate. No need to hold it otherwise

Class

#import <Foundation/Foundation.h>

@protocol ProcessorDelegate;

@interface Processor
- (void)process:(id)data forDelegate:(id<ProcessorDelegate>)delegate;
+ (Processor*)sharedInstance;
@end

@protocol ProcessorDelegate
- (void)processor:(Processor*)processor didProcess:(id)data withResult:(id)result;
@end

@implementation  Processor

- (void)process:(id)data forDelegate:(id<ProcessorDelegate>)delegate {
    __weak id<ProcessorDelegate> wdelegate = delegate; //capture weak to counter potential cycles
    __weak id wself = self;
    dispatch_async(dispatch_get_global_queue(0,0), ^{
        NSLog(@"WORK");
        id result = data; //TODO
        [wdelegate processor:wself didProcess:data withResult:result];
    });
}

+ (Processor*)sharedInstance {
    static Processor *p = nil;
    if(!p) {
        p = [[Processor alloc] init];
    }

    return p;
}

@end

DEMO

@interface Demo : NSObject <ProcessorDelegate>
- (void)doIt;
@end

@implementation Demo
- (void)doIt {
    [Processor sharedInstance] process:@"TEST" forDelegate:self];
}
@end

int main(int argc, char *argv[]) {
    @autoreleasepool {
        Demo *d1 = [[Demo alloc] init];
        Demo *d2 = [[Demo alloc] init];
        Demo *d3 = [[Demo alloc] init];
        Demo *d4 = [[Demo alloc] init];

        [d1 doIt];
        [d2 doIt];
        [d3 doIt];
        [d4 doIt];

        [[NSRunLoop currentRunLoop] run];
    }
}
Daij-Djan
  • 49,552
  • 17
  • 113
  • 135
  • disclaimer: written inline, never run. should work and definitely should show what you need to do: nothing :D – Daij-Djan Jan 02 '14 at 12:29
  • Of course `sharedInstance` should be done with [`dispatch_once()`](http://stackoverflow.com/a/19947222/1971013). – meaning-matters Jan 02 '14 at 17:20
  • in general... sure why not :D with the great Xcode macros I do that too. The syntax is only hard to remember but.... yes – Daij-Djan Jan 02 '14 at 17:31
1

It seems more appropriate to encapsulate the calculations plus data and delegate in a class of its own. Then you can have an array of those objects in your singleton. You may want to consider using NSOperation here.

OMT: Simply pass this large array as a pointer (to each calculation object) and use regular strong properties (not copy) if you're using any properties at all, saving a reference to it using an ivar is fine too. One concern is that this data-structure must be read-only; otherwise (when you'd modify it in each thread), you'd need some data locking.

meaning-matters
  • 21,929
  • 10
  • 82
  • 142
  • 1
    That data structure is never modified ... And I would rather do the calculations using GCD in the same class than NSOperation with another class ... – user1028028 Jan 02 '14 at 11:55
  • don't see why a heavy duty object like a separate NSOperation is required – Daij-Djan Jan 02 '14 at 14:17
0

I have done it with blocks : a singleton that have all the functions you needs (like an API) and a delegate class

// singleton.h
typedef void (^request_handler_t)(NSData* data);
- (void) foo:(NSString *)str withBlock:(request_handler_t)callback;

// singleton.m
- (void) foo:(NSString *)str withBlock:(request_handler_t)callback;{
    MyDelegate *delegate = [MyDelegate delegateWithBlock:callback];
    [yourMethodThatNeedDelegate:delegate];
}

// MyDelegate.h
+ (MyDelegate*) delegateWithBlock:(api_request_handler_t)block;
- (void)delegateMethod1;

//Delegate.m
+ (MyDelegate*) requestWithBlock:(api_request_handler_t)block;{
    //... alloc init
    _callback = block;
}
- (void)delegateMethod1;{
    // delegate finished the job
    block(myResultingData);
}

// Usage : 
[MySingleton singleton] foo:(NSString *)str withBlock:^(NSData *data){
    //do something with the async data
}];
HaneTV
  • 916
  • 1
  • 7
  • 24