Копирует ли CGDataProviderCopyData () байты?Или просто указатель? - PullRequest
2 голосов
/ 30 апреля 2010

Я использую этот метод в быстрой последовательности так быстро, как только могу, и чем быстрее, тем лучше, поэтому, очевидно, если CGDataProviderCopyData() фактически копирует данные побайтно, то я думаю, что должен быть более быстрый способ прямой доступ к этим данным ... это просто байты в памяти. Кто-нибудь точно знает, копирует ли CGDataProviderCopyData() данные? Или он просто создает новый указатель на существующие данные?

Ответы [ 2 ]

6 голосов
/ 30 апреля 2010

Скопированы байты.

Внутренне создается CFData ( CFDataCreate ) с содержимым поставщика данных. Функция CFDataCreate всегда делает копию.

5 голосов
/ 02 мая 2010

Кто-нибудь наверняка знает, действительно ли CGDataProviderCopyData () копирует данные? Или он просто создает новый указатель на существующие данные?

Это одно и то же. Указатели являются адресами памяти; по определению, если у вас одни и те же данные по двум адресам , это одни и те же данные в двух местах , поэтому вы должны были скопировать их (либо с одного на другой, либо на оба от общего происхождения).

Итак, давайте переформулируем вопрос соответственно:

Или он просто копирует существующий указатель?

Кварц не обязательно может сделать это, потому что поставщики данных не обязательно предоставляют существующий указатель , поскольку вместо них они могут быть реализованы как по существу потоковые (последовательные) поставщики.

А как насчет провайдеров прямого доступа? Даже тем, кому не нужно выкашливать байт-указатель ; поставщик может просто предложить доступ к диапазону по требованию .

Но что, если он предлагает указатель байта? Ну, документация для этого гласит:

Запрещается перемещать или изменять данные поставщика, пока Quartz не вызовет вашу функцию CGDataProviderReleaseBytePointerCallback.

Так что, возможно, Кварц мог повторно использовать указатель. Но что если вы освободите провайдера данных (вызывая ваш обратный вызов ReleaseBytePointer) до того, как освободите данные?

Это все еще может быть безопасно, если Quartz реализует частный пользовательский подкласс CFData или NSData, который либо реализует сбой, либо принимает на себя задачу вызова ReleaseBytePointer, так что если вы создаете провайдера прямого доступа и создаете из него CFData и освободив провайдера, вы все равно можете использовать объект CFData.

Но это много если. Они , вероятно, просто создают простые старые (bytes-copying-at-time-time) CFData, что делает их действительными проблемами производительности.

Профилируйте это и посмотрите, сколько боли это причиняет вам. Если вам нужно о чем-то беспокоиться, тогда вам нужны некоторые решения:

  • Вы могли бы просто реализовать ReleaseBytePointer как неиспользуемое (пустое тело функции) и освободить байты по отдельности, обязательно сделав это после освобождения как поставщика, так и данных. Теоретически, предотвращает выход байтов из-под CFData, если он использует оригинальный указатель байтов, а Quartz не реализует пользовательский подкласс CFData. Немного волосатый К сожалению, Apple не может полагаться на то, что вы делаете это, поэтому я сомневаюсь, что это действительно поможет.
  • Вместо этого обрабатывайте NS / CFData напрямую. Создайте провайдер данных только для того, чтобы передать его в Quartz, а затем отпустите и сразу же забудьте об этом (не владейте им самим).
  • В зависимости от ваших потребностей, вы можете предпочесть сохранить структуру обратных вызовов в переменной экземпляра и вызывать их напрямую для копирования частей данных. Конечно, если это решение работает для вас, у вас все равно не будет проблемы, описанной выше, так как вы не создаете провайдера данных с прямым доступом «здесь вы можете иметь мой указатель байтов».

В документации для CGDataProviderCreateWithCFData не говорится, возвращает ли он провайдер данных с прямым доступом или нет, поэтому вам придется ошибиться, если вы так создаете провайдера данных.

...