diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/Republished.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/Republished.xcscheme
index af7ab88..6aaa0c6 100644
--- a/.swiftpm/xcode/xcshareddata/xcschemes/Republished.xcscheme
+++ b/.swiftpm/xcode/xcshareddata/xcschemes/Republished.xcscheme
@@ -29,7 +29,7 @@
shouldUseLaunchSchemeArgsEnv = "YES">
diff --git a/Package.swift b/Package.swift
index 049addd..951ee16 100644
--- a/Package.swift
+++ b/Package.swift
@@ -11,7 +11,7 @@ let package = Package(
.library(
name: "Republished",
targets: ["Republished"]
- )
+ ),
],
dependencies: [
// Dependencies declare other packages that this package depends on.
@@ -27,6 +27,6 @@ let package = Package(
.testTarget(
name: "RepublishedTests",
dependencies: ["Republished"]
- )
+ ),
]
)
diff --git a/README.md b/README.md
index 3f3593e..3cae04a 100644
--- a/README.md
+++ b/README.md
@@ -37,7 +37,7 @@ from inner `ObservableObjects` that it actually accesses.
You can use this library via Swift Package Manger by adding a dependency in your Package.swift.
```swift
-.package(url: "https://github.com/adam-zethraeus/Republished", from: "0.1.0")
+.package(url: "https://github.com/adam-zethraeus/Republished", from: "1.0.1")
```
## Example App
diff --git a/RepublishTestApp.swiftpm/.swiftpm/playgrounds/CachedManifest.plist b/RepublishTestApp.swiftpm/.swiftpm/playgrounds/CachedManifest.plist
deleted file mode 100644
index ec45f98..0000000
--- a/RepublishTestApp.swiftpm/.swiftpm/playgrounds/CachedManifest.plist
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-
-
- CachedManifest
-
- manifestData
-
- eyJkZXBlbmRlbmNpZXMiOltdLCJkaXNwbGF5TmFtZSI6IlJlcHVibGlzaFRl
- c3RBcHAiLCJwYWNrYWdlS2luZCI6eyJyb290Ijp7fX0sInBsYXRmb3JtcyI6
- W3sib3B0aW9ucyI6W10sInBsYXRmb3JtTmFtZSI6ImlvcyIsInZlcnNpb24i
- OiIxNS4yIn1dLCJwcm9kdWN0cyI6W3sibmFtZSI6IlJlcHVibGlzaFRlc3RB
- cHAiLCJzZXR0aW5ncyI6W3siZGlzcGxheVZlcnNpb24iOlsiMS4wIl19LHsi
- YnVuZGxlVmVyc2lvbiI6WyIxIl19LHsiaU9TQXBwSW5mbyI6W3siYWNjZW50
- Q29sb3IiOnsicHJlc2V0Q29sb3IiOnsicHJlc2V0Q29sb3IiOnsicmF3VmFs
- dWUiOiJwaW5rIn19fSwiYXBwSWNvbiI6eyJwbGFjZWhvbGRlciI6eyJpY29u
- Ijp7InJhd1ZhbHVlIjoiY2FsZW5kYXIifX19LCJjYXBhYmlsaXRpZXMiOltd
- LCJzdXBwb3J0ZWREZXZpY2VGYW1pbGllcyI6WyJwYWQiLCJwaG9uZSJdLCJz
- dXBwb3J0ZWRJbnRlcmZhY2VPcmllbnRhdGlvbnMiOlt7InBvcnRyYWl0Ijp7
- fX0seyJsYW5kc2NhcGVSaWdodCI6e319LHsibGFuZHNjYXBlTGVmdCI6e319
- LHsicG9ydHJhaXRVcHNpZGVEb3duIjp7ImNvbmRpdGlvbiI6eyJkZXZpY2VG
- YW1pbGllcyI6WyJwYWQiXX19fV19XX1dLCJ0YXJnZXRzIjpbIkFwcCJdLCJ0
- eXBlIjp7ImV4ZWN1dGFibGUiOm51bGx9fV0sInRhcmdldE1hcCI6eyJBcHAi
- OnsiZGVwZW5kZW5jaWVzIjpbXSwiZXhjbHVkZSI6W10sIm5hbWUiOiJBcHAi
- LCJwYXRoIjoiQXBwIiwicmVzb3VyY2VzIjpbXSwic2V0dGluZ3MiOltdLCJ0
- eXBlIjoiZXhlY3V0YWJsZSJ9fSwidGFyZ2V0cyI6W3siZGVwZW5kZW5jaWVz
- IjpbXSwiZXhjbHVkZSI6W10sIm5hbWUiOiJBcHAiLCJwYXRoIjoiQXBwIiwi
- cmVzb3VyY2VzIjpbXSwic2V0dGluZ3MiOltdLCJ0eXBlIjoiZXhlY3V0YWJs
- ZSJ9XSwidG9vbHNWZXJzaW9uIjp7Il92ZXJzaW9uIjoiNS42LjAifX0=
-
- manifestHash
-
- 67WQxc7+xhzNa6Ms8hXit4D9TlQCnVRJTuqNMN96+Yw=
-
- schemaVersion
- 4
- swiftPMVersionString
- 5.6.0-dev
-
-
-
diff --git a/RepublishTestApp.swiftpm/.swiftpm/playgrounds/DocumentThumbnail.plist b/RepublishTestApp.swiftpm/.swiftpm/playgrounds/DocumentThumbnail.plist
deleted file mode 100644
index e13743f..0000000
--- a/RepublishTestApp.swiftpm/.swiftpm/playgrounds/DocumentThumbnail.plist
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
- DocumentThumbnailConfiguration
-
- accentColorHash
-
- pnpByLx51dqRe1BR8fDT9a60tjuiRrNUapYe96PH2TE=
-
- appIconHash
-
- UVJ5DieOuJA5+L+qNUuUTsG0TF0/wUTtxXIMPtwEXHM=
-
- thumbnailIsPrerendered
-
-
-
-
diff --git a/RepublishTestApp.swiftpm/.swiftpm/playgrounds/DocumentThumbnail.png b/RepublishTestApp.swiftpm/.swiftpm/playgrounds/DocumentThumbnail.png
deleted file mode 100644
index 3e29a79..0000000
Binary files a/RepublishTestApp.swiftpm/.swiftpm/playgrounds/DocumentThumbnail.png and /dev/null differ
diff --git a/RepublishTestApp.swiftpm/.swiftpm/playgrounds/Workspace.plist b/RepublishTestApp.swiftpm/.swiftpm/playgrounds/Workspace.plist
deleted file mode 100644
index e713dbb..0000000
--- a/RepublishTestApp.swiftpm/.swiftpm/playgrounds/Workspace.plist
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
- AppSettings
-
- appIconPlaceholderGlyphName
- calendar
- appSettingsVersion
- 1
-
-
-
diff --git a/RepublishTestApp.swiftpm/.swiftpm/playgrounds/contentInfo.plist b/RepublishTestApp.swiftpm/.swiftpm/playgrounds/contentInfo.plist
deleted file mode 100644
index 4ffd5fe..0000000
--- a/RepublishTestApp.swiftpm/.swiftpm/playgrounds/contentInfo.plist
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
- contentVersion
- 1.0.1
- contentIdentifier
- com.apple.playgrounds.recognizinggestures
- guideVersion
- 1.0.0
-
-
diff --git a/RepublishTestApp.swiftpm/.swiftpm/playgrounds/version.plist b/RepublishTestApp.swiftpm/.swiftpm/playgrounds/version.plist
deleted file mode 100644
index 090c480..0000000
--- a/RepublishTestApp.swiftpm/.swiftpm/playgrounds/version.plist
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
- BuildVersion
- 4
- ProductBuildVersion
- 5E95
-
-
diff --git a/RepublishTestApp.swiftpm/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata b/RepublishTestApp.swiftpm/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
deleted file mode 100644
index 919434a..0000000
--- a/RepublishTestApp.swiftpm/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
diff --git a/RepublishTestApp.swiftpm/App/App.swift b/RepublishTestApp.swiftpm/App/App.swift
deleted file mode 100644
index 0a48b60..0000000
--- a/RepublishTestApp.swiftpm/App/App.swift
+++ /dev/null
@@ -1,11 +0,0 @@
-import SwiftUI
-
-@main
-struct RepublishTestApp: App {
-
- var body: some Scene {
- WindowGroup {
- ContentView(viewModel: ViewModel(model: DomainModel()))
- }
- }
-}
diff --git a/RepublishTestApp.swiftpm/App/DomainModel.swift b/RepublishTestApp.swiftpm/App/DomainModel.swift
deleted file mode 100644
index 0d31e61..0000000
--- a/RepublishTestApp.swiftpm/App/DomainModel.swift
+++ /dev/null
@@ -1,62 +0,0 @@
-import SwiftUI
-
-final class DomainModel: ObservableObject {
-
- // A standard ObservableObject.
-
- // Updates to `count` makes the object fire a signal that
- // consumers can listen to to know when to read — and SwiftUI
- // does this by default.
-
- // However, if you nest this in another ObservableObject, there's
- // no inbuilt functionality to make the outer one fire for updates
- // in response to this inner one firing.
-
- // (An ObservableObject is a reference type, so an @Published field
- // on the outer object containing this object as an inner one
- // isn't actually changing.
-
- @Published private(set) var count = 0
-
- var isEven: Bool {
- count % 2 == 0
- }
-
- var isZero: Bool {
- count == 0
- }
-
- var isNegative: Bool {
- count < 0
- }
-
- var isPositive: Bool {
- count > 0
- }
-
- var isMax: Bool {
- count == Int.max
- }
-
- var isMin: Bool {
- count == Int.min
- }
-
- var isPrime: Bool {
- switch true {
- case count < 2: return false
- case count < 4: return true
- default:
- return (2...Int(Double(count).squareRoot()))
- .lazy
- .filter { [count] div in
- count % div == 0
- }
- .first == nil
- }
- }
-
- func set(count: Int) {
- self.count = count
- }
-}
diff --git a/RepublishTestApp.swiftpm/App/ViewModel.swift b/RepublishTestApp.swiftpm/App/ViewModel.swift
deleted file mode 100644
index cc6047f..0000000
--- a/RepublishTestApp.swiftpm/App/ViewModel.swift
+++ /dev/null
@@ -1,61 +0,0 @@
-import Republished
-import SwiftUI
-
-@MainActor
-final class ViewModel: ObservableObject {
-
- init(model: DomainModel) {
- _model = .init(wrappedValue: model)
- }
-
- var info: String {
- [
- model.isEven ? "even" : nil,
- model.isZero ? "zero" : nil,
- model.isNegative ? "negative" : nil,
- model.isPositive ? "positive" : nil,
- model.isMax ? "MAXINT" : nil,
- model.isMin ? "MININT" : nil,
- model.isPrime ? "prime" : nil
- ]
- .compactMap { $0 }
- .sorted()
- .joined(separator: ", ")
- }
-
- var countString: String {
- "\(model.count)"
- }
-
- func increment() {
- model.set(count: model.count + 1)
- }
-
- func decrement() {
- model.set(count: model.count - 1)
- }
-
- func rand() {
- model.set(count: Int.random(in: Int.min...Int.max))
- }
-
- func zero() {
- model.set(count: 0)
- }
-
- // Here the @Republished property wrapper is used to hold
- // the nested object *instead* of an @Published property wrapper.
- // (There are *no* @Published wrappers in this file.)
-
- // @Republished listens to the inner ObservableObject's
- // change notifications and propagates them to the outer one.
-
- // SwiftUI views can use properties derived from the inner object
- // normally — just like how they would use an @Published field.
- //
- // This outer object could also provide @Binding surfaces into
- // the inner object's data.
-
- @Republished private var model: DomainModel
-
-}
diff --git a/RepublishTestApp.swiftpm/App/Views/CapsuleButton.swift b/RepublishTestApp.swiftpm/App/Views/CapsuleButton.swift
deleted file mode 100644
index 297f74e..0000000
--- a/RepublishTestApp.swiftpm/App/Views/CapsuleButton.swift
+++ /dev/null
@@ -1,34 +0,0 @@
-import SwiftUI
-
-struct CapsuleButton: View {
-
- let bg: (c: CGFloat, m: CGFloat, y: CGFloat, k: CGFloat)
- let fg: CGFloat
- let text: String
- let action: () -> Void
-
- var body: some View {
- Button(text) { action() }
- .padding(16)
- .background(
- Color(
- CGColor(
- genericCMYKCyan: bg.c,
- magenta: bg.m,
- yellow: bg.y,
- black: bg.k,
- alpha: 1
- )
- )
- )
- .foregroundColor(
- Color(
- hue: 0,
- saturation: 0,
- brightness: fg
- )
- )
- .clipShape(Capsule())
- }
-
-}
diff --git a/RepublishTestApp.swiftpm/App/Views/ContentView.swift b/RepublishTestApp.swiftpm/App/Views/ContentView.swift
deleted file mode 100644
index bff9d68..0000000
--- a/RepublishTestApp.swiftpm/App/Views/ContentView.swift
+++ /dev/null
@@ -1,67 +0,0 @@
-import SwiftUI
-
-// MARK: - ContentView
-
-struct ContentView: View {
-
- // Regular direct use of outer ObservableObject
-
- @StateObject var viewModel: ViewModel
-
- var body: some View {
- ScrollView {
- VStack(alignment: .center, spacing: 24) {
- Spacer()
- Text(viewModel.countString)
- .font(.title)
- .fontWeight(.bold)
- .scaledToFit()
- Text(viewModel.info)
- .font(.body.monospaced())
- Spacer()
- VStack(alignment: .center, spacing: 24) {
- Spacer()
- CapsuleButton(
- bg: (1, 0, 0, 0),
- fg: 1,
- text: "count += 1"
- ) {
- viewModel.increment()
- }
- CapsuleButton(
- bg: (0, 1, 0, 0),
- fg: 1,
- text: "count -= 1"
- ) {
- viewModel.decrement()
- }
- CapsuleButton(
- bg: (0, 0, 1, 0),
- fg: 0,
- text: "count = rand()"
- ) {
- viewModel.rand()
- }
- CapsuleButton(
- bg: (0, 0, 0, 1),
- fg: 1,
- text: "count = 0"
- ) {
- viewModel.zero()
- }
- Spacer()
- }
- }
- .frame(maxWidth: .infinity)
- }
- .background(.gray.opacity(0.6))
- }
-}
-
-// MARK: - ContentView_Previews
-
-struct ContentView_Previews: PreviewProvider {
- static var previews: some View {
- ContentView(viewModel: ViewModel(model: DomainModel()))
- }
-}
diff --git a/RepublishTestApp.swiftpm/Package.swift b/RepublishTestApp.swiftpm/Package.swift
deleted file mode 100644
index 94c38cd..0000000
--- a/RepublishTestApp.swiftpm/Package.swift
+++ /dev/null
@@ -1,45 +0,0 @@
-// swift-tools-version: 5.6
-
-// WARNING:
-// This file is automatically generated.
-// Do not edit it by hand because the contents will be replaced.
-
-import AppleProductTypes
-import PackageDescription
-
-let package = Package(
- name: "RepublishTestApp",
- platforms: [
- .iOS("15.2")
- ],
- products: [
- .iOSApplication(
- name: "RepublishTestApp",
- targets: ["App"],
- displayVersion: "1.0",
- bundleVersion: "1",
- appIcon: .placeholder(icon: .calendar),
- accentColor: .presetColor(.pink),
- supportedDeviceFamilies: [
- .pad,
- .phone
- ],
- supportedInterfaceOrientations: [
- .portrait,
- .landscapeRight,
- .landscapeLeft,
- .portraitUpsideDown(.when(deviceFamilies: [.pad]))
- ]
- )
- ],
- dependencies: [
- .package(path: "..")
- ],
- targets: [
- .executableTarget(
- name: "App",
- dependencies: ["Republished"],
- path: "App"
- )
- ]
-)
diff --git a/RepublishedExampleApp/RepublishedExampleApp/DomainModel.swift b/RepublishedExampleApp/RepublishedExampleApp/DomainModel.swift
index 0d31e61..aa86139 100644
--- a/RepublishedExampleApp/RepublishedExampleApp/DomainModel.swift
+++ b/RepublishedExampleApp/RepublishedExampleApp/DomainModel.swift
@@ -5,16 +5,16 @@ final class DomainModel: ObservableObject {
// A standard ObservableObject.
// Updates to `count` makes the object fire a signal that
- // consumers can listen to to know when to read — and SwiftUI
- // does this by default.
+ // consumers can listen to to know when to read — and that
+ // SwiftUI listens to by default.
- // However, if you nest this in another ObservableObject, there's
+ // However, if you nest this in another ObservableObject there's
// no inbuilt functionality to make the outer one fire for updates
// in response to this inner one firing.
- // (An ObservableObject is a reference type, so an @Published field
- // on the outer object containing this object as an inner one
- // isn't actually changing.
+ // An ObservableObject is a reference type, so an @Published field
+ // on the outer object (which contains this object) the field does
+ // not actually change.
@Published private(set) var count = 0
diff --git a/RepublishedExampleApp/RepublishedExampleApp/ViewModel.swift b/RepublishedExampleApp/RepublishedExampleApp/ViewModel.swift
index cc6047f..c42a9a9 100644
--- a/RepublishedExampleApp/RepublishedExampleApp/ViewModel.swift
+++ b/RepublishedExampleApp/RepublishedExampleApp/ViewModel.swift
@@ -4,6 +4,21 @@ import SwiftUI
@MainActor
final class ViewModel: ObservableObject {
+ // Here the @Republished property wrapper is used *instead* of
+ // an @Published property wrapper and hold the nested ObservableObject.
+ // (Note that there are no @Published wrappers in this file.)
+
+ // @Republished listens to the inner ObservableObject's
+ // change notifications and propagates them to the outer one.
+
+ // SwiftUI views can use properties here derived from the inner object
+ // just as they would use an @Published field.
+ //
+ // This outer object could also provide @Binding surfaces into
+ // the inner object's data.
+
+ @Republished private var model: DomainModel
+
init(model: DomainModel) {
_model = .init(wrappedValue: model)
}
@@ -16,7 +31,7 @@ final class ViewModel: ObservableObject {
model.isPositive ? "positive" : nil,
model.isMax ? "MAXINT" : nil,
model.isMin ? "MININT" : nil,
- model.isPrime ? "prime" : nil
+ model.isPrime ? "prime" : nil,
]
.compactMap { $0 }
.sorted()
@@ -43,19 +58,4 @@ final class ViewModel: ObservableObject {
model.set(count: 0)
}
- // Here the @Republished property wrapper is used to hold
- // the nested object *instead* of an @Published property wrapper.
- // (There are *no* @Published wrappers in this file.)
-
- // @Republished listens to the inner ObservableObject's
- // change notifications and propagates them to the outer one.
-
- // SwiftUI views can use properties derived from the inner object
- // normally — just like how they would use an @Published field.
- //
- // This outer object could also provide @Binding surfaces into
- // the inner object's data.
-
- @Republished private var model: DomainModel
-
}
diff --git a/Sources/Republished/Republished.swift b/Sources/Republished/Republished.swift
index 1ae5c17..67ad5f4 100644
--- a/Sources/Republished/Republished.swift
+++ b/Sources/Republished/Republished.swift
@@ -24,7 +24,7 @@ import SwiftUI
/// > of inner `ObservableObjects` that it actually accesses.
@MainActor
@propertyWrapper
-public class Republished
+public final class Republished
where Republishing.ObjectWillChangePublisher == ObservableObjectPublisher {
public init(wrappedValue republished: Republishing) {
@@ -52,10 +52,9 @@ public class Republished
)
-> Republishing where Instance.ObjectWillChangePublisher == ObservableObjectPublisher {
let storage = instance[keyPath: storageKeyPath]
- let wrapped = storage.republishedSelf
- if storage.republishedSelf.cancellable == nil {
- storage.republishedSelf.cancellable = wrapped
+ if storage.cancellable == nil {
+ storage.cancellable = storage
.wrappedValue
.objectWillChange
.sink { [objectWillChange = instance.objectWillChange] in
@@ -63,11 +62,7 @@ public class Republished
}
}
- return wrapped.wrappedValue
- }
-
- var republishedSelf: Republished {
- self
+ return storage.wrappedValue
}
private var republished: Republishing