Wrapping a C creation method that returns object by reference?

I'm doing a lot of raw image data manipulation, and for visualization purposes I tend to need to get high-level images out. This means going through one of several "raw" buffer types offered by macOS. In my case, CVPixelBuffer seems most promising because it supports the widest array of pixel formats.

Now, what I'm doing doesn't need to be an initializer, but I wanted to try to understand if there was a way to accomplish this in an init(), and if not, why not.

I wanted to make an initializer to help with this, but it seems Swift won't let me for two reasons. 1), I can't seem to create initializers in extensions (not sure why in this case, I've done it many times before); and 2) self is read-only so I can't assign it from the creation func.

This is CVPixelBufferCreateWithBytes:

func CVPixelBufferCreate(_ allocator: CFAllocator?, 
                       _ width: Int, 
                       _ height: Int, 
                       _ pixelFormatType: OSType, 
                       _ pixelBufferAttributes: CFDictionary?, 
                       _ pixelBufferOut: UnsafeMutablePointer<CVPixelBuffer?>) -> CVReturn

I tried to to write this:

extension CVPixelBuffer
{
    init?(buffer: UnsafeMutableRawPointer,
            width: Int, height: Int,
            pixelFormatType: OSType, bytesPerRow: Int,
            pixelBufferAttributes: [String:Any]?)
    {
        var pb: CVPixelBuffer?
        let result = CVPixelBufferCreateWithBytes(kCFAllocatorDefault,
                                        Int(width), Int(height),
                                        kCVPixelFormatType_OneComponent16,
                                        buffer, bytesPerRow,
                                        { (inMutableP, inP) in
                                            inP?.deallocate()
                                        }, nil, nil, &pb)
        if result != 0  {
            return nil
        }
        
        self = pb
    }
}

Well, the first time through I tried passing &self. I didn't think these would work, but you can do it in Objective-C, and I could swear I saw swift code assign to self somewhere.

Anyway, two errors:

  1. Designated initializer cannot be declared in an extension of 'CVBuffer'
    1a. Designated initializer for 'CVBuffer' cannot delegate (with 'self.init')
  2. Cannot assign to value: 'self' is immutable

Is there any way to wrap CVPixelBufferCreateWithBytes() in an initializer like this?

That's right, for classes, you can only define convenient initializer, i.e., those that call another self.init.

self in init is actually mutable. The problem is that for classes, you cannot reassign self to anything. at all.

Closest you can get is probably a factory method.

1 Like

So, that was the first thing I tried, but it complained about convenience in this context too.

Pity. That was a pretty cool thing in Objective-C.

There is a workaround for this in the general case:

protocol SelfAssignableInit {
    init(assigningFrom other: Self)
}

extension SelfAssignableInit {
    init(assigningFrom other: Self) {
        self = other
    }
}

extension CVPixelBuffer: SelfAssignableInit {}

https://forums.swift.org/t/allow-self-x-in-class-convenience-initializers/ from a few years back gives more details/discussion.

In this particular case, however, you may have another issue: I don't think you can write convenience inits for CoreFoundation types, and I think that includes CVPixelBuffer. At a guess, that's what you're running into for your first issue.

4 Likes
Terms of Service

Privacy Policy

Cookie Policy