Как реализовать общий протокол, в котором есть функция, использующая тип ассоциированного типа?

Я создаю некоторый класс, подтверждающий общий протокол, этот общий протокол имеет метод, который принимает параметр типа associatedtype, я использую Xcode для создания заглушки для меня:


import UIKit

struct SomeObject: Codable {
    var id: String?
    var name: String?
}

protocol INetworkManager {
    associatedtype ResponseObject
    func get(url: String, ofType: ResponseObject.Type, completion: (ResponseObject?, Error?) -> Void)
}

class NetworkManager: INetworkManager {
    typealias ResponseObject = Codable

    func get(url: String, ofType: ResponseObject.Protocol, completion: (ResponseObject?, Error?) -> Void) {
        completion(SomeObject(id: "1", name: "hello"), nil)
    }
}

Вместо ResponseObject.Type он генерирует ResponseObject.Protocol для меня, я на самом деле не знаю, что это за ResponseObject.Protocol, и я не могу передать SomeObject.self в качестве параметра следующим образом:

let networkManager = NetworkManager()
networkManager.get(url: "http://whatever.com", ofType: SomeObject.self) { (responseObject, error) in
    print("got response object named: \(responseObject.name)")
}

компилятор выдал мне эту ошибку:

error: Cannot convert value of type 'SomeObject.Type' to expected argument type 'NetworkManager.ResponseObject.Protocol' (aka '(Decodable & Encodable).Protocol')

Я думаю, что что-то не так с моей реализацией, кто-нибудь может дать мне какие-либо идеи?

Спасибо!

Пожалуйста, не могли бы вы исправить MCVE. Ваш класс не соответствует протоколу.

JeremyP 30.05.2019 12:57

Чего вы пытаетесь достичь? Когда у вас есть associatedtype на protocol, то нет необходимости передавать его в качестве аргумента функции. Вы можете напрямую использовать MyType.self в методе.

Kamran 30.05.2019 13:00

@JeremyP Извините за мою ошибку, приведенный выше фрагмент кода теперь исправлен.

Yiming Dong 31.05.2019 01:36

@Kamaran На самом деле, я хочу написать общий протокол для своего NetworkManager, в котором метод get принимает класс Codable. Я обновил приведенный выше фрагмент, чтобы показать, чего я хочу достичь, пожалуйста, посмотрите, спасибо.

Yiming Dong 31.05.2019 01:46

Передача типов в Swift — это плохой запах. Вам почти никогда не нужно это делать. Переосмыслите это.

matt 31.05.2019 01:58

@matt Мне нужен метод get, чтобы вернуть объект этого Type, и этот Type различается в разных конечных точках API, что мне делать, кроме передачи типов?

Yiming Dong 01.06.2019 04:44
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
6
151
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Это не то, как работают ассоциированные типы. get должен быть универсальным для своего типа ответа, но сам сетевой менеджер не является универсальным для определенного типа ответа. Я считаю, что вы имели в виду вот это:

protocol NetworkManager {
    func get<ResponseObject>(url: String, 
                             ofType: ResponseObject.Type, 
                             completion: (Result<ResponseObject, Error>) -> Void) 
    where ResponseObject: Decodable
}

class TrivialNetworkManager: NetworkManager {
    func get<ResponseObject>(url: String, 
                             ofType: ResponseObject.Type, 
                             completion: (Result<ResponseObject, Error>) -> Void) 
    where ResponseObject: Decodable {
        completion(.success(SomeObject(id: "1", name: "hello"))
    }
}

Для более подробной версии этой конкретной проблемы вы можете прочитать мой серия протоколов, но важная концепция здесь заключается в том, что NetworkManager не зависит от своего ResponseType, поэтому нет причин делать его ResponseType ассоциированным типом.

То, что вы написали, пытается сказать: «Некоторые сетевые менеджеры будут иметь Codable ResponseType, а другие сетевые менеджеры будут иметь какой-то другой тип ResponseType». Не «какой-то другой конкретный тип ответа (например, User)», а «какой-то другой протокол, которому должны соответствовать его типы ответов». Хотя создать что-то подобное можно, это гораздо сложнее, и вам нужно будет объяснить свой конкретный вариант использования, чтобы спроектировать его. В частности, вам нужно будет показать несколько конкретных реализаций вашего протокола, чтобы увидеть, какой общий код вы пытаетесь извлечь.

Привет, Роб, спасибо за подробный ответ! Я должен был пропустить использование associatedtype, которое означало, что оно может быть разным для разных конкретных классов, и не для этого случая использования. Я изменю свой код, чтобы вместо этого использовать общий метод в протоколе.

Yiming Dong 01.06.2019 11:56

Другие вопросы по теме