jjzjj

ios - 在 ScrollView 中延迟加载图像似乎会增加内存

coder 2024-01-19 原文

我懒惰地在 ScrollView 中加载图像。但是,当我滚动内容时,内存分配会增加,而且速度很慢。这是我的代码;

- (void)scrollViewSetUp
{

    self.scrollview.delegate = self;
    self.automaticallyAdjustsScrollViewInsets = NO;
    NSInteger pageCount = self.saleImages.count;


    self.pageControl = [[UIPageControl alloc] initWithFrame:CGRectMake(0.0,0.0,self.view.frame.size.width,40.0)];
    [self.pageControl setNumberOfPages:pageCount];
    [self.pageControl setCurrentPage:0];
    self.pageControl.pageIndicatorTintColor = [UIColor lightGrayColor];
    self.pageControl.currentPageIndicatorTintColor = [UIColor whiteColor];
    [self.pageControl setBackgroundColor:[UIColor clearColor]];


       //Next, you set up the array that holds the UIImageView instances. At first, no pages have been lazily loaded and so you just fill it with the right amount of NSNull objects that are needed – one for each page.
       //You’re using [NSNull null] because it’s a lightweight singleton object that can be added to an array to signify a placeholder.
       //Later on, you’ll use the fact that there is an NSNull in there to know if that page is loaded or not.
        self.pageViews = [[NSMutableArray alloc] init];
        for (NSInteger i = 0; i < pageCount; i++) {
            [self.pageViews addObject:[NSNull null]];
        }

    }

这是我的loadPage: 方法;

-(void)loadPage:(NSInteger)page{
    if (page < 0 || (page >= self.saleImages.count)) {
        //if its outside the range of what you have to display, then do nothing
        return;
    }


    //First, you check if you've already loaded the view. If you haven't, then the object in the pageViews array will be an NSNull ( remember, [NSNull null] is a special singleton which is why == works).
    UIView * pageView = [self.pageViews objectAtIndex:page];

    if ((NSNull*) pageView == [NSNull null]) {

        CGRect frame = self.view.bounds;//set to views bounds instead of scrollviews bounds because it doesnt work very well with autolayout
        frame.origin.x = (frame.size.width+kScrollViewPadding) * page;
        frame.origin.y = 0.0f;

        UIImageView * newPageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:[self.saleImages objectAtIndex:page]]];
        newPageView.contentMode = UIViewContentModeScaleToFill;
        newPageView.frame = CGRectMake(frame.origin.x,frame.origin.y,frame.size.width, frame.size.height);

        [self.scrollview addSubview:newPageView];

    //Finally, you replace the NSNull in pageViews array with the view you've kust created, so that if this page was asked to load again you would now not go into the if statement and instead do nothing since the view for the page has already been created.

        [self.pageViews replaceObjectAtIndex:page withObject:newPageView];
    }


}

这是我的 purgePageloadVisiblePages

-(void)purgePage:(NSInteger)page{
    if (page <0 || page >= self.saleImages.count) {
        //if it's outside the range of what you have to display, then do nothing
        return;
    }

    //Remove a page from the scroll view and reset the container array
    UIView * pageView = [self.pageViews objectAtIndex:page];
    if ((NSNull *)pageView != [NSNull null]) {
        [pageView removeFromSuperview];
        pageView = nil;
        [self.pageViews replaceObjectAtIndex:page withObject:[NSNull null]];

    }

}



-(void)loadVisiblePages{
    //first determine which page is currently visible
    CGFloat pageWidth = self.scrollview.frame.size.width;
    NSInteger page = (NSInteger)floor((self.scrollview.contentOffset.x * 2.0f + pageWidth)/(pageWidth * 2.0f));

    //update the page control
    self.pageControl.currentPage = page;

    //Work out which pages you want to load
    NSInteger firstPage = page -1;
    NSInteger lastPage = page+1;

    //purge anything before the first page
    for (NSInteger i = 0; i<firstPage; i++) {
        [self purgePage:i];
    }

    //load pages in our range
    for (NSInteger i = firstPage; i<=lastPage; i++) {
        [self loadPage:i];
    }

    //purge anything after the last page
    for (NSInteger i = lastPage +1; i<self.saleImages.count; i++) {
        [self purgePage:i];
    }

}

我个人觉得我的purgePage方法有问题。在这里,我从 super View 中删除了 pageView 并将其设置为 nil。我希望有人能提供帮助,因为我正在撕扯我的头发。

