sunshinejr / SwiftyUserDefaults

Modern Swift API for NSUserDefaults
http://radex.io/swift/nsuserdefaults/static
MIT License
4.84k stars 364 forks source link

[Xcode 13.3] builtin extensions are missing #285

Closed shimastripe closed 1 year ago

shimastripe commented 2 years ago

Problem

struct SomeStruct: Codable, DefaultsSerializable {}
=> type 'SomeStruct' does not conform to protocol 'DefaultsSerializable'

In Xcode 13.3, I can't build my apps about DefaultsSerializable.

struct SomeStruct: Codable, DefaultsSerializable {
    public static var _defaults: DefaultsCodableBridge<SomeStruct> { .init() }
    public static var _defaultsArray: DefaultsCodableBridge<[SomeStruct]> { .init() }
}
=> Build succeed

Then I added some default extension's implementations. This problem is occurred about RowRepresentable, NSCoding, or more.

WHY

https://github.com/sunshinejr/SwiftyUserDefaults/blob/master/Sources/BuiltIns.swift extensions are missing?

Xcode 13.3 Beta 1

robinkunde commented 2 years ago

They're not missing. If you look at the build errors in the logs, it actually says something like:

ambiguous inference of associated type 'Bridge': 'DefaultsCodableBridge<Foo>' vs. 'DefaultsRawRepresentableBridge<Foo>'
matching requirement '_defaults' to this declaration inferred associated type to 'DefaultsCodableBridge<Foo>'
matching requirement '_defaults' to this declaration inferred associated type to 'DefaultsRawRepresentableBridge<Foo>'

In my testing, this only happens if the extensions with the default implementations are in another module. It looks like a compiler bug to me.

shimastripe commented 2 years ago

@robinkunde Thank you for your help 🙏

robinkunde commented 2 years ago

Filed here https://bugs.swift.org/browse/SR-15807

apps4everyone commented 2 years ago

same with Xcode 13.3 Beta 3

apps4everyone commented 2 years ago

same with RC, maybe a fix is needed here!

gewill commented 2 years ago

A simple workaround is change dependency to source code

ricardopaiva commented 2 years ago

Hi everyone,

This workaround worked for me:

  1. CreateSwiftyUserDefaults+Workaround.swift in the module which is using SwiftyUserDefaults.
  2. Copy the codes below into SwiftyUserDefaults+Workaround.swift
import SwiftyUserDefaults
import Foundation

extension DefaultsSerializable {
    public static var _defaultsArray: DefaultsArrayBridge<[T]> { return DefaultsArrayBridge() }
}
extension Date: DefaultsSerializable {
    public static var _defaults: DefaultsObjectBridge<Date> { return DefaultsObjectBridge() }
}
extension String: DefaultsSerializable {
    public static var _defaults: DefaultsStringBridge { return DefaultsStringBridge() }
}
extension Int: DefaultsSerializable {
    public static var _defaults: DefaultsIntBridge { return DefaultsIntBridge() }
}
extension Double: DefaultsSerializable {
    public static var _defaults: DefaultsDoubleBridge { return DefaultsDoubleBridge() }
}
extension Bool: DefaultsSerializable {
    public static var _defaults: DefaultsBoolBridge { return DefaultsBoolBridge() }
}
extension Data: DefaultsSerializable {
    public static var _defaults: DefaultsDataBridge { return DefaultsDataBridge() }
}

extension URL: DefaultsSerializable {
    #if os(Linux)
    public static var _defaults: DefaultsKeyedArchiverBridge<URL> { return DefaultsKeyedArchiverBridge() }
    #else
    public static var _defaults: DefaultsUrlBridge { return DefaultsUrlBridge() }
    #endif
    public static var _defaultsArray: DefaultsKeyedArchiverBridge<[URL]> { return DefaultsKeyedArchiverBridge() }
}

extension DefaultsSerializable where Self: Codable {
    public static var _defaults: DefaultsCodableBridge<Self> { return DefaultsCodableBridge() }
    public static var _defaultsArray: DefaultsCodableBridge<[Self]> { return DefaultsCodableBridge() }
}

