Skip to content

Instantly share code, notes, and snippets.

@KaQuMiQ
Created December 12, 2019 14:45
Show Gist options
  • Save KaQuMiQ/0dabbf74e7addf813bde91b6b8bb4226 to your computer and use it in GitHub Desktop.
Save KaQuMiQ/0dabbf74e7addf813bde91b6b8bb4226 to your computer and use it in GitHub Desktop.
Dynamic unowned generic value
@propertyWrapper
internal final class Unowned<Wrapped> {
private let wrapper: Wrapper
fileprivate init(wrapper: Wrapper) {
self.wrapper = wrapper
}
internal var wrappedValue: Wrapped {
get { wrapper.get() }
set { wrapper.set(newValue) }
}
fileprivate struct Wrapper {
fileprivate var get: () -> Wrapped
fileprivate var set: (Wrapped) -> Void
}
}
extension Unowned where Wrapped: AnyObject {
internal convenience init(wrappedValue: Wrapped) {
self.init(wrapper: fromClass(wrappedValue))
}
}
extension Unowned {
internal convenience init(wrappedValue: Wrapped) {
self.init(wrapper: from(wrappedValue))
}
}
fileprivate func fromClass<T: AnyObject>(_ value: T) -> Unowned<T>.Wrapper {
let container = ReferenceContainer<T>(value: value)
return .init(
get: { container.value },
set: { container.value = $0 }
)
}
fileprivate func from<T: Any>(_ value: T) -> Unowned<T>.Wrapper {
let container = ValueContainer<T>(value: value)
return .init(
get: { container.value },
set: { container.value = $0 }
)
}
private final class ReferenceContainer<Value: AnyObject> {
unowned var value: Value
init(value: Value) {
self.value = value
}
}
private final class ValueContainer<Value> {
var value: Value
init(value: Value) {
self.value = value
}
}
@KaQuMiQ
Copy link
Author

KaQuMiQ commented Dec 12, 2019

Sample:

class ClassToTest { init() {} }
struct StructToTest { init() {} }
struct TestUnowned {
  @Unowned var unownedClass: ClassToTest = ClassToTest()
  @Unowned var unownedStruct: StructToTest = StructToTest()
}
---
_ = TestUnowned().unownedStruct // ok
_ = TestUnowned().unownedClass // crash - unowned deallocated

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment