[swift] Swift에서 일반 프로토콜을 만드는 방법은 무엇입니까?

제네릭 입력을 받아 제네릭 값을 반환하는 메서드로 프로토콜을 만들고 싶습니다.

이것은 지금까지 시도한 것이지만 구문 오류가 발생합니다.

선언되지 않은 식별자 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의 문서 에서 “Associated Types” 보십시오 .

이것이 귀하의 예에서 사용하는 방법입니다.

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
    }
}


답변

Lou Franco의 대답 을 조금 설명하려면 특정을 사용하는 메서드를 만들고 싶다면 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)


답변

제네릭 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: ...)


답변

일반 프로토콜을 생성하고 사용하는 방법

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"))


답변