extension DefaultsSerializable where Self: RawRepresentable {
    public static var _defaults: DefaultsRawRepresentableBridge<Self> { return DefaultsRawRepresentableBridge() }
    public static var _defaultsArray: DefaultsRawRepresentableArrayBridge<[Self]> { return DefaultsRawRepresentableArrayBridge() }
}

extension DefaultsSerializable where Self: NSCoding {
    public static var _defaults: DefaultsKeyedArchiverBridge<Self> { return DefaultsKeyedArchiverBridge() }
    public static var _defaultsArray: DefaultsKeyedArchiverBridge<[Self]> { return DefaultsKeyedArchiverBridge() }
}

extension Dictionary: DefaultsSerializable where Key == String {
    public typealias T = [Key: Value]
    public typealias Bridge = DefaultsObjectBridge<T>
    public typealias ArrayBridge = DefaultsArrayBridge<[T]>
    public static var _defaults: Bridge { return Bridge() }
    public static var _defaultsArray: ArrayBridge { return ArrayBridge() }
}
extension Array: DefaultsSerializable where Element: DefaultsSerializable {
    public typealias T = [Element.T]
    public typealias Bridge = Element.ArrayBridge
    public typealias ArrayBridge = DefaultsObjectBridge<[T]>
    public static var _defaults: Bridge {
        return Element._defaultsArray
    }
    public static var _defaultsArray: ArrayBridge {
        fatalError("Multidimensional arrays are not supported yet")
    }
}

This is pretty much a copy from the BuiltIns.swift file in the Sources folder: https://raw.githubusercontent.com/sunshinejr/SwiftyUserDefaults/master/Sources/BuiltIns.swift

I just removed the last part due to an error that I didn't spend too much time to solve. Just removed this piece of code and the app compiled successfully.

extension Optional: DefaultsSerializable where Wrapped: DefaultsSerializable {
    public typealias Bridge = DefaultsOptionalBridge<Wrapped.Bridge>
    public typealias ArrayBridge = DefaultsOptionalBridge<Wrapped.ArrayBridge>

    public static var _defaults: DefaultsOptionalBridge<Wrapped.Bridge> { return DefaultsOptionalBridge(bridge: Wrapped._defaults) }
    public static var _defaultsArray: DefaultsOptionalBridge<Wrapped.ArrayBridge> { return DefaultsOptionalBridge(bridge: Wrapped._defaultsArray) }
}

This was based on a workaround shared here: https://github.com/sindresorhus/Defaults/issues/93#issuecomment-1053183113

r-plus commented 2 years ago

FYI: in our project codebase that only using DefaultsSerializable with Codable, this small workaround code adding to main module is resolved compiler error too. But this is not maybe fit to all of the case.

extension DefaultsSerializable where Self: Codable {
    typealias Bridge = DefaultsCodableBridge<Self>
    typealias ArrayBridge = DefaultsCodableBridge<[Self]>
}
morgz commented 2 years ago

FYI: in our project codebase that only using DefaultsSerializable with Codable, this small workaround code adding to main module is resolved compiler error too. But this is not maybe fit to all of the case.

extension DefaultsSerializable where Self: Codable {
    typealias Bridge = DefaultsCodableBridge<Self>
    typealias ArrayBridge = DefaultsCodableBridge<[Self]>
}

Thanks, this avoided a ton of compiler warnings

skywalkerlw commented 2 years ago

can we update a new version and get this done?

WestFlow127 commented 2 years ago

This worked for me, having had classes/structs using RawRepresentable or Codable paired with DefaultsSerializable:

extension DefaultsSerializable where Self: Codable {
    public typealias Bridge = DefaultsCodableBridge<Self>
    public typealias ArrayBridge = DefaultsCodableBridge<[Self]>
}

extension DefaultsSerializable where Self: RawRepresentable {
    typealias Bridge = DefaultsRawRepresentableBridge<Self>
    typealias ArrayBridge = DefaultsRawRepresentableArrayBridge<[Self]>
}

Added this to our global constants file, got rid of the issues related to this post.

thanhdevapp commented 2 years ago

why not release new version to fix this bug

shimastripe commented 2 years ago

I checked Xcode 14 Beta (Swift@5.7) was resolved this problem!

shimastripe commented 1 year ago

I checked this bug was resolved in Xcode 14 RC too! So close this issue! Thanks!