Skip to content

Commit 10e0525

Browse files
committed
Document RawRepresentable enums and add compatibility tests
1 parent a9e0a69 commit 10e0525

7 files changed

Lines changed: 124 additions & 1 deletion

File tree

README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,25 @@ struct UserPreferences: Codable {
408408
}
409409
```
410410

411+
### Enum RawRepresentable Types
412+
413+
Enums whose `RawValue` already conforms to the property-list set (for example `String`, `Int`, etc.) are persisted automatically via their raw value:
414+
415+
```swift
416+
enum Theme: String {
417+
case light
418+
case dark
419+
case system
420+
}
421+
422+
@ObservableDefaults
423+
class AppearanceSettings {
424+
var theme: Theme = Theme.system
425+
}
426+
```
427+
428+
Because these enums are handled through `RawRepresentable`, avoid adding an explicit `Codable` conformance to the same type—doing so can introduce ambiguous overloads in the generated storage accessors. If you need custom encoding, wrap the enum in another `Codable` type instead of conforming the enum itself.
429+
411430
### Integrating with Other Observable Objects
412431

413432
It's recommended to manage storage data separately from your main application state:

README_zh.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,25 @@ struct UserPreferences: Codable {
408408
}
409409
```
410410

411+
### Enum RawRepresentable 支持
412+
413+
当枚举的 `RawValue` 本身就是属性列表支持的类型(例如 `String``Int` 等)时,宏会自动通过 rawValue 进行持久化:
414+
415+
```swift
416+
enum Theme: String {
417+
case light
418+
case dark
419+
case system
420+
}
421+
422+
@ObservableDefaults
423+
class AppearanceSettings {
424+
var theme: Theme = Theme.system
425+
}
426+
```
427+
428+
由于这些枚举依赖 `RawRepresentable` 存储,请避免为它们额外声明 `Codable`,否则会在生成的存取器中出现重载歧义。如果需要自定义编码,可在更高层的 `Codable` 模型中包装该枚举,而不是直接让枚举本身符合 `Codable`
429+
411430
### 与其他 Observable 对象集成
412431

413432
建议将存储数据与主应用程序状态分开管理:

Sources/ObservableDefaults/NSUbiquitousKeyValueStore/CloudPropertyListValue.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@ import Foundation
1111
/// Protocol for types that can be stored in NSUbiquitousKeyValueStore
1212
public protocol CloudPropertyListValue {}
1313

14+
/// Compatibility shim: legacy projects may still conform to this typealias.
15+
///
16+
/// New code can simply conform to `Codable`—this remains only to avoid breaking
17+
/// existing code and may be removed in a future major release.
18+
public typealias CodableCloudPropertyListValue = Codable
19+
1420
// Extensions for basic types supported by NSUbiquitousKeyValueStore
1521
extension String: CloudPropertyListValue {}
1622
extension Int: CloudPropertyListValue {}

Sources/ObservableDefaults/UserDefaults/UserDefaultsPropertyListValue.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@ import Foundation
3232
/// - Note: All conforming types must also be Equatable to support value comparison
3333
public protocol UserDefaultsPropertyListValue: Equatable {}
3434

35+
/// Compatibility shim: legacy projects may still conform to this typealias.
36+
///
37+
/// New code can simply conform to `Codable`—this remains only to avoid breaking
38+
/// existing code and may be removed in a future major release.
39+
public typealias CodableUserDefaultsPropertyListValue = Codable
40+
3541
// MARK: - Data Types
3642

3743
/// NSData conforms to UserDefaultsPropertyListValue as it's a fundamental property list type
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import Foundation
2+
import ObservableDefaults
3+
import Testing
4+
5+
private struct LegacyDefaultsValue: CodableUserDefaultsPropertyListValue, Equatable {
6+
var text: String = "legacy"
7+
}
8+
9+
private struct LegacyCloudValue: CodableCloudPropertyListValue, Equatable {
10+
var text: String = "legacy"
11+
}
12+
13+
@ObservableDefaults
14+
private class LegacyDefaultsStore {
15+
var value = LegacyDefaultsValue()
16+
}
17+
18+
@ObservableCloud(developmentMode: true)
19+
private class LegacyCloudStore {
20+
var value = LegacyCloudValue()
21+
}
22+
23+
@Suite("Compatibility Tests")
24+
struct CompatibilityTests {
25+
@Test
26+
func defaultsCodableCompatibility() {
27+
let store = LegacyDefaultsStore()
28+
store.value = LegacyDefaultsValue(text: "updated")
29+
#expect(store.value.text == "updated")
30+
}
31+
32+
@Test
33+
func cloudCodableCompatibility() {
34+
let store = LegacyCloudStore()
35+
store.value = LegacyCloudValue(text: "updated")
36+
#expect(store.value.text == "updated")
37+
}
38+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import Foundation
2+
import ObservableDefaults
3+
import Testing
4+
5+
private enum Color: String {
6+
case red
7+
case green
8+
case blue
9+
}
10+
11+
@ObservableDefaults
12+
private class RawValueDefaultsStore {
13+
var color: Color = .red
14+
}
15+
16+
@ObservableCloud(developmentMode: true)
17+
private class RawValueCloudStore {
18+
var color: Color = .red
19+
}
20+
21+
@Suite("Enum RawRepresentable Tests")
22+
struct EnumRawRepresentableTests {
23+
@Test
24+
func defaultsEnumSupport() {
25+
let store = RawValueDefaultsStore()
26+
store.color = .green
27+
#expect(store.color == .green)
28+
}
29+
30+
@Test
31+
func cloudEnumSupport() {
32+
let store = RawValueCloudStore()
33+
store.color = .blue
34+
#expect(store.color == .blue)
35+
}
36+
}

Tests/ObservableDefaultsTests/PrefixTests.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,5 @@ func emptyParameters() {
8585
func emptyPrefixCloud() {
8686
let test = Test6()
8787
test.emptyPrefix = "updated"
88-
let value = test.emptyPrefix == "updated"
8988
#expect(test.emptyPrefix == "updated")
9089
}

0 commit comments

Comments
 (0)