Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,34 @@ public protocol UserService: ObservableObject {
var observableObjectPublisher: ObservableObjectPublisher { get }
}

/// A type-erased wrapper around a `UserService` that is itself a `UserService` and `ObservableObject`.
public final class AnyUserService: UserService, ObservableObject {
public init(_ userService: some UserService) {
self.userService = userService
objectWillChange = userService
.objectWillChange
.map { _ in () }
.eraseToAnyPublisher()
}

public var userName: String? {
get {
userService.userName
}
set {
userService.userName = newValue
}
}

public var observableObjectPublisher: ObservableObjectPublisher {
userService.observableObjectPublisher
}

public let objectWillChange: AnyPublisher<Void, Never>

private let userService: any UserService
}

@Instantiable(fulfillingAdditionalTypes: [UserService.self])
public final class DefaultUserService: Instantiable, UserService {
public init(stringStorage: StringStorage) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public struct NotesApp: Instantiable, App {
// Memberwise initializer to satisfy SafeDI.
// `public init()` will be generated for this type because this type is a root.
public init(
userService: any UserService,
userService: AnyUserService,
stringStorage: StringStorage,
nameEntryViewBuilder: Instantiator<NameEntryView>,
noteViewBuilder: Instantiator<NoteView>
Expand All @@ -51,17 +51,14 @@ public struct NotesApp: Instantiable, App {
self.stringStorage = stringStorage
self.nameEntryViewBuilder = nameEntryViewBuilder
self.noteViewBuilder = noteViewBuilder
observedUserService = AnyObservableObject(userService)
}

/// A private property that is instantiated when the app is instantiated and manages the User state.
@Instantiated private let userService: any UserService
@ObservedObject @Instantiated(fulfilledByType: "DefaultUserService", erasedToConcreteExistential: true) private var userService: AnyUserService
/// A private property that is instantiated when the app is instantiated and manages the persistence of strings.
@Instantiated private let stringStorage: StringStorage
/// A private property that is instantiated when the app is instantiated and can create a NameEntryView on demand.
@Instantiated private let nameEntryViewBuilder: Instantiator<NameEntryView>
/// A private property that is instantiated when the app is instantiated and can create a NoteView on demand.
@Instantiated private let noteViewBuilder: Instantiator<NoteView>
/// A mechanism for observing updates to the user service.
@ObservedObject private var observedUserService: AnyObservableObject
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import SwiftUI
@MainActor
@Instantiable
public struct NameEntryView: Instantiable, View {
public init(userService: any UserService) {
public init(userService: AnyUserService) {
self.userService = userService
}

Expand All @@ -46,9 +46,9 @@ public struct NameEntryView: Instantiable, View {

@State private var name: String = ""

@Received private let userService: any UserService
@Received private let userService: AnyUserService
}

#Preview {
NameEntryView(userService: DefaultUserService(stringStorage: UserDefaults.standard))
NameEntryView(userService: .init(DefaultUserService(stringStorage: UserDefaults.standard)))
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import SwiftUI
@MainActor
@Instantiable
public struct NoteView: Instantiable, View {
public init(userName: String, userService: any UserService, stringStorage: StringStorage) {
public init(userName: String, userService: AnyUserService, stringStorage: StringStorage) {
self.userName = userName
self.userService = userService
self.stringStorage = stringStorage
Expand All @@ -48,7 +48,7 @@ public struct NoteView: Instantiable, View {
}

@Forwarded private let userName: String
@Received private let userService: any UserService
@Received private let userService: AnyUserService
@Received private let stringStorage: StringStorage

@State private var note: String = ""
Expand All @@ -57,7 +57,7 @@ public struct NoteView: Instantiable, View {
#Preview {
NoteView(
userName: "dfed",
userService: DefaultUserService(stringStorage: UserDefaults.standard),
userService: .init(DefaultUserService(stringStorage: UserDefaults.standard)),
stringStorage: UserDefaults.standard
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
3289B4072BF955720053F2E4 /* Subproject.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3289B4012BF955710053F2E4 /* Subproject.framework */; };
3289B4082BF955720053F2E4 /* Subproject.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3289B4012BF955710053F2E4 /* Subproject.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
3289B40D2BF955A10053F2E4 /* StringStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 324F1ECC2B314DB20001AC0C /* StringStorage.swift */; };
3289B40E2BF955A10053F2E4 /* AnyObservableObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 324F1ED62B3156810001AC0C /* AnyObservableObject.swift */; };
3289B40F2BF955A10053F2E4 /* UserService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 324F1ECA2B314D8D0001AC0C /* UserService.swift */; };
32B72E192D39763900F5EB6F /* SafeDI in Frameworks */ = {isa = PBXBuildFile; productRef = 32B72E182D39763900F5EB6F /* SafeDI */; };
32B72E1B2D39764200F5EB6F /* SafeDI in Frameworks */ = {isa = PBXBuildFile; productRef = 32B72E1A2D39764200F5EB6F /* SafeDI */; };
Expand Down Expand Up @@ -51,7 +50,6 @@
324F1ECC2B314DB20001AC0C /* StringStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringStorage.swift; sourceTree = "<group>"; };
324F1ECE2B314E030001AC0C /* NameEntryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NameEntryView.swift; sourceTree = "<group>"; };
324F1ED12B3150480001AC0C /* NoteView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoteView.swift; sourceTree = "<group>"; };
324F1ED62B3156810001AC0C /* AnyObservableObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyObservableObject.swift; sourceTree = "<group>"; };
32756FE22B24C042006BDD24 /* ExampleMultiProjectIntegration.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ExampleMultiProjectIntegration.app; sourceTree = BUILT_PRODUCTS_DIR; };
32756FE52B24C042006BDD24 /* ExampleApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExampleApp.swift; sourceTree = "<group>"; };
32756FE92B24C044006BDD24 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
Expand Down Expand Up @@ -135,7 +133,6 @@
children = (
324F1ECA2B314D8D0001AC0C /* UserService.swift */,
324F1ECC2B314DB20001AC0C /* StringStorage.swift */,
324F1ED62B3156810001AC0C /* AnyObservableObject.swift */,
3289B4032BF955720053F2E4 /* Subproject.h */,
);
path = Subproject;
Expand Down Expand Up @@ -280,7 +277,6 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
3289B40E2BF955A10053F2E4 /* AnyObservableObject.swift in Sources */,
3289B40D2BF955A10053F2E4 /* StringStorage.swift in Sources */,
3289B40F2BF955A10053F2E4 /* UserService.swift in Sources */,
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public struct NotesApp: Instantiable, App {
// Memberwise initializer to satisfy SafeDI.
// `public init()` will be generated for this type because this type is a root.
public init(
userService: any UserService,
userService: AnyUserService,
stringStorage: StringStorage,
nameEntryViewBuilder: Instantiator<NameEntryView>,
noteViewBuilder: Instantiator<NoteView>
Expand All @@ -52,17 +52,14 @@ public struct NotesApp: Instantiable, App {
self.stringStorage = stringStorage
self.nameEntryViewBuilder = nameEntryViewBuilder
self.noteViewBuilder = noteViewBuilder
observedUserService = AnyObservableObject(userService)
}

/// A private property that is instantiated when the app is instantiated and manages the User state.
@Instantiated private let userService: any UserService
@ObservedObject @Instantiated(fulfilledByType: "DefaultUserService", erasedToConcreteExistential: true) private var userService: AnyUserService
/// A private property that is instantiated when the app is instantiated and manages the persistence of strings.
@Instantiated private let stringStorage: StringStorage
/// A private property that is instantiated when the app is instantiated and can create a NameEntryView on demand.
@Instantiated private let nameEntryViewBuilder: Instantiator<NameEntryView>
/// A private property that is instantiated when the app is instantiated and can create a NoteView on demand.
@Instantiated private let noteViewBuilder: Instantiator<NoteView>
/// A mechanism for observing updates to the user service.
@ObservedObject private var observedUserService: AnyObservableObject
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import SwiftUI
@MainActor
@Instantiable
public struct NameEntryView: Instantiable, View {
public init(userService: any UserService) {
public init(userService: AnyUserService) {
self.userService = userService
}

Expand All @@ -47,9 +47,9 @@ public struct NameEntryView: Instantiable, View {

@State private var name: String = ""

@Received private let userService: any UserService
@Received private let userService: AnyUserService
}

#Preview {
NameEntryView(userService: DefaultUserService(stringStorage: UserDefaults.standard))
NameEntryView(userService: .init(DefaultUserService(stringStorage: UserDefaults.standard)))
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import SwiftUI
@MainActor
@Instantiable
public struct NoteView: Instantiable, View {
public init(userName: String, userService: any UserService, stringStorage: StringStorage) {
public init(userName: String, userService: AnyUserService, stringStorage: StringStorage) {
self.userName = userName
self.userService = userService
self.stringStorage = stringStorage
Expand All @@ -49,7 +49,7 @@ public struct NoteView: Instantiable, View {
}

@Forwarded private let userName: String
@Received private let userService: any UserService
@Received private let userService: AnyUserService
@Received private let stringStorage: StringStorage

@State private var note: String = ""
Expand All @@ -58,7 +58,7 @@ public struct NoteView: Instantiable, View {
#Preview {
NoteView(
userName: "dfed",
userService: DefaultUserService(stringStorage: UserDefaults.standard),
userService: .init(DefaultUserService(stringStorage: UserDefaults.standard)),
stringStorage: UserDefaults.standard
)
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,34 @@ public protocol UserService: ObservableObject {
var observableObjectPublisher: ObservableObjectPublisher { get }
}

/// A type-erased wrapper around a `UserService` that is itself a `UserService` and `ObservableObject`.
public final class AnyUserService: UserService, ObservableObject {
public init(_ userService: some UserService) {
self.userService = userService
objectWillChange = userService
.objectWillChange
.map { _ in () }
.eraseToAnyPublisher()
}

public var userName: String? {
get {
userService.userName
}
set {
userService.userName = newValue
}
}

public var observableObjectPublisher: ObservableObjectPublisher {
userService.observableObjectPublisher
}

public let objectWillChange: AnyPublisher<Void, Never>

private let userService: any UserService
}

@Instantiable(fulfillingAdditionalTypes: [UserService.self])
public final class DefaultUserService: Instantiable, UserService {
public init(stringStorage: StringStorage) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
324F1ECD2B314DB20001AC0C /* StringStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 324F1ECC2B314DB20001AC0C /* StringStorage.swift */; };
324F1ECF2B314E030001AC0C /* NameEntryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 324F1ECE2B314E030001AC0C /* NameEntryView.swift */; };
324F1ED22B3150480001AC0C /* NoteView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 324F1ED12B3150480001AC0C /* NoteView.swift */; };
324F1ED72B3156810001AC0C /* AnyObservableObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 324F1ED62B3156810001AC0C /* AnyObservableObject.swift */; };
32756FE62B24C042006BDD24 /* ExampleApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32756FE52B24C042006BDD24 /* ExampleApp.swift */; };
32756FEA2B24C044006BDD24 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 32756FE92B24C044006BDD24 /* Assets.xcassets */; };
32756FEE2B24C044006BDD24 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 32756FED2B24C044006BDD24 /* Preview Assets.xcassets */; };
Expand All @@ -23,7 +22,6 @@
324F1ECC2B314DB20001AC0C /* StringStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringStorage.swift; sourceTree = "<group>"; };
324F1ECE2B314E030001AC0C /* NameEntryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NameEntryView.swift; sourceTree = "<group>"; };
324F1ED12B3150480001AC0C /* NoteView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoteView.swift; sourceTree = "<group>"; };
324F1ED62B3156810001AC0C /* AnyObservableObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyObservableObject.swift; sourceTree = "<group>"; };
32756FE22B24C042006BDD24 /* ExampleProjectIntegration.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ExampleProjectIntegration.app; sourceTree = BUILT_PRODUCTS_DIR; };
32756FE52B24C042006BDD24 /* ExampleApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExampleApp.swift; sourceTree = "<group>"; };
32756FE92B24C044006BDD24 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
Expand Down Expand Up @@ -58,7 +56,6 @@
children = (
324F1ECA2B314D8D0001AC0C /* UserService.swift */,
324F1ECC2B314DB20001AC0C /* StringStorage.swift */,
324F1ED62B3156810001AC0C /* AnyObservableObject.swift */,
);
path = Models;
sourceTree = "<group>";
Expand Down Expand Up @@ -189,7 +186,6 @@
32756FE62B24C042006BDD24 /* ExampleApp.swift in Sources */,
324F1ECD2B314DB20001AC0C /* StringStorage.swift in Sources */,
324F1ECB2B314D8D0001AC0C /* UserService.swift in Sources */,
324F1ED72B3156810001AC0C /* AnyObservableObject.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down

This file was deleted.

Loading
Loading