Sendability of function types in instance method 'dataTask(with:completionHandler:)' does not match requirement in protocol 'URLSessionProtocol' - swift

I am getting below warning while writing URLSessionProtocol.
What could be the reason?
protocol URLSessionProtocol {
typealias DataTaskResult = (Data?, URLResponse?, Error?) -> Void
func dataTask(with request: URLRequest, completionHandler: #escaping DataTaskResult) -> URLSessionDataTask
}
extension URLSession: URLSessionProtocol { }

simple change it to
typealias DataTaskResult = #Sendable (Data?, URLResponse?, Error?) -> Void

Related

Protocol with associatedtype conformance with generic gives compiler error

I'm trying to make a DB mock to test some UI implementations, but compiler keeps giving me the following error:
Type 'DBClientMock<T>' does not conform to protocol 'DBClient'
This is my code...
protocol DBClient {
associatedtype Model
func get(id: UUID, completion: #escaping ((Model?, Error?)) -> Void)
func insert(_ model: Model, completion: #escaping (Error?) -> Void)
func delete(_ model: Model, completion: #escaping (Error?) -> Void)
}
final class DBClientMock<T>: DBClient where T: Identifiable, T: Equatable {
typealias Model = T
private let queue: DispatchQueue
private var modelDB = [T]()
enum Error: Swift.Error {
case notFound
}
init(queue: DispatchQueue = DispatchQueue.global()) {
self.queue = queue
}
private func getModel(id: UUID) -> T? {
let results = modelDB.filter({ $0.id as? UUID == id })
guard results.count > 0 else { return nil }
return results[0]
}
// Extension
func get(id: UUID, completion: #escaping ((T?, Error?)) -> Void) {
let record = getModel(id: id)
queue.asyncAfter(deadline: .now() + .milliseconds(1500), execute: {
if let model = record {
completion((model, nil))
} else {
completion((nil, Error.notFound))
}
})
}
func insert(_ model: T, completion: #escaping (Error?) -> Void) {
modelDB.append(model)
queue.asyncAfter(deadline: .now() + .milliseconds(1000), execute: {
completion(nil)
})
}
func delete(_ model: T, completion: #escaping (Error?) -> Void) {
modelDB.removeAll(where: { $0 == model })
queue.asyncAfter(deadline: .now() + .milliseconds(800), execute: {
completion(nil)
})
}
}
XCode: Version 12.4 (12D4e)
Swift: 5.0
What am I doing wrong? Do I have to be more explicit with the generic type in some way? I tried replacing T with Model but had the same result.
Thanks for your help!
It doesn't conform because you declared another Error type inside the class, so everywhere where you use Error in the required methods, it uses DBClientMock.Error instead of the protocol-required Swift.Error.
Either rename DBClientMock.Error to something else, or change the Error in methods to Swift.Error, like below:
// Extension
func get(id: UUID, completion: #escaping (T?, Swift.Error?) -> Void) {
//...
}
func insert(_ model: T, completion: #escaping (Swift.Error?) -> Void) {
//...
}
func delete(_ model: T, completion: #escaping (Swift.Error?) -> Void) {
//...
}

save escaping method reference in swift

I am a Java/Kotlin programmer and new to swift. I want to pass a method reference in a constructor to save it for later use. The method I want to pass looks like this:
func refresh(completion: #escaping (Error?) -> ()) {
...
}
What I want to do is instantiate an object and pass this method as a parameter like this:
refreshControl = Refresher() {
compl -> Void in
self.refresh(completion: compl)
}
The class I want to pass this function to looks like this:
class Refresher {
let refresh: (#escaping (Error?) -> ()) -> Void
init(refresh: (#escaping (Error?) -> ()) -> Void) {
self.refresh = refresh
}
// call refresh somewhere later
}
This does not compile with error "Assigning non-escaping parameter 'refresh' to an #escaping closure. Not entirely sure what escaping does but I know I need it in the actual refresh function. I am not sure how to syntax this right. Any help would be appreciated.
But Xcode tells you what to do. It offers you a Fix-It:
init(refresh: #escaping (#escaping (Error?) -> ()) -> Void) {
Personally I would then get rid of the other #escaping stuff you've put in, as it is not needed. So:
class Refresher {
let refresh: ((Error?) -> ()) -> Void
init(refresh: #escaping ((Error?) -> ()) -> Void) {
self.refresh = refresh
}
}
And elsewhere:
func refresh(completion: (Error?) -> ()) {
// ...
}
func f() {
let refreshControl = Refresher() {
compl -> Void in
self.refresh(completion: compl)
}
// ...
}

Protocol composition confusing

I have protocols SocketIORepresentable and Typeable. Typeable is protocol with associatedType. Why I have error when i try to create protocol composition in my func?
swift 5.0
import Foundation
protocol Typeable {
associatedtype Item: Decodable
var responseType: Item.Type { get }
}
protocol SocketIORepresentable {
func representable() throws -> [Any]
}
extension SocketIORepresentable where Self: Encodable {
func representable() throws -> [Any] {
let tempSendData = try JSONEncoder().encode(self)
return [try JSONSerialization.jsonObject(with: tempSendData, options: .allowFragments)]
}
}
public struct APIRequest: Encodable {
let type: String
let payload: Data
let ts = Date()
}
extension APIRequest: SocketIORepresentable {}
public struct Request<T: Decodable>: Typeable {
let apiRequest: APIRequest
var responseType: T.Type
public init(apiRequest: APIRequest) {
self.apiRequest = apiRequest
self.responseType = T.self
}
}
private func sendRequest<T: Typeable>(_ request: T & SocketIORepresentable, completion: #escaping (Result<T.Item, Error>) -> Void) {
}
T is not a protocol. T is a concrete type that conforms to Typeable. You cannot then say that request must be "of the concrete type T and also conforms to SocketIORepresentable." What you meant is that T is a concrete type that conforms to both:
private func sendRequest<T: Typeable & SocketIORepresentable>(_ request: T, completion: #escaping (Result<T.Item, Error>) -> Void) { ... }
Typically you'd write this with a where clause instead to avoid such a large angle-bracket:
private func sendRequest<T>(_ request: T, completion: #escaping (Result<T.Item, Error>) -> Void)
where T : Typeable & SocketIORepresentable { ... }

Class Initializer with #escaping parameter

I'm setting up a class that can ideally store an async method for later use. I would like to pass a function inside of class initializer but I'm running into a weird compiler issue.
Cannot convert value of type '(#escaping (Int) -> Void) -> ()' to expected argument type '((Int) -> Void) -> Void'
If the method is not escaping/sync this works fine. The compiler also suggest to force cast the parameter as! (((Int) -> Void) -> Void). Gave that a shot but it crashes.
Here's an example I've been messing with in a playground:
class NumberTwo {
let numberTwoMethod: ((Int) -> Void) -> Void
init(numberTwoMethod: #escaping ((Int) -> Void) -> Void) {
self.numberTwoMethod = numberTwoMethod
}
func callNumberTwoMethod() {
numberTwoMethod { myNum in
print(myNum)
}
}
}
func getNumberTwoMethod(completion: #escaping (Int) -> Void) {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
completion(2)
}
}
func getNumberTwoMethodSync(completion: (Int) -> Void) {
completion(2)
}
NumberTwo(numberTwoMethod: getNumberTwoMethod) // error: cannot convert value of type '(#escaping (Int) -> Void) -> ()' to expected argument type '((Int) -> Void) -> Void'
NumberTwo(numberTwoMethod: getNumberTwoMethodSync) // Works
Any suggestions on what's going on here or alternative ways of storing an async function as a variable in a class?
You are missing #escaping on the inner closure:
class NumberTwo {
let numberTwoMethod: (#escaping (Int) -> Void) -> Void
init(numberTwoMethod: #escaping (#escaping (Int) -> Void) -> Void) {
self.numberTwoMethod = numberTwoMethod
}
func callNumberTwoMethod() {
numberTwoMethod { myNum in
print(myNum)
}
}
}
or slightly simplified:
class NumberTwo {
typealias CompletionHandler = (Int) -> Void
let numberTwoMethod: (#escaping CompletionHandler) -> Void
init(numberTwoMethod: #escaping (#escaping CompletionHandler) -> Void) {
self.numberTwoMethod = numberTwoMethod
}
func callNumberTwoMethod() {
numberTwoMethod { myNum in
print(myNum)
}
}
}
Also note this will probably create a memory leak since there is no weak anywhere.

Generic understanding issue

I was reading Alamofire example, below is the function declaration is not clear to me what does this mean: Response<T, NSError> -> Void
public func responseObject<T: ResponseJSONObjectSerializable>
(completionHandler: Response<T, NSError> -> Void) -> Self {
////
}