我正在使用 SDWebImage 库将远程图像加载到使用我创建的自定义单元格类的表格 View 中。我只是使用
[cell.imageView setImageWithURL:url placeholderImage:[UIImage imageNamed:@"loading.jpg"]];
最佳答案
如果要预取行,可以回复UIScrollViewDelegate确定表格滚动何时完成的方法,触发行的预取。您可以使用 SDWebImagePrefetcher 执行预取。 (在我最初的回答中,我对这个有用的类(class)有点不屑一顾,但现在它似乎工作得相对好):
- (void)viewDidLoad
{
[super viewDidLoad];
// the details don't really matter here, but the idea is to fetch data,
// call `reloadData`, and then prefetch the other images
NSURL *url = [NSURL URLWithString:kUrlWithJSONData];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
if (connectionError) {
NSLog(@"sendAsynchronousRequest error: %@", connectionError);
return;
}
self.objects = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
[self.tableView reloadData];
[self prefetchImagesForTableView:self.tableView];
}];
}
// some of the basic `UITableViewDataDelegate` methods have been omitted because they're not really relevant
cellForRowAtIndexPath (不完全相关,但只是表明如果您使用 SDWebImagePrefetcher ,则不必弄乱 cellForRowAtIndexPath :- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = @"Cell";
CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
NSAssert([cell isKindOfClass:[CustomCell class]], @"cell should be CustomCell");
[cell.customImageView setImageWithURL:[self urlForIndexPath:indexPath] placeholderImage:nil];
[cell.customLabel setText:[self textForIndexPath:indexPath]];
return cell;
}
UIScrollViewDelegate滚动完成时方法预取更多行- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
// if `decelerate` was true for `scrollViewDidEndDragging:willDecelerate:`
// this will be called when the deceleration is done
[self prefetchImagesForTableView:self.tableView];
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
// if `decelerate` is true, then we shouldn't start prefetching yet, because
// `cellForRowAtIndexPath` will be hard at work returning cells for the currently visible
// cells.
if (!decelerate)
[self prefetchImagesForTableView:self.tableView];
}
NSIndexPath可见单元格两侧的单元格的值,获取它们的图像 URL,然后预取该数据。/** Prefetch a certain number of images for rows prior to and subsequent to the currently visible cells
*
* @param tableView The tableview for which we're going to prefetch images.
*/
- (void)prefetchImagesForTableView:(UITableView *)tableView
{
NSArray *indexPaths = [self.tableView indexPathsForVisibleRows];
if ([indexPaths count] == 0) return;
NSIndexPath *minimumIndexPath = indexPaths[0];
NSIndexPath *maximumIndexPath = [indexPaths lastObject];
// they should be sorted already, but if not, update min and max accordingly
for (NSIndexPath *indexPath in indexPaths)
{
if (indexPath.section < minimumIndexPath.section || (indexPath.section == minimumIndexPath.section && indexPath.row < minimumIndexPath.row)) minimumIndexPath = indexPath;
if (indexPath.section > maximumIndexPath.section || (indexPath.section == maximumIndexPath.section && indexPath.row > maximumIndexPath.row)) maximumIndexPath = indexPath;
}
// build array of imageURLs for cells to prefetch
NSMutableArray *imageURLs = [NSMutableArray array];
indexPaths = [self tableView:tableView priorIndexPathCount:kPrefetchRowCount fromIndexPath:minimumIndexPath];
for (NSIndexPath *indexPath in indexPaths)
[imageURLs addObject:[self urlForIndexPath:indexPath]];
indexPaths = [self tableView:tableView nextIndexPathCount:kPrefetchRowCount fromIndexPath:maximumIndexPath];
for (NSIndexPath *indexPath in indexPaths)
[imageURLs addObject:[self urlForIndexPath:indexPath]];
// now prefetch
if ([imageURLs count] > 0)
{
[[SDWebImagePrefetcher sharedImagePrefetcher] prefetchURLs:imageURLs];
}
}
NSIndexPath 的实用方法对于可见单元格之前的行以及可见单元格之后的行:/** Retrieve NSIndexPath for a certain number of rows preceding particular NSIndexPath in the table view.
*
* @param tableView The tableview for which we're going to retrieve indexPaths.
* @param count The number of rows to retrieve
* @param indexPath The indexPath where we're going to start (presumably the first visible indexPath)
*
* @return An array of indexPaths.
*/
- (NSArray *)tableView:(UITableView *)tableView priorIndexPathCount:(NSInteger)count fromIndexPath:(NSIndexPath *)indexPath
{
NSMutableArray *indexPaths = [NSMutableArray array];
NSInteger row = indexPath.row;
NSInteger section = indexPath.section;
for (NSInteger i = 0; i < count; i++) {
if (row == 0) {
if (section == 0) {
return indexPaths;
} else {
section--;
row = [tableView numberOfRowsInSection:section] - 1;
}
} else {
row--;
}
[indexPaths addObject:[NSIndexPath indexPathForRow:row inSection:section]];
}
return indexPaths;
}
/** Retrieve NSIndexPath for a certain number of following particular NSIndexPath in the table view.
*
* @param tableView The tableview for which we're going to retrieve indexPaths.
* @param count The number of rows to retrieve
* @param indexPath The indexPath where we're going to start (presumably the last visible indexPath)
*
* @return An array of indexPaths.
*/
- (NSArray *)tableView:(UITableView *)tableView nextIndexPathCount:(NSInteger)count fromIndexPath:(NSIndexPath *)indexPath
{
NSMutableArray *indexPaths = [NSMutableArray array];
NSInteger row = indexPath.row;
NSInteger section = indexPath.section;
NSInteger rowCountForSection = [tableView numberOfRowsInSection:section];
for (NSInteger i = 0; i < count; i++) {
row++;
if (row == rowCountForSection) {
row = 0;
section++;
if (section == [tableView numberOfSections]) {
return indexPaths;
}
rowCountForSection = [tableView numberOfRowsInSection:section];
}
[indexPaths addObject:[NSIndexPath indexPathForRow:row inSection:section]];
}
return indexPaths;
}
SDWebImage及其SDWebImagePrefetcher正在做繁重的工作。SDWebImage 做一些预取,您可以执行以下操作:setImageWithURL称呼:- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(@"%s", __FUNCTION__);
static NSString *cellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
TableModelRow *rowData = self.objects[indexPath.row];
cell.textLabel.text = rowData.title;
[cell.imageView setImageWithURL:rowData.url
placeholderImage:[UIImage imageNamed:@"placeholder.png"]
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType) {
[self prefetchImagesForTableView:tableView];
}];
return cell;
}
prefetcher这里的例程(我希望 iOS 有一些不错的 didFinishTableRefresh 委托(delegate)方法),但它可以工作,即使它调用例程的次数比我真正想要的要多。我只是确保下面的例程确保它不会发出多余的请求。 const NSInteger kPrefetchRowCount = 10;
- (void)prefetchImagesForTableView:(UITableView *)tableView
{
// determine the minimum and maximum visible rows
NSArray *indexPathsForVisibleRows = [tableView indexPathsForVisibleRows];
NSInteger minimumVisibleRow = [indexPathsForVisibleRows[0] row];
NSInteger maximumVisibleRow = [indexPathsForVisibleRows[0] row];
for (NSIndexPath *indexPath in indexPathsForVisibleRows)
{
if (indexPath.row < minimumVisibleRow) minimumVisibleRow = indexPath.row;
if (indexPath.row > maximumVisibleRow) maximumVisibleRow = indexPath.row;
}
// now iterate through our model;
// `self.objects` is an array of `TableModelRow` objects, one object
// for every row of the table.
[self.objects enumerateObjectsUsingBlock:^(TableModelRow *obj, NSUInteger idx, BOOL *stop) {
NSAssert([obj isKindOfClass:[TableModelRow class]], @"Expected TableModelRow object");
// if the index is within `kPrefetchRowCount` rows of our visible rows, let's
// fetch the image, if it hasn't already done so.
if ((idx < minimumVisibleRow && idx >= (minimumVisibleRow - kPrefetchRowCount)) ||
(idx > maximumVisibleRow && idx <= (maximumVisibleRow + kPrefetchRowCount)))
{
// my model object has method for initiating a download if needed
[obj downloadImageIfNeeded];
}
}];
}
SDWebImage ,我保留一个weak指向我的 TableModelRow 中的网络图像操作的指针类(支持我的表的各个行的模型类):@property (nonatomic, weak) id<SDWebImageOperation> webImageOperation;
downloadImageIfNeeded如果还没有,例程开始下载(您可以看到为什么使 weak 如此重要......我正在检查该行是否在开始另一个操作之前已经有待处理的操作)。我没有对下载的图像做任何事情(出于调试目的,没有记录下载完成的事实),而只是下载并让 SDImageWeb为我跟踪缓存的图像,所以当 cellForRowAtIndexPath稍后在用户向下滚动时请求图像,它就在那里,准备就绪并等待。- (void)downloadImageIfNeeded
{
if (self.webImageOperation)
return;
SDWebImageManager *imageManager = [SDWebImageManager sharedManager];
self.webImageOperation = [imageManager downloadWithURL:self.url
options:0
progress:nil
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished) {
NSLog(@"%s: downloaded %@", __FUNCTION__, self.title);
// I'm not going to do anything with the image, but `SDWebImage` has now cached it for me
}];
}
imageManager.imageCache 可能更可靠。实例方法queryDiskCacheForKey首先,但是在进行了一些测试之后,它看起来并不需要(无论如何downloadWithURL 为我们做了这件事)。 SDImageWeb图书馆确实有 SDWebImagePrefetcher类(见 the documentation)。类的名称非常有前途,但是查看代码,完全尊重其他优秀的库,这对我来说感觉不是很健壮(例如,它是一个简单的 URL 列表,如果你再做一次,它取消了先前的列表,没有“添加到队列”或类似的概念)。这是一个很有前途的想法,但执行起来有点弱。当我尝试它时,我的用户体验明显受到影响。SDWebImagePrefetcher (至少在它得到改进之前),并坚持我的基本预取技术。它不是非常复杂,但它似乎工作。
关于ios - SDWebImage 在滚动之前不会加载远程图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15701556/
设置:狂欢ruby1.9.2高线(1.6.13)描述:我已经相当习惯在其他一些项目中使用highline,但已经有几个月没有使用它了。现在,在Ruby1.9.2上全新安装时,它似乎不允许在同一行回答提示。所以以前我会看到类似的东西:require"highline/import"ask"Whatisyourfavoritecolor?"并得到:Whatisyourfavoritecolor?|现在我看到类似的东西:Whatisyourfavoritecolor?|竖线(|)符号是我的终端光标。知道为什么会发生这种变化吗? 最佳答案
鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende
我在我的Rails项目中使用Pow和powifygem。现在我尝试升级我的ruby版本(从1.9.3到2.0.0,我使用RVM)当我切换ruby版本、安装所有gem依赖项时,我通过运行railss并访问localhost:3000确保该应用程序正常运行以前,我通过使用pow访问http://my_app.dev来浏览我的应用程序。升级后,由于错误Bundler::RubyVersionMismatch:YourRubyversionis1.9.3,butyourGemfilespecified2.0.0,此url不起作用我尝试过的:重新创建pow应用程序重启pow服务器更新战俘
我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("
我有一个服务模型/表及其注册表。在表单中,我几乎拥有服务的所有字段,但我想在验证服务对象之前自动设置其中一些值。示例:--服务Controller#创建Action:defcreate@service=Service.new@service_form=ServiceFormObject.new(@service)@service_form.validate(params[:service_form_object])and@service_form.saverespond_with(@service_form,location:admin_services_path)end在验证@ser
这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下
我正在尝试解析一个文本文件,该文件每行包含可变数量的单词和数字,如下所示:foo4.500bar3.001.33foobar如何读取由空格而不是换行符分隔的文件?有什么方法可以设置File("file.txt").foreach方法以使用空格而不是换行符作为分隔符? 最佳答案 接受的答案将slurp文件,这可能是大文本文件的问题。更好的解决方案是IO.foreach.它是惯用的,将按字符流式传输文件:File.foreach(filename,""){|string|putsstring}包含“thisisanexample”结果的
我一直致力于让我们的Rails2.3.8应用程序在JRuby下正确运行。一切正常,直到我启用config.threadsafe!以实现JRuby提供的并发性。这导致lib/中的模块和类不再自动加载。使用config.threadsafe!启用:$rubyscript/runner-eproduction'pSim::Sim200Provisioner'/Users/amchale/.rvm/gems/jruby-1.5.1@web-services/gems/activesupport-2.3.8/lib/active_support/dependencies.rb:105:in`co
我有带有Logo图像的公司模型has_attached_file:logo我用他们的Logo创建了许多公司。现在,我需要添加新样式has_attached_file:logo,:styles=>{:small=>"30x15>",:medium=>"155x85>"}我是否应该重新上传所有旧数据以重新生成新样式?我不这么认为……或者有什么rake任务可以重新生成样式吗? 最佳答案 参见Thumbnail-Generation.如果rake任务不适合你,你应该能够在控制台中使用一个片段来调用重新处理!关于相关公司
我们目前正在为ROR3.2开发自定义cms引擎。在这个过程中,我们希望成为我们的rails应用程序中的一等公民的几个类类型起源,这意味着它们应该驻留在应用程序的app文件夹下,它是插件。目前我们有以下类型:数据源数据类型查看我在app文件夹下创建了多个目录来保存这些:应用/数据源应用/数据类型应用/View更多类型将随之而来,我有点担心应用程序文件夹被这么多目录污染。因此,我想将它们移动到一个子目录/模块中,该子目录/模块包含cms定义的所有类型。所有类都应位于MyCms命名空间内,目录布局应如下所示:应用程序/my_cms/data_source应用程序/my_cms/data_ty