Skip to content

Instantly share code, notes, and snippets.

@Amzd
Last active October 7, 2024 22:25
Show Gist options
  • Save Amzd/8f0d4d94fcbb6c9548e7cf0c1493eaff to your computer and use it in GitHub Desktop.
Save Amzd/8f0d4d94fcbb6c9548e7cf0c1493eaff to your computer and use it in GitHub Desktop.
StateObject that works in iOS 13
import Combine
import PublishedObject // https://github.com/Amzd/PublishedObject
import SwiftUI
/// A property wrapper type that instantiates an observable object.
@propertyWrapper
public struct StateObject<ObjectType: ObservableObject>: DynamicProperty
where ObjectType.ObjectWillChangePublisher == ObservableObjectPublisher {
/// Wrapper that helps with initialising without actually having an ObservableObject yet
private class ObservedObjectWrapper: ObservableObject {
@PublishedObject var wrappedObject: ObjectType? = nil
init() {}
}
private var thunk: () -> ObjectType
@ObservedObject private var observedObject = ObservedObjectWrapper()
@State private var state = ObservedObjectWrapper()
public var wrappedValue: ObjectType {
if state.wrappedObject == nil {
// There is no State yet so we need to initialise the object
state.wrappedObject = thunk()
// and start observing it
observedObject.wrappedObject = state.wrappedObject
} else if observedObject.wrappedObject == nil {
// Retrieve the object from State and observe it in ObservedObject
observedObject.wrappedObject = state.wrappedObject
}
return state.wrappedObject!
}
public var projectedValue: ObservedObject<ObjectType>.Wrapper {
ObservedObject(wrappedValue: wrappedValue).projectedValue
}
public init(wrappedValue thunk: @autoclosure @escaping () -> ObjectType) {
self.thunk = thunk
}
public mutating func update() {
// Not sure what this does but we'll just forward it
_state.update()
_observedObject.update()
}
}
@TuenTuenna
Copy link

you are a legend!

@BugMonkey
Copy link

[Is there a way to conditionally use @StateObject while targeting iOS 13 but use apple's @StateObject in iOS 14

@malhal
Copy link

malhal commented Mar 15, 2022

If you are using Combine's ObservableObject as the @StateObject you could use Async/await to replace the functionality and that is backwards compatible with iOS 13. Could be tricky without the task(priority:_:) modifier though.

@calvingit
Copy link

[Is there a way to conditionally use @StateObject while targeting iOS 13 but use apple's @StateObject in iOS 14

try this?

@available(iOS 13, obsoleted: 14)

@eccentricyan
Copy link

eccentricyan commented May 17, 2022

@available(iOS 13, obsoleted: 14)

@calvingit this not work
I insert a break point, it also called iOS 13 method...

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