CGColor内部

loc*_*ope 6 c core-foundation opaque-pointers ios

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

typedef struct CGColor {
        CFRuntimeBase obj;

        CFTypeID colorID;
        CGColorSpaceRef colorSpace;
        CGPatternRef pattern;
        size_t numberOfComponents;
        CGFloat *components;
} *CGColorRef;
Run Code Online (Sandbox Code Playgroud)

(colorID字段由free quartz命名为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
Run Code Online (Sandbox Code Playgroud)

对于当前的颜色图形上下文操作,ripc_GetColor()计算当前笔触/填充颜色的一些变换,并使用此颜色的referenceID和colorID缓存这些变换.

因此,对于下一个图形上下文操作,ripc_GetColor()将先前缓存的当前引用和colorID值进行比较,以跳过已为最后一个图形上下文操作缓存的颜色转换.

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

但是,标识符可以用于单个对象及其引用,因此仅比较ID就足够了.但是,使用了refs和id.我不认为工程师忽视了这么简单和至关重要的事情.

所以,我试图找出比较id和refs的必要性,同时只比较id就足够了.

是否遗留了以前的方法,所以不能完全放弃?

Quu*_*one 1

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

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

    if (c == cached_c && c->colorID == cached_colorID) ...
Run Code Online (Sandbox Code Playgroud)

而不仅仅是

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

    if (c->colorID == cached_colorID) ...
Run Code Online (Sandbox Code Playgroud)

?嗯,有两个明显的原因是

  • 随机存取存储器不是随机存取。取消引用c可能是一个缓慢的操作(缓存未命中会浪费许多纳秒),因此如果我们可以通过预先进行廉价的指针比较来节省 90% 的纳秒时间,那么我们就这样做。

  • 你如何初始化cached_colorID?在上面的第一个实现中,如果我们假设用户尊重 API 契约并始终传入非 null c,那么一旦我们知道c== cached_c,那么我们也知道这一点cached_c != NULL,因此我们在 中具有有意义的值cached_colorID。在第二个实现中,如果用户传入的第一个c碰巧有c->colorID == 0,那么我们会错误地认为我们以前见过它,然后就会发生疯狂的狂欢。

我不知道这是否是苹果公司做你所看到的事情的原因......但它们看起来很有可能,不是吗?