Значение типа протокола ‘InheritingProtocol: протокол’ не может соответствовать ‘Протоколу’

#swift #generics #model-view-controller #protocols #delegation

#swift #общие #модель-представление-контроллер #протоколы #делегирование

Вопрос:

У меня есть приведенный ниже код, который нацелен на abstraction — без Decodable необходимости использовать s — для DataModel s в приложении. Я хотел использовать эти DataModel s для их центрирования. Вот как я далеко зашел прямо сейчас, и я как бы в тупике.

В этой конфигурации код сообщает мне, что ProfileResponseDelegate не может соответствовать ModelDelegate when ProfileResponseDelegate is a protocol , что имеет смысл.

 protocol ModelDelegate: class {
    
    associatedtype DataType: Decodable
    func didReceive(data: DataType)
    
}

class Model<Type, Delegate: ModelDelegate> where Type == Delegate.DataType {
    
    var data: Type?
    weak var delegate: Delegate?
    
    func requestData() { return }
    
}

protocol ProfileResponseDelegate: ModelDelegate where DataType == ProfileResponse {}

//throws Value of protocol type 'ProfileResponseDelegate' cannot conform to 'ModelDelegate'; only struct/enum/class types can conform to protocols
class ProfileResponseModel: Model<ProfileResponse, ProfileResponseDelegate> {
    
    override func requestData() {
        guard let data = data else {
            // go to api to get data
            return
        }
        delegate?.didReceive(data: data)
    }
}

class Controller: UIViewController, ProfileResponseDelegate {
    
    let model = ProfileResponseModel()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        model.delegate = self
        model.requestData()
    }
    
    func didReceive(data: ProfileResponse) {
        //tell view code to update regarding data
    }
}
  

Когда я меняю ProfileResponseDelegate значение на a class — не будучи delegate больше a, но в любом случае — код не позволяет Controller наследовать от обоих UIViewController , и ProfileResponseDelegate рассуждение a class не может наследовать от нескольких class es. что опять же имеет смысл.

 class ProfileResponseDelegate: ModelDelegate {
    typealias DataType = ProfileResponse
    func didReceive(data: ProfileResponse) {
       return
    }
}


class Controller: UIViewController, ProfileResponseDelegate {
    
    let model = ProfileResponseModel()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        model.delegate = self
        model.requestData()
    }
    
    override func didReceive(data: ProfileResponse) {
        //tell view code to update regarding data
    }
}
  

Что касается первой конфигурации, я не смог заставить ее работать. Однако для второго, когда Controller он просто наследуется от ProfileResponseDelegate него, работает просто отлично.

Я должен найти способ заставить это работать — предпочтительно первую конфигурацию — и нуждаюсь в вашем совете. Заранее благодарен.

Обновить

Итак, я удалил associatedType из ModelDelegate и удалил ProfileResponseModel . Прямо сейчас код выглядит следующим образом.

 protocol ModelDelegate: class {
    
    //associatedtype DataType: Decodable
    func didReceive<T: Decodable>(data: T)
    
}

class Model<Type: Decodable> {
    
    var data: Type?
    weak var delegate: ModelDelegate?
    
    func requestData() { return }
    
}

//protocol ProfileResponseDelegate: ModelDelegate where DataType == ProfileResponse {}

class ProfileResponseModel: Model<ProfileResponse> {
    
    override func requestData() {
        guard let data = data else {
            // go to api to get data
            return
        }
        delegate?.didReceive(data: data)
    }
}

class Controller: UIViewController, ModelDelegate {
    
    
    let model = ProfileResponseModel()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        model.delegate = self
        model.requestData()
    }
    
    func didReceive<T>(data: T) where T : Decodable {
        //I want this `data` to come as what it is.
        if let response = data as? ProfileResponse {
            print(type(of: response))
        }
    }
}
  

Это работает так, однако моя конечная цель для этого — не приводить data ProfileResponse здесь — и в других местах — к другому Decodable типу.

Комментарии:

1. Первый никогда не может работать. Это не то, что протоколы.

2. Какие-либо обходные пути? @matt

3. Передайте обработчик завершения requestData() вместо того, чтобы пытаться принудить делегата к этому. Здесь вполне возможно создать делегата, но это слишком сложно для этой проблемы, и обработчик завершения значительно упростит все это. Для более общего подхода к более крупной проблеме см. youtube.com/watch?v=DXwJg0QTlZE а для другого (еще более продвинутого) подхода см. davedelong.com/blog/2020/06/27/http-in-swift-part-1

4. Ваш первый подход на самом деле ближе к цели, чем ваш второй. Во-вторых, вы сказали, что делегат должен иметь дело с любым декодируемым, который ему передается. Это противоположно тому, что вы хотите. Ваш первый подход технически ближе, но его фактическая работа приведет вас на ложный путь.

5. Спасибо за ваш ответ. Я сейчас смотрю ваш лейтмотив и изучил более продвинутую реализацию. И у меня возникла мысль о том, что, возможно, я ошибался, начиная с кода клиента API. Я написал клиент, очень похожий Moya на библиотеку с универсальными функциями. И для огромного процесса рефакторинга, в котором я нахожусь, я стараюсь убрать как можно больше кода из контроллеров представления. Я также включил сетевой код в этот контекст. Цель приведенного выше кода — обеспечить интерфейс между моделью и контроллером, и, таким образом, будет ModelController, который управляет данными во всем приложении.