-1

When generating a CGImage one can choose between an initializer using JPEG-encoded data, PNG-encoded data or just data. I'm generating an image from a Data object containing 16 bit grayscale values. The initializer required a CGDataProvider which could be Sequential-Access or Direct-Access Data Provider. Under the Sequential-Access we have only one initializer:

  • Creates a sequential-access data provider

Under the Direct-Access we have multiple initializers but let's focus on a subset:

  • Creates a direct-access data provider
  • Creates a direct-access data provider that uses data your program supplies
  • Creates a data provider that reads from a CFData object

We can definitely notice that the last item in the Direct-Access list missing the "direct-access" term in its definition.

First question: I understand the notion of sequential and direct access to memory, but can someone give me a more precise definition taking into consideration Swift's behaviour?

Let's move on. I have two different Data objects in my subclass of UIViewController. I'm calling from the main dispatch queue to a static function I have in a helper class. This helper function gets the Data and this is where I'm creating the CGImage and return it to the view controller. The view controller saves each image in a separate property variable.

This is where things get weird:

Using "Creates a data provider that reads from a CFData object" - works!

But I don't want to use CoreFoundation inside an iOS project and create a CFData object (which probably copies the buffer into a new one)

Using "Creates a direct-access data provider that uses data your program supplies" - works!

I'm accessing the raw buffer using withUnsafeBytes which provides me an UnsafeRawBufferPointer inside a closure.

But if I change the access to the Data using withUnsafeMutableBytes - the second image returned to the view controller overrides the first image!

I tried to debug it with XCode and each image is actually generated appropriately inside the helper function, but when the second image returned to the view controller, the first image is changed.

Second question: What could create this weird behaviour?

There are a lot of participants in this process and I think I did everything I could to try and resolve it. Any feedback would be kindly appreciated.

Yonatan Vainer
  • 453
  • 5
  • 15

1 Answers1

2

"Direct-access" just means all the bytes are always available, and you can access them in any order.

"Sequential-access" means that the bytes are in a stream, and you can only read them at the current "head", skip forward some number of bytes, or rewind all the way to the beginning. You can't just jump anywhere you want. For example, if you're streaming data from the network, you may never have all the data in memory at the same time.

CFData is always direct-access, so there is no need to call this out in the definition. Nothing here relates to Swift. These are all Core Foundation (i.e. "C") data structures. Swift can bridge Data to CFData, but these interfaces long predate Swift.

But I don't want to use CoreFoundation inside an iOS project and create a CFData object (which probably copies the buffer into a new one)

Data can bridge to CFData without copying. You just need to add as CFData. Data is a Foundation overlay for NSData, and NSData toll-free bridges to CFData.

let data = Data(...)
let source = CGImageSourceCreateWithData(data as CFData, nil)

To your question about the particular behavior, I'm sure you have a bug, but we'd have to see the code. If I had to guess, I'd suspect you're relying on object lifetimes that aren't promised. This is a common mistake when working with Unsafe types. But if you already have a Data, I wouldn't bother with custom CGImageSources. That's a lot of work that generally isn't needed if you already have all the data in memory. (If you still want to do that, post some code and I'm sure we can walk you through it. It's not that hard, it's just generally not necessary, and a bit fiddly in Swift.)

Rob Napier
  • 286,113
  • 34
  • 456
  • 610