我遇到了麻烦,试图弄清楚如何用我的桌面应用程序(不是iPhone应用程序!)中的异步NSURLConnection返回的数据填充NSImage。

这是情况。

我有一个使用自定义单元格的表。在每个自定义单元中都有一个从网络服务器中拉出的NSImage。为了填充图像,我可以轻松地执行同步请求:

myThumbnail = [[NSImage alloc] initWithContentsOfFile:myFilePath];

这样做的问题在于,表将一直阻塞直到图像被填充为止(显然是因为这是一个同步请求)。在大 table 上,这使滚动难以忍受,但是如果图像大小很大,即使只在第一次运行时填充图像也可能很乏味。

因此,我创建了一个异步请求类,该类将按照Apple's documentation在其自己的线程中检索数据。没问题。我可以看到数据正在被拉出和填充(通过我的日志文件)。

我遇到的问题是一旦有了数据,就需要在我的调用类(自定义表 View )中进行回调。

我的印象是我可以做这样的事情,但这是行不通的,因为(我假设)我的调用类真正需要的是一个委托(delegate):
NSImage * myIMage;
myImage = [myConnectionClass getMyImageMethod];

在我的连接类委托(delegate)中,我可以看到获取了数据,只是看不到如何将其传递回调用类。我的connectionDidFinishLoading方法直接来自Apple文档:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    // do something with the data
    // receivedData is declared as a method instance elsewhere
    NSLog(@"Succeeded! Received %d bytes of data",[receivedData length]);

    // release the connection, and the data object
    [connection release];
    [receivedData release];
}

我希望这是一个简单的问题,但是我担心我在此方面的知识有限,尽管Google进行了一些认真的搜索,并且尝试了许多推荐的方法,但我仍在努力寻求解决方案。

最终,我将为我的应用程序提供一个复杂的缓存机制,其中表 View 在外出并从服务器获取它们之前检查本地计算机上的图像,并可能有进度指示器,直到图像被检索为止。现在,如果使用同步过程处理足够大的图像,则即使本地镜像填充也可能会变慢。

任何和所有帮助将不胜感激。

解决方案更新

万一其他人需要类似的解决方案,这要归功于Ben的帮助(这是我为发布而想当然地修改的)。请记住,我还实现了图像的自定义缓存,并使图像加载类具有足够的通用性,可被应用程序中的各个地方用来调用图像。

在我的调用方法中,在我的情况下,这是表中的自定义单元格...
ImageLoaderClass * myLoader = [[[ImageLoaderClass alloc] init] autorelease];

    [myLoader fetchImageWithURL:@"/my/thumbnail/path/with/filename.png"
                     forMethod:@"myUniqueRef"
                        withId:1234
                   saveToCache:YES
                     cachePath:@"/path/to/my/custom/cache"];

这将创建myLoader类的实例,并向其传递4个参数。我想要获取的图像的URL,用于设置通知观察者时用来确定调用该类的唯一引用,图像的ID,是否要保存图像以进行缓存以及路径到缓存。

我的ImageLoaderClass定义了上面调用的方法,在这里我设置了从调用单元格传递的内容:
-(void)fetchImageWithURL:(NSString *)imageURL
           forMethod:(NSString *)methodPassed
              withId:(int)imageIdPassed
         saveToCache:(BOOL)shouldISaveThis
           cachePath:(NSString *)cachePathToUse
{

    NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:imageURL]
                                          cachePolicy:NSURLRequestUseProtocolCachePolicy
                                      timeoutInterval:60.0];

    // Create the connection with the request and start loading the data

    NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];

    if (theConnection) {

        // Create the NSMutableData that will hold
        // the received data
        // receivedData is declared as a method instance elsewhere

        receivedData = [[NSMutableData data] retain];

        // Now set the variables from the calling class

        [self setCallingMethod:methodPassed];
        [self setImageId:imageIdPassed];
        [self setSaveImage:shouldISaveThis];
        [self setImageCachePath:cachePathToUse];

    } else {
        // Do something to tell the user the image could not be downloaded
    }
}

connectionDidFinishLoading方法中,如果需要,我将文件保存到缓存中,并向所有监听者发出通知:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    NSLog(@"Succeeded! Received %d bytes of data",[receivedData length]);

    // Create an image representation to use if not saving to cache
    // And create a dictionary to send with the notification

    NSImage * mImage = [[NSImage alloc ] initWithData:receivedData];
    NSMutableDictionary * mDict = [[NSMutableDictionary alloc] init];

    // Add the ID into the dictionary so we can reference it if needed

    [mDict setObject:[NSNumber numberWithInteger:imageId] forKey:@"imageId"];

    if (saveImage)
    {
        // We just need to add the image to the dictionary and return it
        // because we aren't saving it to the custom cache

        // Put the mutable data into NSData so we can write it out

        NSData * dataToSave = [[NSData alloc] initWithData:receivedData];

        if (![dataToSave writeToFile:imageCachePath atomically:NO])
    NSLog(@"An error occured writing out the file");
    }
    else
    {
        // Save the image to the custom cache

        [mDict setObject:mImage forKey:@"image"];
    }

    // Now send the notification with the dictionary

    NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];

    [nc postNotificationName:callingMethod object:self userInfo:mDict];

    // And do some memory management cleanup

    [mImage release];
    [mDict release];
    [connection release];
    [receivedData release];
}

最后,在表 Controller 中设置观察者以监听通知,并将其发送给该方法以处理重新显示自定义单元的方法:
-(id)init
{
    [super init];

    NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];

    [nc addObserver:self selector:@selector(updateCellData:) name:@"myUniqueRef" object:nil];

    return self;
}

问题解决了!

最佳答案

您的直觉是正确的;您想要从对象(该对象是NSURLConnection的委托(delegate))到管理表 View 的 Controller 进行回调,该 Controller 将更新您的数据源,然后使用与图像对应的行的rect调用-setNeedsDisplayInRect:

10-08 08:20
查看更多