Chciałbym utworzyć protokół z metodą, która pobiera ogólne dane wejściowe i zwraca ogólną wartość.
To jest to, czego do tej pory próbowałem, ale powoduje to błąd składni.
Stosowanie niezadeklarowanego identyfikatora T.
Co ja robię źle?
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
}
}
Odpowiedzi:
Trochę inaczej jest w przypadku protokołów. Spójrz na „Powiązane typy” w dokumentacji Apple .
Tak to wykorzystujesz w swoim przykładzie
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 } }
źródło
x
jest lokalny, nie musisz jawnie określać jego typu, więclet x = UserMapper()
.Aby wyjaśnić nieco odpowiedź Lou Franco , jeśli chcesz stworzyć metodę, która wykorzystywałaby konkret
ApiMapperProtocol
, zrób to w ten sposób: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
ma teraz gwarancję, że akceptuje tylkoSourceType
s zgodne z podanymiApiMapperProtocol
:let dictionary: NSDictionary = ... let uses = UsesApiMapperProtocol() let userModel: UserModel = uses.usesApiMapperProtocol(UserMapper() source: dictionary)
źródło
as!
zamiast tylkoas
Swift 1.2? Po drugie: czy możesz mi powiedzieć, dlaczego musimytype alias
ponownie zdefiniować (tj.typealias T = NSDictionary typealias U = UserModel
) W klasie, która jest zgodna z protokołem? Z góry dziękuję.as
naas!
. Sprawdź devforums.typealias T=NSDictionary
itypealias U=UserModel
nie są wymagane. Zaktualizowałem przykład, aby to odzwierciedlić.Aby uzyskać rodzajowe i deklarowane w ten sposób
let userMapper: ApiMapperProtocol = UserMapper()
, musisz mieć klasę generyczną zgodną z protokołem, który zwraca element generyczny.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 } }
Teraz możesz również odnosić się do tych
userMapper
,ApiMapper
które mają określoną implementację w kierunkuUserMapper
:let userMapper: ApiMapper = UserMapper() let userModel: UserModel = userMapper.MapFromSource(data: ...)
źródło
userMapper
.JAK TWORZYĆ I KORZYSTAĆ Z PROTOKOŁU OGÓLNEGO
protokół Generic {
associatedtype T associatedtype U func operation(_ t:T)->U
}
// użyj protokołu ogólnego
struct Test: Generic {
typealias T = UserModel typealias U = Any func operation(_ t: UserModel)->Any { let dict = ["name":"saurabh"] return dict }
}
źródło
Możesz używać metod szablonów z usuwaniem typów ...
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"))
źródło