【问题标题】:CGColor internalsCGColor内部
【发布时间】:2013-10-26 14:31:56
【问题描述】:

我希望通过这项研究了解 CoreFoundation CGColor 对象的内部结构。我可以从免费的石英项目中找到一个 CGColor 结构的示例定义,它似乎与 IOS 声明相匹配(依赖于我的研究)。

typedef struct CGColor {
        CFRuntimeBase obj;

        CFTypeID colorID;
        CGColorSpaceRef colorSpace;
        CGPatternRef pattern;
        size_t numberOfComponents;
        CGFloat *components;
} *CGColorRef;

(colorID 字段被免费石英命名为 nextID,但我认为它旨在作为 IOS 的颜色的唯一标识符,因此它不是一种下一个标识符。)

持有一个全局线程安全唯一值,对于创建并分配给 colorID 成员的每个 CGColor 对象,该值递增 1。只有未记录的 CGColorGetIdentifier() 函数返回此值。 (我猜测 id 值是单调递增的,它可能会在设备之间转换为校准颜色查找时提高性能,反之亦然。)

我检查了 CoreGraphics 及其资源库。我发现只有 ripc_GetColor (libRIP.A.dylib) 函数调用了 CGColorGetIdentifier() 函数。

CGColorGetIdentifier 的调用堆栈;(希望有助于推断 colorID)

0   com.apple.CoreGraphics CGColorGetIdentifier + 0
1   libRIP.A.dylib          ripc_GetColor + 112
2   libRIP.A.dylib          ripc_DrawGlyphs + 1740
3   com.apple.CoreGraphics  CGContextDelegateDrawGlyphs + 108
4   com.apple.CoreGraphics  drawGlyphs + 284
5   com.apple.CoreGraphics  CGContextShowGlyphsWithAdvances + 208

对于当前颜色图形上下文操作,ripc_GetColor() 计算当前笔触/填充颜色的一些转换,并将这些转换与该颜色的引用和 colorID 一起缓存。

因此,对于下一个图形上下文操作,ripc_GetColor() 比较先前缓存的和当前的参考和 colorID 值,以跳过已经为上一个图形上下文操作缓存的颜色转换。

我们知道释放对象的引用(内存地址)可以在创建另一个对象时使用。所以仅仅检查引用是不够的,相同的颜色对象是有效的,但我们需要比较内容或某种哈希值。因此,我们可以为此目的使用唯一标识符值。

但是,标识符可以用于单个对象及其引用,因此仅比较 id 就足够了。但是,refs 和 ids 都被使用了。我不认为工程师忽略了这样一个简单而关键的事情。

所以,我试图找出比较 ids 和 refs 的必要性,而只比较 ids 就足够了。

它是从以前的方法遗留下来的,所以不能完全放弃吗?

【问题讨论】:

  • 对不起,这与 CFTypeID 无关。
  • 您正在研究实施细节。学术上很有趣,但在生产代码中通常没有用处,除非你发现了一个特定的行为,它的表现非常糟糕,以至于阻碍了你。
  • @bbum 你的评论到底有什么意义?
  • @BrennanVincent。创建依赖于实现细节的代码可能会被破坏。

标签: ios c core-foundation opaque-pointers


【解决方案1】:

如果我理解正确,您是在问为什么有人可能将缓存实现为

void DoSomethingWith(CGColorRef c)
{
    static CGColorRef cached_c = NULL;
    static CFTypeID cached_colorID;

    if (c == cached_c && c->colorID == cached_colorID) ...

而不仅仅是

void DoSomethingWith(CGColorRef c)
{
    static CFTypeID cached_colorID = 0;

    if (c->colorID == cached_colorID) ...

?嗯,两个明显的原因是

  • Random access memory isn't random access. 取消引用c 可能是一个缓慢的操作(缓存未命中会浪费很多纳秒),所以如果我们可以通过预先进行廉价的指针比较来节省 90% 的纳秒时间,那么我们就去做吧。

  • 如何初始化cached_colorID?在上面的第一个实现中,如果我们假设用户尊重 API 合约并且总是传入一个非空的c,那么一旦我们知道c == cached_c,那么我们也知道cached_c != NULL 和因此我们在cached_colorID 中有一个有意义的值。在第二个实现中,如果用户传入的第一个 c 恰好有 c->colorID == 0,那么我们会错误地认为我们以前见过它,然后就会出现疯狂的问题。

我不知道这是否是 Apple 做你所看到的事情的原因......但它们似乎是可靠的可能性,不是吗?

【讨论】:

  • * 首先是第二个原因,它是不相关的,因为 c->colorID 它从 1 开始。 * 关于第一个原因,它是相当明智的。当 refs 和 ids 都相等时,在第一个实现中会有一个额外的比较,但我认为比较比内存读取便宜得多,所以它可以忽略不计!..(我对吗?)当 refs 不相等时,首先实现将只有一个比较,并且不会读取内存。但是,我不知道是否值得优化单个内存读取,而通过转换计算会有一堆内存读取。
猜你喜欢
  • 1970-01-01
  • 2019-09-07
  • 1970-01-01
  • 2021-09-19
  • 1970-01-01
  • 2016-05-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多