Iphone:传递对象和多个线程

时间:2010-09-29 16:02:51

标签: iphone objective-c cocoa-touch xcode thread-safety

我在将NSNumber对象传递给不同的线程时遇到了一些麻烦。 我在viewDidload上调用一个函数,它将核心数据中的一些对象作为后台进程加载。它调用另一个函数循环加载的对象,以查看是否有与之相关的图像alredy下载。如果它不存在,则异步下载图像并在本地保存。问题是我需要在主线程上执行startDownloadFor:atIndex:但是由于传递的NSNumber对象,应用程序崩溃了。这是代码..

- (void)viewDidLoad {
   ...
   ...
   [self performSelectorInBackground:@selector(loadImages) withObject:nil]; 
}

-(void)loadImages{
 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
 ...
        ...
 [self fillInImages];
 [pool release];
}

-(void)fillInImages{

 NSString *imageURL;
 for (int i=0; i < [dataManager.objectList count]; i++) {
  ...
  if ([dataManager.RelatedImages Image] == nil) {
   //[self startDownloadFor:imageURL atIndex:[NSNumber numberWithInt:i]; // << WORKS FINE
   [self performSelectorOnMainThread:@selector(startDownloadFor:atIndex:) withObject:(imageURL, [NSNumber numberWithInt:i]) waitUntilDone:YES]; // << CRASHES 
   ...
  }else {
   ...
  }
  ...
 }
 ...
}

-(void)startDownloadFor:(NSString*)imageUrl atIndex:(int)indexPath{

 NSString *indexKey = [NSString stringWithFormat:@"key%d",indexPath];
 ...
}

这样做的正确方法是什么?

由于

2 个答案:

答案 0 :(得分:1)

我从未见过将多个对象传递给选择器的语法 - 是有效的objective-c代码吗?另外,在你的startDownloadFor:atIndex:你传入一个NSNumber,但该选择器上第二个参数的类型是(int) - 这可能不是很好;)

performSelectorOnMainThread的文档:说选择器应该只接受一个id类型的参数。你传递了一个无效的选择器,所以我认为它对NSNumber的位置感到非常困惑。

要修复它,请传递一个包含数字和图像URL的NSDictionary,即

NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:imageURL, @"imageURL", [NSNumber numberWithInt:i], @"number", nil];
[self performSelectorOnMainThread:@selector(startDownload:) withObject:dict waitUntilDone:YES];

//-(void)startDownloadFor:(NSString*)imageUrl atIndex:(int)indexPath{
- (void)startdownload:(NSDictionary *)dict {
    NSURL *imageURL = [dict objectForKey:@"imageURL"];
    int indexPath = [[dict objectforKey:@"number"] intValue];

答案 1 :(得分:1)

您尝试将2个参数传递给performSelectorOnMainThread:withObject:waitUntilDone:,而该方法仅支持传递一个参数。

您需要使用NSInvocation发送更多参数(或使用像院长提议的NSDictionary)。

SEL theSelector;
NSMethodSignature *aSignature;
NSInvocation *anInvocation;

theSelector = @selector(startDownloadFor:atIndex:);
aSignature = [self instanceMethodSignatureForSelector:theSelector];
anInvocation = [NSInvocation invocationWithMethodSignature:aSignature];
[anInvocation setSelector:theSelector];
[anInvocation setTarget:self];
// indexes for arguments start at 2, 0 = self, 1 = _cmd
[anInvocation setArgument:&imageUrl atIndex:2];
[anInvocation setArgument:&i atIndex:3];

[anInvocation performSelectorOnMainThread:@selector(invoke) withObject:NULL waitUntilDone:YES];