Я хотел бы создать протокол с методом, который принимает общий ввод и возвращает общее значение.
Это то, что я пробовал до сих пор, но он вызывает синтаксическую ошибку.
Использование необъявленного идентификатора T.
Что я делаю неправильно?
protocol ApiMapperProtocol {
func MapFromSource(T) -> U
}
class UserMapper: NSObject, ApiMapperProtocol {
func MapFromSource(data: NSDictionary) -> UserModel {
var user = UserModel() as UserModel
var accountsData:NSArray = data["Accounts"] as NSArray
return user
}
}
Ответы:
Для протоколов все немного иначе. Посмотрите «Связанные типы» в документации Apple .
Вот как вы используете это в своем примере
protocol ApiMapperProtocol { associatedtype T associatedtype U func MapFromSource(_:T) -> U } class UserMapper: NSObject, ApiMapperProtocol { typealias T = NSDictionary typealias U = UserModel func MapFromSource(_ data:NSDictionary) -> UserModel { var user = UserModel() var accountsData:NSArray = data["Accounts"] as NSArray // For Swift 1.2, you need this line instead // var accountsData:NSArray = data["Accounts"] as! NSArray return user } }
источник
x
локальный, вам не нужно явно указывать его тип, поэтомуlet x = UserMapper()
.Чтобы немного разъяснить ответ Лу Франко , если вы хотите создать метод, который использует конкретный
ApiMapperProtocol
, вы делаете это следующим образом:protocol ApiMapperProtocol { associatedtype T associatedtype U func mapFromSource(T) -> U } class UserMapper: NSObject, ApiMapperProtocol { // these typealiases aren't required, but I'm including them for clarity // Normally, you just allow swift to infer them typealias T = NSDictionary typealias U = UserModel func mapFromSource(data: NSDictionary) -> UserModel { var user = UserModel() var accountsData: NSArray = data["Accounts"] as NSArray // For Swift 1.2, you need this line instead // var accountsData: NSArray = data["Accounts"] as! NSArray return user } } class UsesApiMapperProtocol { func usesApiMapperProtocol< SourceType, MappedType, ApiMapperProtocolType: ApiMapperProtocol where ApiMapperProtocolType.T == SourceType, ApiMapperProtocolType.U == MappedType>( apiMapperProtocol: ApiMapperProtocolType, source: SourceType) -> MappedType { return apiMapperProtocol.mapFromSource(source) } }
UsesApiMapperProtocol
теперь гарантированно принимает толькоSourceType
s, совместимые с даннымApiMapperProtocol
:let dictionary: NSDictionary = ... let uses = UsesApiMapperProtocol() let userModel: UserModel = uses.usesApiMapperProtocol(UserMapper() source: dictionary)
источник
as!
вместоas
Swift 1.2? Во-вторых: не могли бы вы сказать мне, почему нам нужноtype alias
снова определить (т.е.typealias T = NSDictionary typealias U = UserModel
) в классе, который соответствует протоколу? Заранее спасибо.as
наas!
. Проверить форумы.typealias T=NSDictionary
иtypealias U=UserModel
не требуются. Я обновил пример, чтобы отразить это.Чтобы добиться наличия универсальных шаблонов, а также объявить его таким образом,
let userMapper: ApiMapperProtocol = UserMapper()
вы должны иметь универсальный класс, соответствующий протоколу, который возвращает универсальный элемент.protocol ApiMapperProtocol { associatedtype I associatedType O func MapFromSource(data: I) -> O } class ApiMapper<I, O>: ApiMapperProtocol { func MapFromSource(data: I) -> O { fatalError() // Should be always overridden by the class } } class UserMapper: NSObject, ApiMapper<NSDictionary, UserModel> { override func MapFromSource(data: NSDictionary) -> UserModel { var user = UserModel() as UserModel var accountsData:NSArray = data["Accounts"] as NSArray return user } }
Теперь вы также можете ссылаться на
userMapper
то,ApiMapper
что имеет конкретную реализацию дляUserMapper
:let userMapper: ApiMapper = UserMapper() let userModel: UserModel = userMapper.MapFromSource(data: ...)
источник
userMapper
.КАК СОЗДАТЬ И ИСПОЛЬЗОВАТЬ ОБЩИЙ ПРОТОКОЛ
protocol Generic {
associatedtype T associatedtype U func operation(_ t:T)->U
}
// использовать общий протокол
struct Test: Generic {
typealias T = UserModel typealias U = Any func operation(_ t: UserModel)->Any { let dict = ["name":"saurabh"] return dict }
}
источник
Вы можете использовать методы шаблонов со стиранием типа ...
protocol HeavyDelegate : class { func heavy<P, R>(heavy: Heavy<P, R>, shouldReturn: P) -> R } class Heavy<P, R> { typealias Param = P typealias Return = R weak var delegate : HeavyDelegate? func inject(p : P) -> R? { if delegate != nil { return delegate?.heavy(self, shouldReturn: p) } return nil } func callMe(r : Return) { } } class Delegate : HeavyDelegate { typealias H = Heavy<(Int, String), String> func heavy<P, R>(heavy: Heavy<P, R>, shouldReturn: P) -> R { let h = heavy as! H h.callMe("Hello") print("Invoked") return "Hello" as! R } } let heavy = Heavy<(Int, String), String>() let delegate = Delegate() heavy.delegate = delegate heavy.inject((5, "alive"))
источник