How to overcome the error of "Generic parameter 'T' is not used in function signature"? - swift

I'm trying to convert the following to be generic.
extension RLMOrganization: DataProvider {
func getLastSyncToken() -> String {
let lastUpdated: RLMOrganization? = self.findAll(sortedBy: "syncToken").last
if let syncToken = lastUpdated?.syncToken {
return syncToken
} else {
return "00000000000000000000000000000000"
}
}
}
And have tried this:
protocol DataProvider: DatabaseLayer {
associatedtype T: Object
func findAll<T: Object>(sortedBy key: String) -> [T]
}
extension DataProvider {
func findAll<T: Object>(sortedBy key: String) -> [T] {
let database = self.getDatabase()
if let allObjects = database?.objects(T.self) {
let results = allObjects.sorted(byKeyPath: key, ascending: true)
return Array(results)
}
return []
}
func getLastSyncToken<T: Object>() -> String {
let lastUpdated = self.findAll(sortedBy: "syncToken").last as? T
if let value = lastUpdated?.value(forKey: "syncToken") { // get value from object by string name
let syncToken = value as! String
return syncToken
} else {
return "00000000000000000000000000000000"
}
}
...
But can't seem to overcome the error of:
Generic parameter 'T' is not used in function signature
I would think the compiler has everything it needs to determine type usage.

Below works for me, I don't know how findAll is defined but the problem is the reference to self as I see it so you need to define T there using associatedtype.
protocol DataProvider: DatabaseLayer {
associatedtype T: Object
func findAll(sortedBy: String) -> T?
}

Related

Observe generic values with Combine

Take this case of a type constrained class Parameter, wrapping a value of given type.
Parameter conforms to the AnyParameter so it can be passed anywhere in the app without knowing the type. Parameters can be displayed in value cells AnyValueCell
How would you do to observe the change without having to know the underlying value type? It would be nice to avoid the code repetition in the value cell updateObserver function
Could AnyPublisher can be used here and how?
import UIKit
import Combine
print("Hello Playground")
protocol AnyParameter {
var anyValue: Any { get }
func set(value: Any)
}
protocol ParameterProtocol: AnyParameter {
associatedtype ValueType
var value: ValueType { get }
func set(value: ValueType)
}
public class Parameter<T>: ParameterProtocol {
typealias ValueType = T
#Published var value: T
var anyValue: Any { value }
init(value: T) {
self.value = value
}
func set(value: Any) {
guard let value = value as? T else { return }
set(value: value)
}
func set(value: T) {
self.value = value
}
}
public class AnyValueCell {
var parameter: AnyParameter {
didSet {
updateObserver()
}
}
var observer: AnyCancellable?
init(parameter: AnyParameter) {
self.parameter = parameter
updateObserver()
}
func updateObserver() {
observer?.cancel()
// This is the point of the question - How to make this generic?
// ---->
if let p = parameter as? Parameter<Int> {
observer = p.$value.sink() { value in
print("Update Cell -> \(value)")
}
return
}
if let p = parameter as? Parameter<Double> {
observer = p.$value.sink() { value in
print("Update Cell -> \(value)")
}
return
}
if let p = parameter as? Parameter<Bool> {
observer = p.$value.sink() { value in
print("Update Cell -> \(value)")
}
return
}
// <----
print("Wrong param type")
}
}
let intParam = Parameter<Int>(value: 42)
let doubleParam = Parameter<Double>(value: 3.14)
let boolParam = Parameter<Bool>(value: false)
var params: [AnyParameter] = [intParam, doubleParam, boolParam]
print ("--> Init Cells")
let cells: [AnyValueCell] = params.map { AnyValueCell(parameter: $0) }
print ("--> Change values")
intParam.set(value: 21)
doubleParam.set(value: 1.618)
boolParam.set(value: true)
Result, as expected:
Hello Playground
--> Init Cells
Update Cell -> 42
Update Cell -> 3.14
Update Cell -> false
--> Change values
Update Cell -> 21
Update Cell -> 1.618
Update Cell -> true
Add an anyValuePublisher property. You can (and maybe should) add it to AnyParameter, or you can define it in a separate protocol like this:
protocol AnyParameterPublishing: AnyParameter {
var anyValuePublisher: AnyPublisher<Any, Never> { get }
}
extension Parameter: AnyParameterPublishing {
var anyValuePublisher: AnyPublisher<Any, Never> {
return $value.map { $0 as Any }.eraseToAnyPublisher()
}
}
Then you can use it like this:
class AnyValueCell {
// ...
func updateObserver() {
guard let publishing = (parameter as? AnyParameterPublishing) else {
print("Wrong param type")
return
}
observer = publishing.anyValuePublisher
.sink { print("Update Cell -> \($0)") }
}
}

Cannot convert return expression of type '[Favorite.Type]' to return type '[Favorite]'

I want to make a general function for getting Elements from UserDefaults that are conforming to the NSObject and NSCoding Protocol. But when I want to use that function I get this error
func getFavorites() -> [Favorite] {
return get(type: Favorite, forKey: UD_FAVORITES)
}
Cannot convert return expression of type '[Favorite.Type]' to return type '[Favorite]'
That's my UserDefaults Extension:
func get<T>(type: T, forKey key: String) -> [T] {
if let data = self.object(forKey: key) as? Data {
do {
let tData = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as! [T]
return tData
} catch {
debugPrint(error)
return [T]()
}
} else {
print("EMPTY \(key)")
return [T]()
}
}
The type of type must be T.Type
func get<T>(type: T.Type, forKey key: String) -> [T] { ...
and you have to call it
return get(type: Favorite.self, forKey: UD_FAVORITES)
Actually you don't need the parameter, this is Swift, the compiler can infer the type (specified by the return type [Favorite])
func get<T>(valueForKey key: String) -> [T] {
and
return get(valueForKey: UD_FAVORITES)
And there is
if let data = self.data(forKey: key) {

How can you check if a type is Optional in Swift?

How can you check if a type is Optional in Swift?
Say I have a variable of type PartialKeyPath where:
struct Foo {
let bar: String
let baz: String?
}
typealias Property<Root> = (key: PartialKeyPath<Root>, value: Any?)
typealias Properties<Root> = [Property<Root>]
Now say I iterate thru an instance of Properties:
properties.forEach { prop in
let valueType1 = type(of: prop.key).valueType
let valueType2 = type(of: value)
...
How can I check here whether valueType1 is Optional<valueType2>, or whether it is Optional of any other flavor for that matter?
So far the only way I’ve found is really ugly...
Using a similar approach to Optional field type doesn't conform protocol in Swift 3, you could define a 'dummy protocol' for Optional and use this to get the wrapped metatype:
protocol OptionalProtocol {
// the metatype value for the wrapped type.
static var wrappedType: Any.Type { get }
}
extension Optional : OptionalProtocol {
static var wrappedType: Any.Type { return Wrapped.self }
}
If you just want to know a type is an optional:
func isOptionalType(_ type: Any.Type) -> Bool {
return type is OptionalProtocol.Type
}
print(isOptionalType(String.self)) // false
print(isOptionalType(String?.self)) // true
If you want to check if one metatype is the 'optional version' of another metatype:
struct Foo {
let bar: String
let baz: String?
}
struct Property<Root> {
var key: PartialKeyPath<Root>
var value: Any
}
let properties = [Property(key: \Foo.baz, value: "hello")]
/// Attempt to get the `Wrapped` metatype from a metatype of an
/// `Optional<Wrapped>`. If not an `Optional`, will return `nil`.
func wrappedTypeFromOptionalType(_ type: Any.Type) -> Any.Type? {
return (type as? OptionalProtocol.Type)?.wrappedType
}
for property in properties {
let valueType1 = type(of: property.key).valueType
let valueType2 = type(of: property.value)
if wrappedTypeFromOptionalType(valueType1) == valueType2 {
print("\(valueType1) == Optional<\(valueType2)>")
}
}
// Optional<String> == Optional<String>
However there's almost certainly a better way to do whatever you're trying to do here with the key paths.
could you use a mirror reflecting Any and check displayStyle is optional?.
func isOptional(any:Any) -> Bool {
let mirror = Mirror(reflecting: any)
if mirror.displayStyle == .Optional {
return true
} else {
return false
}
}
More on mirror display style:
https://developer.apple.com/documentation/swift/mirror.displaystyle
This is a hacky but working solution:
func isOptional(_ type: Any.Type) -> Bool {
let typeName = String(describing: type)
return typeName.hasPrefix("Optional<")
}
Test:
let t1 = Int?.self
let t2 = Bool.self
print(isOptional(t1))
// true
print(isOptional(t2))
// false
A tweak of #kelin’s answer:
postfix operator ...?!
postfix func ...?!<T>(_ instance: T) -> Bool {
let subject = "\(Mirror(reflecting: instance).subjectType)"
return !subject.hasPrefix("Optional")
}
And in the vein of #Ercell0’s answer is this superior method:
func isOptional<T>(_ instance: T) -> Bool {
guard let displayStyle = Mirror(reflecting: instance).displayStyle
else { return false }
return displayStyle == .optional
}

Can Swift enums be inferred and restricted generically?

I can't find the syntax, but I want to do something like this:
class MyClass {
let stringValue: String // filled in later
let integerValue: Int // filled in later
init(stringValue: String) {
self.stringValue = stringValue
self.integerValue = stringValue.hashValue
}
init(integerValue: Int) {
self.integerValue = integerValue
self.stringValue = String(integerValue)
}
}
extension MyClass {
// This is invalid syntax, but I think you can understand
// vvvvvvvvv I'm trying to give back an enum whose type is inferred
var enumValue<T: enum>: T? {
get {
// This is also invalid; I want to check the type of the enum's raw value
if T is String {
return T(rawValue: self.stringValue)
} else if T is Int {
return T(rawValue: self.integerValue)
} else {
return nil
}
}
}
}
The usage would be like:
enum MyEnum: String {
case foo
case bar
}
func baz(_ some: MyClass) {
if let myEnum: MyEnum = some.enumValue {
print(myEnum)
}
}
let some = MyClass(stringValue: "foo")
baz(some) // prints "foo"
Is this possible in Swift? That is, to have a generically-typed field or function whose type is constricted to enums and inferred based on usage, then use that to instantiate an enum value?
A possible solution would be a generic overloaded function:
extension MyClass {
func enumValue<T: RawRepresentable>() -> T? where T.RawValue == String {
return T(rawValue: stringValue)
}
func enumValue<T: RawRepresentable>() -> T? where T.RawValue == Int {
return T(rawValue: integerValue)
}
}
which is then called as
func baz(_ some: MyClass) {
if let myEnum: MyEnum = some.enumValue() {
print(myEnum)
}
}
Alternatively, pass the enum type as an argument:
extension MyClass {
func enumValue<T: RawRepresentable>(_ type: T.Type) -> T? where T.RawValue == String {
return T(rawValue: stringValue)
}
func enumValue<T: RawRepresentable>(_ type: T.Type) -> T? where T.RawValue == Int {
return T(rawValue: integerValue)
}
}
and call it like
func baz(_ some: MyClass) {
if let myEnum = some.enumValue(MyEnum.self) {
print(myEnum)
}
}

Swift: check return type of generic function

I know how to check type of named variable - if var is T. But can't find how to check supposed return type for generic function.
Live example, dealing with SwiftyJSON, ugly solution:
func getValue<T>(key: String) -> T? {
let result: T // so ugly approach...
if result is Bool {
return json[key].bool as? T
}
if result is Int {
return json[key].int as? T
}
if result is String {
return json[key].string as? T
}
fatalError("unsupported type \(result.dynamicType)")
}
Looking for more elegant approach.
This would work:
func getValue<T>(key: String) -> T? {
if T.self is Bool.Type {
return json[key].bool as? T
}
if T.self is Int.Type {
return json[key].int as? T
}
if T.self is String.Type {
return json[key].string as? T
}
fatalError("unsupported type \(T.self)")
}
But I'm not sure it's any more elegant than yours.
Overloading is something worth trying:
func getValue(key: String) -> Bool? {
return json[key].bool
}
func getValue(key: String) -> Int? {
return json[key].int
}
func getValue(key: String) -> String? {
return json[key].string
}
With this, you can find errors in compile time, rather than getting fatal errors in runtime.