开发者

Does CGDataProviderCopyData() actually copy the bytes? Or just the pointer?

开发者 https://www.devze.com 2022-12-28 13:32 出处:网络
I\'m running that method in quick succession as fast as I can, and the fa开发者_JAVA技巧ster the better, so obviously if CGDataProviderCopyData() is actually copying the data byte-for-byte, then I thi

I'm running that method in quick succession as fast as I can, and the fa开发者_JAVA技巧ster the better, so obviously if CGDataProviderCopyData() is actually copying the data byte-for-byte, then I think there must be a faster way to directly access that data...it's just bytes in memory. Anyone know for sure if CGDataProviderCopyData() actually copies the data? Or does it just create a new pointer to the existing data?


The bytes are copied.

Internally a CFData is created (CFDataCreate) with the content of the data provider. The CFDataCreate function always make a copy.


Anyone know for sure if CGDataProviderCopyData() actually copies the data? Or does it just create a new pointer to the existing data?

Those are the same thing. Pointers are memory addresses; by definition, if you have the same data at two addresses, it is the same data in two places, so you must have copied it (either from one to the other or to both from a common origin).

So, let's restate the question accordingly:

Or does it just copy the existing pointer?

Quartz can't necessarily do this, because data providers do not necessarily provide an existing pointer, as they can be implemented as essentially stream-based (sequential) providers instead.

What about direct-access providers? Even those need not cough up a byte pointer; the provider may simply offer range-on-demand access instead.

But what if it does offer a byte pointer? Well, the documentation for that says:

You must not move or modify the provider data until Quartz calls your CGDataProviderReleaseBytePointerCallback function.

So, conceivably, Quartz could reuse the pointer. But what if you release the data provider (causing your ReleaseBytePointer callback to be called) before you release the data?

This could still be safe if Quartz implements a private custom subclass of CFData or NSData that either implements faulting or takes over the job of calling ReleaseBytePointer, so that if you create a direct-access provider and create a CFData from it and release the provider, you can still use the CFData object.

But that's a lot of ifs. They probably just create a plain old (bytes-copying-at-creation-time) CFData, which makes it a valid performance concern.

Profile it and see how much pain it's causing you. If it's enough to worry about, then you need some solutions:

  • You could just implement ReleaseBytePointer as a no-op (empty function body) and release the bytes separately, making sure to do so after releasing both the provider and the data. In theory, prevents the bytes from going away out from under the CFData if it is using the original bytes pointer and Quartz doesn't implement a custom CFData subclass. A little hairy. Unfortunately, Apple can't really rely on you doing this, so I doubt it will actually help.
  • Handle an NS/CFData directly instead. Create the data provider only to pass it to Quartz, and release it and forget about it immediately thereafter (not own it yourself).
  • Depending on your needs, you may prefer to keep your callbacks structure in an instance variable and call them directly to copy parts of the data. Of course, if this solution works for you, then you don't have the problem described above anyway, since you aren't creating a here-you-can-have-my-bytes-pointer direct-access data provider.

The documentation for CGDataProviderCreateWithCFData doesn't say whether it returns a direct-access data provider or not, so you'll have to err on the side of caution if that's how you're creating your data provider.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号