小编Mus*_*ang的帖子

使用 UICollectionViewLayoutInvalidationContext 优化插入、删除和移动过程中的布局计算

我已经UICollectionViewLayout为我实现了一个自定义UICollectionView,也是一个UICollectionViewLayoutInvalidationContext希望获得良好性能的自定义。

在我的第一个用例中,我有浮动标题,在滚动期间我只使需要滑动的标题无效。

我这样做如下:

  • YESshouldInvalidateLayoutForBoundsChange:.
  • 当我的invalidationContextForBoundsChange:方法被调用时,我通过调用invalidateSupplementaryElementsOfKind:atIndexPaths:.
  • invalidateLayoutWithContext:被调用时,我真的不需要做任何事情,因为使标头无效足以使以下关键事情发生layoutAttributesForSupplementaryViewOfKind:atIndexPath:被调用而不是从prepareLayout.

这很好用。

我的第一个问题是:这个场景如何抑制prepareLayout序列?起初我认为向上下文添加任何数据(在这种情况下是陈旧补充的索引路径)足以让 Apple 假设我知道我在做什么(iOS8-wise)而不是调用prepareLayout. 我知道不再相信这一点,正如您将在下面看到的那样。

我的第二个用例:在实践中,我的数据源几乎总是只在最后添加项目。对于我的布局算法,这意味着较早(indexPath-wise)项目的布局不会因新数据而失效。我不想花时间重新计算我不需要的潜在大量布局属性。因此,当客户端代码调用时,我需要做“正确的事情”:

[collection insertItemsAtIndexPaths: newIndices];
Run Code Online (Sandbox Code Playgroud)

通过注意最早的 indexPath 是什么newIndices并从那里开始重新计算我的布局。几乎总是newIndices从最后开始,并且没有现有的单元格变得陈旧——因此 Apple 应该只询问我的布局对象的新单元格的属性。

但请注意,invalidationContextForBoundsChange:对于插入/删除/移动调用没有类似的方法。所以我无法预先配置我的上下文,并说明什么索引来来去去。

所以在调用内部insertItemsAtIndexPaths:会发生什么:

  • 我的上下文对象被初始化。这发生得早——在invalidateLayout被调用之前。在初始化时,self.invalidateEverything并且self.invalidateDataSourceCounts是 (NO,NO) (并且它们是只读的)。
  • 接下来,我invalidateLayoutWithContext:现在被调用,invalidateDataSourceCounts设置为YES--Apple 只告诉我我的计数已经过时。这是没用的,因为它没有告诉我关于在哪里重新开始布局计算的任何信息。但这是我第一次(也是唯一一次)注意到某事或做某事。
  • 接下来我prepareLayout被叫到——Grrr!我不想重新开始。我不想 …

ios uicollectionview uicollectionviewlayout

6
推荐指数
0
解决办法
792
查看次数

非捕获 lambda 不会降级为函数指针

下面是一个典型的 C 函数,它采用经典函数指针作为参数:

int DoThingy( const char* stuff, int(*helper)(int))
{
    int result = 0;
    //...call helper...
    return result;
}
Run Code Online (Sandbox Code Playgroud)

下面我用一个非捕获 lambda 来调用上面的内容,它神奇地“降级”为函数指针。在“A”处,转换是隐式的。在“B”处,它是明确的。都好。

void UseThingy()
{
    auto lam = [](int)->int {
        return 42;
    };

    int i;
    i = DoThingy( "hello", lam); //"A" works

    int (*ptr)(int) = lam;
    i = DoThingy( "hello", ptr); //"B" works
}
Run Code Online (Sandbox Code Playgroud)

但在这个新示例中,回调函数的签名取决于模板类型:

template <typename T>
int DoThingy2( const char* stuff, int (*helper)(T))
{
    int result = 0;
    //...call helper...
    return result;
}
Run Code Online (Sandbox Code Playgroud)

当我尝试使用上面的这个版本时,“C”行甚至无法编译。然而“D”处的显式版本是有效的。什么?为什么这些不一样?请注意,当我在“E”处给出显式模板参数时,它可以工作,但当然可以<int>从 的签名推断出来lam …

c++ lambda templates

0
推荐指数
1
解决办法
135
查看次数