菜鸟教程小白 发表于 2022-12-12 09:14:54

ios - 应用程序分配 650MB 的 RAM 到 CG 光栅数据加载 ~250 UIImages


                                            <p><p>我目前正在开发一个 iPad 应用程序,它将 ~250 个 <code>UIImage</code>s 加载到 <code>UIButton</code>s 中(然后更改颜色),创建一个世界地图 - 每个国家有自己的按钮和相应的图像 - 加载游戏时。我遇到的问题是,在视网膜 iPad 上,应用程序在加载图像时使用了大约 650MB 的 RAM,这太疯狂了。 </p>

<p>当应用最初加载游戏时,它使用以下代码将图像设置为按钮(<code>Territory</code> 是 <code>UIButton</code> 的子类)。</p>

<pre><code>//Initialize the arrays of each territory and add an action to the territory
    for (int i = (int)territoryArray.count - 1; i &gt;= 0; i--) {

      @autoreleasepool {

            //Cast the object into a territory object
            Territory *ter = (Territory *);

            //Set the territory&#39;s image
             pathForResource:, i + 1] ofType:nil]] forState:UIControlStateNormal];
      }
    }
</code></pre>

<p>这会导致以下内存使用情况。峰值在循环运行时出现,但即使 block 被 <code>@autoreleasepool</code> 包围也不会消失。注意 <code>ImageIO</code> 正在使用内存:</p>

<p> <img src="/image/ch0W5.png" alt="Without coloring"/> </p>

<p>该屏幕截图是在领土的图像文件中具有原始颜色时拍摄的。我正在使用 <code>MGImageUtilities</code> 中的 <code>UIImage+Tint</code> 库为图像着色。使用该库时,使用以下代码:</p>

<pre><code> imageTintedWithColor: floatValue]/255.0 green:[ floatValue]/255.0 blue:[ floatValue]/255.0 alpha:1.0]] forState:UIControlStateNormal];
</code></pre>

<p>在加载所有图像后,在另一个循环中使用此代码(在另一个函数中用 <code>@autoreleasepool</code> 括起来)时,会发生以下内存使用情况。请注意,<code>CG raster data</code> 正在使用内存。</p>

<p> <img src="/image/Z9YWp.png" alt="With coloring"/> </p>

<p>不知道为什么使用内存的东西不一样。</p>

<p>我 <a href="http://devforums.apple.com/message/949029" rel="noreferrer noopener nofollow">posted a thread</a>在 Apple Developer Forums 上,这也是该问题的前奏。</p>

<p>我还联系了 Apple Developer TSI,他们建议使用“延迟图像加载”。我对此进行了调查,但我还没有找到在非基于页面的 <code>UIScrollView</code> 上执行此操作的方法。</p>

<p>在这一点上,我几乎不知道如何解决这个问题。经过数小时的努力,我已经尝试了我能想到的一切,但我似乎无法提出任何可行的解决方案。如果有人可以帮助我,我将不胜感激。如果您想查看更多信息或代码,请告诉我,我很乐意发布。提前感谢您的帮助。</p>

<p><strong>编辑:</strong></p>

<p>我一直在试验,我正在使用 <code>scrollViewDidScroll:</code> 中的以下代码。它似乎正在工作,但内存没有被释放,它继续上升。想法?</p>

<pre><code>CGRect currentF = ;

    //Loop through all territories and determine which need to be rendered
    for (int i = (int)territoryArray.count - 1; i &gt;= 0; i--) {

      @autoreleasepool {

            //See if the territory is on-screen
            if (CGRectIntersectsRect(currentF, [ frame])) {

                //See if the territory needs an image
                if ([ image] == nil) {

                  //Set the territory&#39;s image
                  [ setImage: pathForResource:, i + 1] ofType:nil]] forState:UIControlStateNormal];
                }
            } else {
                //Remove the territory&#39;s image, it is off-screen
                [ setImage:nil forState:UIControlStateNormal];
            }
      }
    }
</code></pre></p>
                                    <br><hr><h1><strong>Best Answer-推荐答案</ strong></h1><br>
                                            <p><p>我发现,当我必须将图像加载到 ScrollView 中时,为了避免内存问题和应用程序的一般响应能力,您需要逐步加载图像。这意味着,尽管您在 ScrollView 中可能有 250 张图像,但您无法同时看到它们。所以加载他可见的瓷砖,以及它下面的几行。您可以在滚动时加载其余部分。</p>

<p>编辑:这是一个例子。</p>

<pre><code>-(void)scrollViewDidScroll:(UIScrollView *)myScrollView {

int currentPage = (1 + myScrollView.contentOffset.x / kXItemSpacingIphone);
for (ItemView* itemView in ){
    if (itemView.tag &gt;= currentPage-1 &amp;&amp; itemView.tag &lt;= currentPage+1)
    {
      //keep it visible
      if (!itemView.isLoaded) {
            ];
      }
    }
    else
    {
      //hide it
      if (itemView.isLoaded) {
            ;
      }

    }
}
</code></pre>

<p>}</p>

<p>上面的代码将加载可见页面上方页面和下方页面的图像。我发现页面滚动有点不稳定。但是我正在从网络加载图像,因此您可能会发现这很好用。 </p>

<p>祝你好运!</p>

<p>编辑 2:</p>

<p>如果您的 ScrollView 没有设置为分页,试试这个。</p>

<ol>
<li><p>让我的 ViewController 成为 ScrollView 的代表(如果你在代码中这样做,你必须修改你的 ViewController 的 .h 来说明它符合 UIScrollViewDelegate)。</p></li>
<li><p>定义一个scrollViewDidScroll方法,(a)确定 ScrollView 可见部分的框架; (b) 确定哪些 subview 与该可见部分相交; (c) 加载可见的项目,卸载不可见的项目。</p></li>
</ol>

<p>它最终会看起来像这样。</p>

<pre><code>    - (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    // Determine the frame of the visible portion of the scrollview.

    CGRect visibleScrollViewFrame = scrollView.bounds;
    visibleScrollViewFrame.origin = scrollView.contentOffset;

    // Now iterate through the various items, remove the ones that are not visible,
    // and show the ones that are.

    for (Item *itemObject in self.itemCollection)
    {
      // Determine the frame within the scrollview that the object does (or
      // should) occupy.

      CGRect itemObjectFrame = ;

      // see if those two frames intersect

      if (CGRectIntersectsRect(visibleScrollViewFrame, itemObjectFrame))
      {
            // If it&#39;s visible, then load it (if it&#39;s not already).
            // Personally, I have my object have a boolean property that
            // tells me whether it&#39;s loaded or not. You can do this any
            // way you want.

            if (!itemObject.loaded)
                ;
      }
      else
      {
            // If not, go ahead and unload it (if it&#39;s loaded) to conserve memory.

            if (itemObject.loaded)
                ;
      }
    }
}
</code></pre>

<blockquote>
<p><a href="https://stackoverflow.com/questions/12826530/ios-not-allocating-too-much-memory-at-once" rel="noreferrer noopener nofollow">Reference</a></p>
</blockquote></p>
                                   
                                                <p style="font-size: 20px;">关于ios - 应用程序分配 650MB 的 RAM 到 CG 光栅数据加载 ~250 UIImages,我们在Stack Overflow上找到一个类似的问题:
                                                        <a href="https://stackoverflow.com/questions/22952027/" rel="noreferrer noopener nofollow" style="color: red;">
                                                                https://stackoverflow.com/questions/22952027/
                                                        </a>
                                                </p>
                                       
页: [1]
查看完整版本: ios - 应用程序分配 650MB 的 RAM 到 CG 光栅数据加载 ~250 UIImages