Swift generics error: Cannot convert value of type 'Type T ' to expected argument type 'Type _ '
You are using a non-generic concrete type MyModel
in a generic function, that doesn't work.
You could do something like this
class Test {
func test<T: MyProcotol>(item: T, completion: (Result<T>) -> Void) {
let result : Result<T> = .success(value: item)
completion(result)
}
}
Cannot convert value of type 'T?' to expected argument type 'T?'
You need to use an associatedtype
in your protocol so all functions/variables in the protocol uses the same type because otherwise each function with a <T>
will be using a different type
Example (simplified
protocol PostDataProviderProtocol{
associatedtype T
func getItemAt(index:Int)-> T?
func replaceItemAt(index:Int, item:T?)
}
Then in your class you can use it as
class BaseDataProvider<SomeType> {
internal var _itemsPerPage:Int = 0
internal var _page:Int = 0
internal var _endpoint:String = ""
internal var cachedData:[SomeType?] = []
}
extension BaseDataProvider: PostDataProviderProtocol {
typealias T = SomeType
func hasNext() -> Bool {
true
}
func getItemAt(index: Int) -> T? {
self.cachedData[index]
}
func getItems() -> [T] {
return self.cachedData as! [T]
}
}
Swift: cannot convert value of type 'SomeType T ' to expected argument type 'SomeType _ '
The following code worked for me.
struct PageData<T> {
let item: T
let pageNumber: Int
}
protocol PagedServiceProvider: class {
associatedtype T
var pageData: PageData<T>? { get set }
func fetchPage(page: Int, completion: @escaping (PageData<T>?) -> Void)
}
class TestPagedServiceProvider: PagedServiceProvider {
var pageData: PageData<String>?
func fetchPage(page: Int, completion: @escaping (PageData<String>?) -> Void) {
completion(pageData)
}
}
Swift generic func cannot convert value of type to expected argument type
That's a compiler bug. Had the same issue when Xcode 10 came out.
Adapt your method to the following:
func importArray<T: ImportableUniqueObject>(from exercisesDict: [[String: Any]], transaction: BaseDataTransaction) -> [T] where T.ImportSource == [String: Any] {
let managedObjects = try? transaction.importUniqueObjects(Into<T>(), sourceArray: jsonObjects)
}
Though I recommend do not do force-try when importing.
Also see: https://bugs.swift.org/browse/SR-8945
Swift Generics: Cannot convert value of type to expected argument type
Swift 4.1 Update
This is a bug that was fixed in this pull request, which will make it into the release of Swift 4.1. Your code now compiles as expected in a 4.1 snapshot.
Pre Swift 4.1
This just looks like you're just stretching the compiler too far.
It can deal with conversions from arrays of sub-typed elements to arrays of super-typed elements, e.g
[A]
to[SomeProtocol]
– this is covariance. It's worth noting that arrays have always been an edge case here, as arbitrary generics are invariant. Certain collections, such asArray
, just get special treatment from the compiler allowing for covariance.It can deal with conversions of functions with super-typed parameters to functions with sub-typed parameters, e.g
(SomeProtocol) -> Void
to(A) -> Void
– this is contravariance.
However it appears that it currently cannot do both in one go (but really it should be able to; feel free to file a bug).
For what it's worth, this has nothing to do with generics, the following reproduces the same behaviour:
protocol SomeProtocol {}
class A : SomeProtocol {}
func f1(listener: (A) -> Void) {}
func f2(listener: ([A]) -> Void) {}
func f3(listener: () -> [SomeProtocol]) {}
func g() {
let l1: (SomeProtocol) -> Void = { _ in }
f1(listener: l1) // NO ERROR
let l2: ([SomeProtocol]) -> Void = { _ in }
f2(listener: l2)
// COMPILER ERROR: Cannot convert value of type '([SomeProtocol]) -> Void' to
// expected argument type '([A]) -> Void'
// it's the same story for function return types
let l3: () -> [A] = { [] }
f3(listener: l3)
// COMPILER ERROR: Cannot convert value of type '() -> [A]' to
// expected argument type '() -> [SomeProtocol]'
}
Until fixed, one solution in this case is to simply use a closure expression to act as a trampoline between the two function types:
// converting a ([SomeProtocol]) -> Void to a ([A]) -> Void.
// compiler infers closure expression to be of type ([A]) -> Void, and in the
// implementation, $0 gets implicitly converted from [A] to [SomeProtocol].
f2(listener: { l2($0) })
// converting a () -> [A] to a () -> [SomeProtocol].
// compiler infers closure expression to be of type () -> [SomeProtocol], and in the
// implementation, the result of l3 gets implicitly converted from [A] to [SomeProtocol]
f3(listener: { l3() })
And, applied to your code:
f2(ofType: A.self, listener: { l2($0) })
This works because the compiler infers the closure expression to be of type ([T]?) -> Void
, which can be passed to f2
. In the implementation of the closure, the compiler then performs an implicit conversion of $0
from [T]?
to [SomeProtocol]?
.
And, as Dominik is hinting at, this trampoline could also be done as an additional overload of f2
:
func f2<T : SomeProtocol>(ofType type: T.Type, listener: ([SomeProtocol]?) -> Void) {
// pass a closure expression of type ([T]?) -> Void to the original f2, we then
// deal with the conversion from [T]? to [SomeProtocol]? in the closure.
// (and by "we", I mean the compiler, implicitly)
f2(ofType: type, listener: { (arr: [T]?) in listener(arr) })
}
Allowing you to once again call it as f2(ofType: A.self, listener: l2)
.
Cannot convert value of generic associated type of protocol to expected argument type
The generic T
in your function and the associated type T
in your protocol aren't the same T
. Inside the function, T
is referring to the type that is implementing the protocol so the associatedtype is T.T
inside of the function. Your arrays and the return value would have to be using T.T
.
This also means that you will need an additional parameter to your function because the [[T.T]]
return value isn't enough for the compiler to infer what type T
is.
This should work (I changed the generic parameter to U
because all the T
s are confusing):
func dataSource<U: UniqueInit>(initializer: U.Type, nrRowsInSection: Int...) -> [[U.T]] {
var result: [[U.T]] = []
for nrRows in nrRowsInSection {
var row: [U.T] = []
for _ in 0 ..< nrRows {
row.append(U.uniqueInit())
}
result.append(row)
}
return result
}
Alternatively, you could define your function as an extension on UniqueInit
which would eliminate the need for the generics:
extension UniqueInit {
func dataSource(nrRowsInSection: Int...) -> [[T]] {
var result: [[T]] = []
for nrRows in nrRowsInSection {
var row: [T] = []
for _ in 0 ..< nrRows {
row.append(Self.uniqueInit())
}
result.append(row)
}
return result
}
}
Cannot convert value of type 'MyEnum T.Type ' to expected argument type 'MyEnum _ '
The error occurs because NetworkResponse
expects an instance of T
, while the mock tries to provide the actual T
.
So, you need to somehow provide an instance, however this cannot be generated by the mock as it doesn't have enough information about how to construct an instance.
I recommend injecting the success value from the outside, when creating the mock. You can do this either by making the mock class generic, or by making the Mode
enum generic. Below is a sample implementation for the latter:
class MockUrlSessionProvider: ProviderProtocol {
// making the enum generic, to support injecting the success value
enum Mode<T> {
case success(T)
case empty
case fail
}
// need to have this as `Any` to cover all possible T generic arguments
private var mode: Any
// however the initializer can be very specific
init<T>(mode: Mode<T>) {
self.mode = mode
}
func request<T>(type: T.Type, service: ServiceProtocol, completion: @escaping (NetworkResponse<T>) -> Void) where T: Decodable {
// if the mock was not properly configured, do nothing
guard let mode = mode as? Mode<T> else { return }
// alternatively you force cast and have the unit test crash, this should help catching early configuration issues
// let mode = mode as! Mode<T>
switch mode {
case let .success(value): completion(NetworkResponse.success(value))
case .empty: completion(.failure(.noData))
case .fail: completion(.failure(.unknown("Error")))
}
}
}
Cannot convert value of type '(Store).Type' to expected argument type 'Binding C '
Case sensitivity matters. You mean store
, the StoreViewModel
instance and not the type of self
. Further the purpose of a ForEach
expression is to iterate an array (presumably item(s)
).
First of all to avoid more confusion rename item
in StoreViewModel
as its plural form
class StoreViewModel: ObservableObject{
@Published var items: [String] = []
@Published var amount: [String] = []
}
Then replace
ForEach((Store), id: \.self){ item in
with
ForEach(store.items, id: \.self){ item in
Related Topics
Check for Launching from Uilocalnotification in Swift
Add Text Label and Button to Dynamic Tableview Cell Programmatically with Swift
Is Swift Inout Parameter a Variable or a Pointer
Disable Audio (And Interruption) with Mpmovieplayercontroller Using Swift
How to Create Type Erasing Weak References with Non-Optional Properties in Swift
How to Rounded the Corners When I Draw Rectangle Using Uibezierpath Points
iOS Screen Sharing (Using Replaykit) Using Webrtc in Swift
How to Convert a Float Value to Byte Array in Swift
How to Pass an Error Pointer in the Swift Language
Compiler Error: Invalid Library File - Corelocation
Swift: Get an Element from a Tuple
Swift Equivalent of Array.Componentsjoinedbystring
Format Float Value with 2 Decimal Places
Convert Int to Uint32 in Swift