Last active
October 7, 2024 22:25
-
-
Save Amzd/8f0d4d94fcbb6c9548e7cf0c1493eaff to your computer and use it in GitHub Desktop.
StateObject that works in iOS 13
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() | |
} | |
} |
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.
[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)
@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
[Is there a way to conditionally use @StateObject while targeting iOS 13 but use apple's @StateObject in iOS 14