Swift универсальный обратный вызов

#ios #swift #generics

#iOS #swift #универсальные

Вопрос:

В настоящее время я изучаю, как реализовать универсальную функцию. Я пытаюсь создать функцию, которая будет возвращать обратный вызов с универсальным типом

Вот мой код

 static func performPOST<T: DomainEntity>(action: Module, completion: @escaping (CallbackResponse, DomainObjectWrapper<T>?) -> Void) {

     //logic implementation at first

     switch action { 
          case .getMenuItem:
          self.alamofireManager.request(urlRequest, encoding: URLEncoding.default, headers: headers).responseObject { (response: DataResponse<DomainObjectWrapper<MenuItemDO>>) in
                var validateRequestResponse = RestHelper.validateRequestResponse(response: response)
                let responseObject = validateRequestResponse.responseObject

                if validateRequestResponse.isSuccess {}
                else {
                    if let errorMessage = responseObject?.error {
                        validateRequestResponse.message = errorMessage
                    }
                    else if let warningMessage = responseObject?.warning {
                        validateRequestResponse.message = warningMessage
                    }
                }
                callbackResponse = RestHelper.bindValidateRequestResponse(validateRequestResponse: validateRequestResponse)
                completion(callbackResponse, responseObject)
            }
          case .makeSales: break
          case .attendance: break
     }
}
  

Я получаю эту ошибку из Xcode. Это не позволит мне скомпилироваться.

 completion(callbackResponse, responseObject) <<-- This Line

Cannot convert value of type 'DomainObjectWrapper<MenuItemDO>?' to expected argument type 'DomainObjectWrapper<_>?'
  

Вот мои другие классы

 public class DomainObjectWrapper<T: Mappable>: Mappable {
     public var data = [T]()
}

public class DomainEntity: Mappable {
     public var id = UUID().uuidString
     public var isDeleted = false
}

public class MenuItemDO: DomainEntity {
     public var categoryId: String?
     public var categoryName: String?
}
  

Кто-нибудь может подсказать мне, чего мне не хватает?

Спасибо

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

1. Как вы вызываете этот метод? На какой строке вы получаете сообщение об ошибке? Можете ли вы дополнить вопрос этими деталями?

2. Как вы думаете, почему ваш метод должен быть универсальным?

3. Привет @Cristik, Xcode не будет компилировать код. Ошибка компилятора указана выше. Спасибо

4. @Sweeper, потому что будет много вызовов API, которые вернут DomainObjectWrapper<DifferentValue> . Итак, я думаю, что создание универсальной функции поможет мне избежать избыточного кода. Спасибо

Ответ №1:

потому что будет много вызовов API, которые вернут DomainObjectWrapper. Итак, я думаю, что создание универсальной функции поможет мне избежать избыточного кода. Спасибо

Если это так, то вы бы использовали DataResponse<DomainObjectWrapper<T>> вместо DataResponse<DomainObjectWrapper<MenuItemDO>> в параметре закрытия вызова Alamofire:

 static func performPOST<T: DomainEntity>(action: Module, completion: @escaping (CallbackResponse, DomainObjectWrapper<T>?) -> Void) {

     //logic implementation at first

     switch action { 
          // this line
          self.alamofireManager.request(urlRequest, encoding: URLEncoding.default, headers: headers).responseObject { (response: DataResponse<DomainObjectWrapper<T>>) in // <----- this line
                var validateRequestResponse = RestHelper.validateRequestResponse(response: response)
                let responseObject = validateRequestResponse.responseObject

                if validateRequestResponse.isSuccess {}
                else {
                    if let errorMessage = responseObject?.error {
                        validateRequestResponse.message = errorMessage
                    }
                    else if let warningMessage = responseObject?.warning {
                        validateRequestResponse.message = warningMessage
                    }
                }
                callbackResponse = RestHelper.bindValidateRequestResponse(validateRequestResponse: validateRequestResponse)
                completion(callbackResponse, responseObject)
            }
     }
}
  

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

1. Привет, подметальщик. Большое спасибо за ваш ответ. Я получаю ошибку в коде завершения (). В принципе, мой ResponseObject верен. Однако каким-то образом родительская функция обратного вызова не распознает мой блок завершения внутри корпуса switch (ResponseObject). Надеюсь, вы понимаете, что я имею в виду. Спасибо

2. @Alvin О, я только что понял! Почему у вас нет switch have case s? И какую ошибку вы получаете?

3. Привет, на самом деле есть, я просто пытаюсь упростить свой код для объяснения здесь :). Ошибка — это та, которую я указал в своем вопросе :). Спасибо!

4. @Alvin Ты изменил DataResponse<DomainObjectWrapper<MenuItemDO>> на DataResponse<DomainObjectWrapper<T>> , как я тебе сказал? Если это так, сообщение об ошибке не должно появляться. Или вы имеете в виду, что получаете сообщение об ошибке при вызове performPOST ?

5. Я изменил его. Но я не смог получить свое свойство MenuItemDO. Я не смог получить данные из JSON. Я могу получить только свойство DomainEntity. Есть ли обходной путь для этого? Или моя функция неверна в начале? Я обновил структуру других моих классов. Пожалуйста, направьте меня. Спасибо

Ответ №2:

Недавно я создал подходящее решение для функций с общими параметрами. Вот пример шаблона командной строки. Таким образом, вы могли бы использовать этот шаблон, получая обратный вызов с универсальным параметром.

 protocol ParameterCommand {
    func execute(with parameter: Any)
}

protocol CallbackCommand: ParameterCommand {
    associatedtype CallBackParameterType
    func execute(with callback: @escaping (CallBackParameterType) -> Void)
}

extension CallbackCommand {
    func execute(with parameter: Any) {
        if let parameter = parameter as? (CallBackParameterType) -> Void {
            execute(with: parameter)
        }
    }
}