How can I make a Generic PreferenceKey in SwiftUI?

Viewed 471

I want make a Generic PreferenceKey, which I got 2 issues with my codes.

First I need define () for T, for using normal type like String, Int as String() or Int() so I need memberwise initializer for T.

Second Xcode complain that my PreferenceKey does not conform to Equatable, while I did it! <T: Equatable>

How can I solve this 2 issues? thanks


struct ContentView: View {
    
    @State private var stringOfText: String = "Hello, world!"
    
    var body: some View {
        
        Text(stringOfText)
            .preference(key: CustomPreferenceKey.self, value: stringOfText)
            .onPreferenceChange(CustomPreferenceKey.self) { newValue in print(newValue) }
        
        
    }
}

struct CustomPreferenceKey<T: Equatable>: PreferenceKey {
    
    static var defaultValue: T { get { return T() } }
    
    static func reduce(value: inout T, nextValue: () -> T) { value = nextValue() }
    
}
1 Answers

Here is a possible approach to move with. Tested as worked with Xcode 12.4 / iOS 14.4

protocol Initable {
    init()
}

extension String: Initable {
}

struct CustomPreferenceKey<T: Equatable & Initable>: PreferenceKey {
    typealias Value = T

    static var defaultValue: T { get { T() } }

    static func reduce(value: inout Value, nextValue: () -> Value) {
        value = nextValue()
    }
}

struct ContentView: View {

    @State private var stringOfText: String = "Hello, world!"

    var body: some View {

        Text(stringOfText)
            .preference(key: CustomPreferenceKey<String>.self, value: stringOfText)
            .onPreferenceChange(CustomPreferenceKey<String>.self) { newValue in print(newValue) }
    }
}
Related