使用来自异步NSURLConnection的数据填充NSImage [英] Populating NSImage with data from an asynchronous NSURLConnection

查看:162
本文介绍了使用来自异步NSURLConnection的数据填充NSImage的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我碰到了谚语的墙,试图找出如何使用从桌面应用程序(非iPhone应用程序)中的异步NSURLConnection返回的数据填充NSImage。

I have hit the proverbial wall trying to figure out how to populate an NSImage with data returned from an asynchronous NSURLConnection in my desktop app (NOT an iPhone application!!).

这是情况。

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

I have a table that is using custom cells. In each custom cell is an NSImage which is being pulled from a web server. In order to populate the image I can do a synchronous request easily:

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

这样做的问题是表会阻塞,直到图像填充(显然是因为它是一个同步请求)。在大表上,这使得滚动难以忍受,但即使只填充第一次运行的图像,如果它们具有任何显着的大小也可能是乏味的。

The problem with this is that the table blocks until the images are populated (obviously because it's a synchronous request). On a big table this makes scrolling unbearable, but even just populating the images on the first run can be tedious if they are of any significant size.

所以我创建一个异步请求类,它将根据 Apple的文档。没有问题。我可以看到数据被拉和填充(通过我的日志文件)。

So I create an asynchronous request class that will retrieve the data in its own thread as per Apple's documentation. No problem there. I can see the data being pulled and populated (via my log files).

我有的问题是一旦我有数据,我需要回调到我的调用类(自定义表视图)。

The problem I have is once I have the data, I need a callback into my calling class (the custom table view).

我的印象是,我可以这样做,但它不工作,因为(我假设)我的调用类真的需要是一个委托:

I was under the impression that I could do something like this, but it doesn't work because (I'm assuming) that what my calling class really needs is a delegate:

NSImage * myIMage;
myImage = [myConnectionClass getMyImageMethod];

在我的连接类委托我可以看到我获得数据,我只是看不到如何将它传递回调用类。我的 connectionDidFinishLoading 方法直接从苹果文档:

In my connection class delegate I can see I get the data, I just don't see how to pass it back to the calling class. My connectionDidFinishLoading method is straight from the Apple docs:

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



我希望这是一个简单的问题,在我对这一个的知识极限,尽管一些严重的谷歌搜索和尝试许多不同的推荐方法,我很努力想出一个解决方案。

I am hoping this is a simple problem to solve, but I fear I am at the limit of my knowledge on this one and despite some serious Google searches and trying many different recommended approaches I am struggling to come up with a solution.

我的应用程序的一个复杂的缓存机制,其中表视图在出去之前检查本地机器的图像并使它们形成服务器,并且可能有一个进度指示器,直到检索到图像。现在,如果图片的大小足够使用同步过程,即使是本地图片的人口也可能会迟钝。

Eventually I will have a sophisticated caching mechanism for my app in which the table view checks the local machine for the images before going out and getting them form the server and maybe has a progress indicator until the images are retrieved. Right now even local image population can be sluggish if the image's are large enough using a synchronous process.

任何和所有的帮助将非常感激。

Any and all help would be very much appreciated.

解决方案更新

如果任何人需要类似的解决方案,感谢Ben的帮助,想出了(一般修改为posting当然)。请记住,我还实现了图像的自定义缓存,并使我的图像加载类泛型足以被我的应用程序中的各个地方调用图像。

In case anyone else needs a similar solution thanks to Ben's help here is what I came up with (generically modified for posting of course). Bear in mind that I have also implemented a custom caching of images and have made my image loading class generic enough to be used by various places in my app for calling images.

在我的调用方法,在我的情况下是一个表中的自定义单元格...

In my calling method, which in my case was a custom cell within a table...

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,是否要将图像保存到缓存以及路径到缓存。

This creates an instance of myLoader class and passes it 4 parameters. The URL of the image I want to get, a unique reference that I use to determine which class made the call when setting up the notification observers, the ID of the image, whether I want to save the image to cache or not and the path to the cache.

我的ImageLoaderClass定义上面调用的方法,其中我设置从调用单元传递的内容:

My ImageLoaderClass defines the method called above where I set what is passed from the calling cell:

-(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 方法中,如果需要,将文件保存到缓存,监听器:

In the connectionDidFinishLoading method I saved the file to cache if needed and made a notification call to any listening observers:

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

最后在表控制器中设置一个观察器来监听通知和发送它关闭到处理重新显示自定义单元格的方法:

Finally in the table controller set up an observer to listen for the notification and send it off to the method to handle re-displaying the custom cell:

-(id)init
{
    [super init];

    NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];

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

    return self;
}

问题已解决!

推荐答案

你的直觉是正确的;你想要有一个从NSURLConnection的委托对象的回调到管理表视图的控制器,这将更新你的数据源,然后调用 -setNeedsDisplayInRect:图像对应的行的rect。

Your intuition is correct; you want to have a callback from the object which is the NSURLConnection’s delegate to the controller which manages the table view, which would update your data source and then call -setNeedsDisplayInRect: with the rect of the row to which the image corresponds.

这篇关于使用来自异步NSURLConnection的数据填充NSImage的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