Subscripting UIKit array properties using withUnsafeBufferPointer

Basically, I've tried to implement safe indexing for internal use. I know that Swift's array subscripting makes a bound check and I've wanted to avoid it by using withUnsafeBufferPointer. But I've faced not expected behavior with UIKit element:

extension Array {
    @inlinable
    public subscript(safe index: Index) -> Element? {
        get {
            guard
                index >= startIndex,
                index < endIndex
            else { return nil }
            return withUnsafeBufferPointer { pointer in
                return pointer[index] // error hapends here
            }
        }
        set {
            guard
                index >= startIndex,
                index < endIndex,
                let value = newValue
            else { return }
            return withUnsafeMutableBufferPointer { pointer in
                pointer[index] = value
            }
        }
    }
}

let array = [0, 1, 2, 3]
// ok
print(array[safe: 0]) 


let stack = UIStackView(arrangedSubviews: [UIView(), UIView()])

// Swift/ArrayBuffer.swift:319: Fatal error: unsupported
// same error for tabBar 
// didn't check other UIKit elements but I guess same exception will be raised 
print(stack.arrangedSubviews[safe: 0]) 

I've checked the source code of ArrayBuffer and find out that somehow that code calls method that shouldn't be called

  public __consuming func _copyContents(
    initializing buffer: UnsafeMutableBufferPointer<Element>
  ) -> (Iterator,UnsafeMutableBufferPointer<Element>.Index) {
    // This customization point is not implemented for internal types.
    // Accidentally calling it would be a catastrophic performance bug.
    fatalError("unsupported")
  }

For me, this looks like a bug, and I don't really know if it's on a Swift side or UIKit one. If someone can explain to me why it's work like that I'll glad to hear it :innocent:

1 Like

It’s a bug with certain bridged arrays: Fatal error: unsupported: file Swift/ArrayBuffer.swift, line 231 · Issue #27 · apple/swift-collections · GitHub

That said, if you’re doing your own bounds-checking, you don’t gain anything by using UnsafeBufferPointer - and in general, you should really avoid unsafe types as much as you possibly can. Swift is designed to be memory-safe; the Unsafe types are a hole in that model and should be used very sparingly and ideally not at all.

2 Likes
Terms of Service

Privacy Policy

Cookie Policy