Skip to content

Instantly share code, notes, and snippets.

@dabrahams
Created May 15, 2020 13:32
Show Gist options
  • Select an option

  • Save dabrahams/d748df73c49f769cbddff007475ff8e0 to your computer and use it in GitHub Desktop.

Select an option

Save dabrahams/d748df73c49f769cbddff007475ff8e0 to your computer and use it in GitHub Desktop.
Rescued very old proposal to redesign Unmanaged
#if false
Changes to Unmanaged
-public struct Unmanaged<Instance : AnyObject> {
// New API: `UnsafeReference(bitPattern:)`.
- public static func fromOpaque(value: COpaquePointer) -> Unmanaged
// New API: `OpaquePointer(bitPattern:)`.
- public func toOpaque() -> COpaquePointer
// New API: `UnsafeReference(retaining:)`.
- public static func passRetained(value: Instance) -> Unmanaged
// New API: `UnsafeReference(withoutRetaining:)`.
- public static func passUnretained(value: Instance) -> Unmanaged
// New API: `UnsafeReference.object`.
- public func takeUnretainedValue() -> Instance
// New API: `UnsafeReference.release()`.
- public func takeRetainedValue() -> Instance
// New API: none.
- public func retain() -> Unmanaged
- public func release()
- public func autorelease() -> Unmanaged
-}
#endif
/// Holds an instance of `Object`, carrying ownership semantics that
/// are not known to the type system and not represented in memory.
///
/// `UnsafeReference<T>` appears as a return type or "out" parameter
/// in [Core
/// Foundation](https://developer.apple.com/library/mac/documentation/CoreFoundation/Reference/CoreFoundation_Collection/)
/// APIs that have not been
/// [annotated](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/WorkingWithCocoaDataTypes.html#//apple_ref/doc/uid/TP40014216-CH6-ID79)
/// with information that allows clients to receive a safe `T`
/// directly.
///
/// An `UnsafeReference` instance `u` can be in one of three
/// "ownership states":
///
/// 1. **Unretained**, where `u.object` yields a valid `T` and will
/// do so through any number of accesses to the `.object`
/// properties of `UnsafeReference` instances. The behavior of
/// `u.release()` is undefined, and any other operations may cause
/// `u` to transition to the *released* state.
///
/// 2. **Retained**, where `u.release()` yields a valid `T` and will
/// do so exactly once. Calling `.release()` transitions `u` and
/// all its copies to the *released* state.
///
/// 3. **Released**, where the behavior of both `u.object` and
/// `u.release()` is undefined. A released `UnsafeReference`
/// can't be used for anything.
///
/// The ownership state of an `UnsafeReference` is not
/// programmatically detectable, so careful documentation is
/// essential. When an `UnsafeReference` is returned in the
/// *retained* state, it is usual to document that "the caller is
/// responsible for releasing the object" or that the API "follows
/// the [create
/// rule](https://developer.apple.com/library/ios/documentation/CoreFoundation/Conceptual/CFMemoryMgmt/Concepts/Ownership.html#//apple_ref/doc/writerid/cfCreateRule)."
/// Other `UnsafeReferences` are assumed to be in the *unretained*
/// state. No API should pass or return a *released*
/// `UnsafeReference`
///
/// The safest way to deal with an instance of `UnsafeReference<T>` is
/// to immediately extract a safe `T` from it exactly once (via
/// `.object` or `.release()` according to its state), and let it go
/// out of scope.
///
/// In the common case where the `UnsafeReference` is a return value,
/// it's best to do the extraction as part of the call, e.g.:
/// ~~~~
/// let names: CFArray = CFHostGetNames(host).object
/// let url: CFURL = CFHTTPMessageCopyRequestURL(message).release()
/// ~~~
///
/// When the `UnsafeReference` is an "out" parameter, you can limit
/// its scope by creating and unwrapping it in a closure:
/// ~~~~
/// var properties: CFPropertyList = try {
/// var properties: UnsafeReference<CFPropertyList>?
/// let error = MIDIObjectGetProperties(midiClient, &properties, true)
/// if error != noErr {
/// throw NSError(domain: "midi", code: Int(error), userInfo: nil)
/// }
/// return properties!.object
/// }()
/// ~~~~
public struct UnsafeReference<Object : AnyObject> {
/// Relinquishes ownership of the `Object` and returns it as a safe
/// reference.
///
/// - Requires: `self` is in the *retained* state.
///
/// - Postcondition: `self` and all its copies are in the *released* state.
///
/// - Warning: Calling `.release()` on an *unretained* or *released*
/// `UnsafeReference` is a severe programming error yielding
/// undefined behavior.
///
/// - Warning: After this method is invoked once, invoking any
/// methods on the same instance, or a copy thereof, is a severe
/// programming error yielding undefined behavior.
public func release() -> Object
/// A safe reference to the `Object` instance.
///
/// - Warning: if `self` is in the *retained* state, you must
/// eventually call `.release()`, or the resulting object will be
/// leaked. It's better to just capture the result of invoking
/// `.release()` in that case.
public var object: Object
/// Creates an unsafe holder of `safeObject` in the *unretained*
/// state; the held object can be accessed via the `.object` property.
public init(withoutRetaining safeObject: Object)
/// Creates an unsafe holder of `safeObject` in the *retained*
/// state; the held object can be accessed via the `release()`
/// method.
public init(retaining safeObject: Object)
/// Creates an unsafe holder of an object having the given
/// `bitPattern`.
public init(bitPattern: OpaquePointer)
}
extension OpaquePointer {
/// Unsafely convert an unmanaged class reference to an opaque
/// C pointer.
///
/// This operation does not change reference counts.
///
/// let str0: CFString = "boxcar"
/// let bits = OpaquePointer(bitPattern: UnsafeReference(withoutRetaining: str0))
/// let str1 = UnsafeReference<CFString>(bitPattern: bits).object
public init<T>(bitPattern bits: UnsafeReference<T>)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment