-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Enable nested Optionals and Arrays of ObservableObjects (#5)
This adds a wrapper layer which abstracts to allow containers of ObservableObjects — and adds an implementation for Optionals and Arrays.
- Loading branch information
1 parent
7812f12
commit 05344d5
Showing
26 changed files
with
1,105 additions
and
357 deletions.
There are no files selected for viewing
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
{ | ||
"pins" : [ | ||
{ | ||
"identity" : "swift-argument-parser", | ||
"kind" : "remoteSourceControl", | ||
"location" : "https://github.com/apple/swift-argument-parser", | ||
"state" : { | ||
"revision" : "8f4d2753f0e4778c76d5f05ad16c74f707390531", | ||
"version" : "1.2.3" | ||
} | ||
}, | ||
{ | ||
"identity" : "swiftlintfix", | ||
"kind" : "remoteSourceControl", | ||
"location" : "https://github.com/GoodHatsLLC/SwiftLintFix.git", | ||
"state" : { | ||
"revision" : "df971eda06ef78e0570a8feb5e03a04c692ef2b2", | ||
"version" : "0.1.7" | ||
} | ||
} | ||
], | ||
"version" : 2 | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,32 +1,46 @@ | ||
// swift-tools-version: 5.6 | ||
// swift-tools-version: 5.8 | ||
// The swift-tools-version declares the minimum version of Swift required to build this package. | ||
|
||
import PackageDescription | ||
|
||
let package = Package( | ||
name: "Republished", | ||
platforms: [.iOS(.v13), .macOS(.v12)], | ||
products: [ | ||
// Products define the executables and libraries a package produces, and make them visible to other packages. | ||
.library( | ||
name: "Republished", | ||
targets: ["Republished"] | ||
), | ||
], | ||
dependencies: [ | ||
// Dependencies declare other packages that this package depends on. | ||
// .package(url: /* package url */, from: "1.0.0"), | ||
], | ||
targets: [ | ||
// Targets are the basic building blocks of a package. A target can define a module or a test suite. | ||
// Targets can depend on other targets in this package, and on products in packages this package depends on. | ||
.target( | ||
name: "Republished", | ||
dependencies: [] | ||
), | ||
.testTarget( | ||
name: "RepublishedTests", | ||
dependencies: ["Republished"] | ||
), | ||
] | ||
name: "Republished", | ||
platforms: [.iOS(.v15), .macOS(.v13)], | ||
products: [ | ||
.library( | ||
name: "Republished", | ||
targets: ["Republished"] | ||
), | ||
], | ||
dependencies: [ | ||
//.package(url: "https://github.com/GoodHatsLLC/SwiftLintFix.git", from: "0.1.7"), | ||
], | ||
targets: [ | ||
.target( | ||
name: "Republished", | ||
dependencies: [], | ||
swiftSettings: Env.swiftSettings | ||
), | ||
.testTarget( | ||
name: "RepublishedTests", | ||
dependencies: ["Republished"], | ||
exclude: ["RepublishedTests.xctestplan"] | ||
), | ||
] | ||
) | ||
|
||
// MARK: - Env | ||
|
||
private enum Env { | ||
static let swiftSettings: [SwiftSetting] = { | ||
var settings: [SwiftSetting] = [] | ||
settings.append(contentsOf: [ | ||
.enableUpcomingFeature("ConciseMagicFile"), | ||
.enableUpcomingFeature("ExistentialAny"), | ||
.enableUpcomingFeature("StrictConcurrency"), | ||
.enableUpcomingFeature("ImplicitOpenExistentials"), | ||
.enableUpcomingFeature("BareSlashRegexLiterals"), | ||
]) | ||
return settings | ||
}() | ||
} |
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
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
63 changes: 63 additions & 0 deletions
63
RepublishedExampleApp/RepublishedExampleApp/Array/ArrayExampleContentView.swift
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import SwiftUI | ||
|
||
// MARK: - ArrayExampleContentView | ||
|
||
struct ArrayExampleContentView: View { | ||
|
||
// Regular direct use of outer ObservableObject | ||
|
||
@StateObject var viewModel: ArrayExampleViewModel | ||
|
||
var body: some View { | ||
ScrollView { | ||
VStack(alignment: .center, spacing: 24) { | ||
Spacer() | ||
Text(viewModel.count) | ||
.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: "increment all models" | ||
) { | ||
viewModel.incrementAll() | ||
} | ||
CapsuleButton( | ||
bg: (0, 1, 0, 0), | ||
fg: 1, | ||
text: "decrement all models" | ||
) { | ||
viewModel.decrementAll() | ||
} | ||
CapsuleButton( | ||
bg: (0, 0, 0, 1), | ||
fg: 1, | ||
text: "zero out all models" | ||
) { | ||
viewModel.zeroAll() | ||
} | ||
Spacer() | ||
} | ||
} | ||
.frame(maxWidth: .infinity) | ||
} | ||
.background(.gray.opacity(0.6)) | ||
} | ||
} | ||
|
||
// MARK: - ArrayExampleContentView_Previews | ||
|
||
struct ArrayExampleContentView_Previews: PreviewProvider { | ||
static var previews: some View { | ||
ArrayExampleContentView(viewModel: ArrayExampleViewModel(models: Array( | ||
repeating: (), | ||
count: Int.random(in: 0 ... 5) | ||
).map { _ in DomainModel() })) | ||
} | ||
} |
55 changes: 55 additions & 0 deletions
55
RepublishedExampleApp/RepublishedExampleApp/Array/ArrayExampleViewModel.swift
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import Republished | ||
import SwiftUI | ||
|
||
@MainActor | ||
final class ArrayExampleViewModel: ObservableObject { | ||
|
||
// MARK: Lifecycle | ||
|
||
init(models: [DomainModel]) { | ||
_models = .init(wrappedValue: models) | ||
} | ||
|
||
// MARK: Internal | ||
|
||
var info: String { | ||
"across \(models.count) models" | ||
} | ||
|
||
var count: String { | ||
"\(models.map(\.count).reduce(0, +))" | ||
} | ||
|
||
func incrementAll() { | ||
for model in models { | ||
model.set(count: model.count + 1) | ||
} | ||
} | ||
|
||
func decrementAll() { | ||
for model in models { | ||
model.set(count: model.count - 1) | ||
} | ||
} | ||
|
||
func zeroAll() { | ||
for model in models { | ||
model.set(count: 0) | ||
} | ||
} | ||
|
||
// MARK: Private | ||
|
||
// Here the @Republished property wrapper is used *instead* of | ||
// an @Published property wrapper and hold the nested ObservableObjects. | ||
// (Note that there are no @Published wrappers in this file.) | ||
|
||
// @Republished listens to all of its inner ObservableObjects's | ||
// change notifications and propagates them to this containing ObservableObject. | ||
|
||
// SwiftUI views can use properties here derived from the inner object | ||
// just as they would use an @Published field. | ||
|
||
@Republished private var models: [DomainModel] | ||
|
||
} |
Oops, something went wrong.