GCD和iOs中的多个代表

时间:2014-01-02 11:00:03

标签: ios objective-c multithreading delegates grand-central-dispatch

我想做以下事情: 在一个类(共享实例)中,我将有一个方法,它将数据对象(nsstring)和委托作为参数。这将创建一个新的后台线程并在该线程上调度一些计算。问题是该方法可能被调用数百次,具有不同的数据并且可能传入不同的委托。我希望结果转到正确的委托(我需要将代理保留在数组中吗?或者我可以将它们传递给后台线程,因为它们来了,当该线程完成时它会将结果仅发送给代表?)。

还有一件事......所有这些方法都将使用一个非常大的数据结构(一个包含10000个nsstring对象的数组,它们只需要从中读取)。如何确保每个线程不重复?并且仅在需要时分配并在没有线程使用时释放?

以下是我决定使用的代码:

   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];
        });

    });

然而......在此次运行之后,我将永久性的24MB添加到已用内存中。我想检测何时没有线程使用self.DIctPasswords数组并释放它。如果有人再次调用此方法,它将在稍后再次从文件中读取... 谢谢你的帮助。

3 个答案:

答案 0 :(得分:2)

让块捕获委托。 不需要等待

#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

样本

@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];
    }
}

答案 1 :(得分:1)

将计算加上数据和委托封装在自己的类中似乎更合适。然后你可以在你的单身人士中拥有这些对象的数组。您可以考虑在此处使用NSOperation

OMT:如果您正在使用任何属性,只需将此大型数组作为指针传递给每个计算对象并使用常规strong属性(而非copy),从而保存对使用ivar也很好。一个问题是这个数据结构必须是只读的;否则(当你在每个线程中修改它时),你需要一些数据锁定。

答案 2 :(得分:0)

我用块完成了它:一个拥有你需要的所有函数的单例(如API)和一个委托类

// 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
}];