编辑 1 在仪器中执行 Generation Analysis 后,UIImage 似乎在增加。罪魁祸首类是 loadPage 和 loadVisiblePages。

编辑 2 @Wain 指出 imageNamed: 做了一些缓存。

最佳答案

您当前正在使用 imageNamed:,它会缓存加载的图像以提高性能。这并不总是理想的,您可能需要避免使用这种方便的方法。

要避免使用 imageNamed:,您需要获取图像的路径(可能来自 bundle),然后使用 initWithContentsOfFile:

请注意,删除所有缓存可能过于极端,您可能希望创建自己的缓存(例如使用字典),您可以控制在任何时候缓存的图像数量。此外,根据您显示图像的方式,您可能希望将一些不同尺寸的图像添加到您的应用中,以便您可以为每种情况加载最合适的尺寸。

另请注意,如果需要,您可以在后台加载图像,然后将图像推送到主线程以更新 UI。

关于ios - 在 ScrollView 中延迟加载图像似乎会增加内存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24651636/

有关ios - 在 ScrollView 中延迟加载图像似乎会增加内存的更多相关文章

  1. ruby-on-rails - Ruby net/ldap 模块中的内存泄漏 - 2

    作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代

  2. ruby - 如何在续集中重新加载表模式? - 2

    鉴于我有以下迁移: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

  3. ruby - 检查数组是否在增加 - 2

    这个问题在这里已经有了答案:Checktoseeifanarrayisalreadysorted?(8个答案)关闭9年前。我只是想知道是否有办法检查数组是否在增加?这是我的解决方案,但我正在寻找更漂亮的方法:n=-1@arr.flatten.each{|e|returnfalseife

  4. ruby - RuntimeError(自动加载常量 Apps 多线程时检测到循环依赖 - 2

    我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("

  5. ruby - 如何验证 IO.copy_stream 是否成功 - 2

    这里有一个很好的答案解释了如何在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返回它复制的字节数,但是当我还没有下

  6. ruby-on-rails - Ruby 中的内存模型 - 2

    ruby如何管理内存。例如:如果我们在执行过程中采用C程序,则以下是内存模型。类似于这个ruby如何处理内存。C:__________________|||stack|||------------------||||------------------|||||Heap|||||__________________|||data|__________________|text|__________________Ruby:? 最佳答案 Ruby中没有“内存”这样的东西。Class#allocate分配一个对象并返回该对象。这就是程序

  7. Ruby 文件 IO 定界符? - 2

    我正在尝试解析一个文本文件,该文件每行包含可变数量的单词和数字,如下所示:foo4.500bar3.001.33foobar如何读取由空格而不是换行符分隔的文件?有什么方法可以设置File("file.txt").foreach方法以使用空格而不是换行符作为分隔符? 最佳答案 接受的答案将slurp文件,这可能是大文本文件的问题。更好的解决方案是IO.foreach.它是惯用的,将按字符流式传输文件:File.foreach(filename,""){|string|putsstring}包含“thisisanexample”结果的

  8. ruby-on-rails - 使用 config.threadsafe 时从 lib/加载模块/类的正确方法是什么!选项? - 2

    我一直致力于让我们的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

  9. ruby-on-rails - 添加回形针新样式不影响旧上传的图像 - 2

    我有带有Logo图像的公司模型has_attached_file:logo我用他们的Logo创建了许多公司。现在,我需要添加新样式has_attached_file:logo,:styles=>{:small=>"30x15>",:medium=>"155x85>"}我是否应该重新上传所有旧数据以重新生成新样式?我不这么认为……或者有什么rake任务可以重新生成样式吗? 最佳答案 参见Thumbnail-Generation.如果rake任务不适合你,你应该能够在控制台中使用一个片段来调用重新处理!关于相关公司

  10. ruby-on-rails - 从应用程序中自定义文件夹内的命名空间自动加载 - 2

    我们目前正在为ROR3.2开发自定义cms引擎。在这个过程中,我们希望成为我们的rails应用程序中的一等公民的几个类类型起源,这意味着它们应该驻留在应用程序的app文件夹下,它是插件。目前我们有以下类型:数据源数据类型查看我在app文件夹下创建了多个目录来保存这些:应用/数据源应用/数据类型应用/View更多类型将随之而来,我有点担心应用程序文件夹被这么多目录污染。因此,我想将它们移动到一个子目录/模块中,该子目录/模块包含cms定义的所有类型。所有类都应位于MyCms命名空间内,目录布局应如下所示:应用程序/my_cms/data_source应用程序/my_cms/data_ty

随机推荐