स्विफ्ट में जेनेरिक प्रोटोकॉल कैसे बनाएं?


85

मैं एक विधि के साथ एक प्रोटोकॉल बनाना चाहता हूं जो एक सामान्य इनपुट लेता है और एक सामान्य मूल्य देता है।

यह वही है जो मैंने अब तक कोशिश की है, लेकिन यह सिंटैक्स त्रुटि पैदा करता है।

अघोषित पहचानकर्ता का उपयोग टी।

मैं क्या गलत कर रहा हूं?

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

कृपया मेरे उत्तर की जाँच करें: stackoverflow.com/a/54900296/3564632
denis_lor

जवाबों:


141

यह प्रोटोकॉल के लिए थोड़ा अलग है। एप्पल के प्रलेखन में "एसोसिएटेड प्रकार" को देखें

यह आप अपने उदाहरण में इसका उपयोग कैसे करते हैं

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

5
ध्यान दें कि ApiMapperProtocol का एकमात्र उद्देश्य सामान्य बाधा के लिए उपयोग किया जाना है। ऐसा नहीं है कि आप x लिख सकते हैं: ApiMapperProtocol = UserMapper ()
बेन

18
क्यों Apple सब कुछ इतना सहज बनाने पर जोर देता है?
डेस्परोग्रामग्राम

@ इस मामले में कोई कैसे x को प्राप्त करेगा: ApiMapperProtocol = UserMapper ()?
डेनिस_क्लोर

@denis_lor यदि xस्थानीय है, तो आपको इसके प्रकार को स्पष्ट रूप से कहने की आवश्यकता नहीं है, इसलिए let x = UserMapper()
बेन लेगिएरो

2
@BenLeggiero मुझे अभी पता चला है कि आप लेट x जैसे काम कर सकते हैं: ApiMapperProtocol = UserMapper () यदि मध्यम सामान्य वर्ग में उपयोग किया जा रहा है: stackoverflow.com/a/54900296-3564632
denis_lor

21

पर व्याख्या करने के लिए लो फ्रेंको जवाब एक सा है, तो आप एक विधि है कि एक विशेष इस्तेमाल किया बनाना चाहता था, तो ApiMapperProtocolआप ऐसा thusly कार्य करें:

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दिए गए के साथ संगत स्वीकार करने की गारंटी है ApiMapperProtocol:

let dictionary: NSDictionary = ...
let uses = UsesApiMapperProtocol()
let userModel: UserModel = uses.usesApiMapperProtocol(UserMapper()
    source: dictionary)

यह एक बहुत अच्छा लेखन है, उत्थान है। मूर्खतापूर्ण सवालों के एक जोड़े: वे स्विफ्ट 1.2 में as!सिर्फ के बजाय का उपयोग करने का फैसला क्यों किया as? दूसरा: क्या आप मुझे बता सकते हैं कि हमें उस वर्ग में type aliasफिर से (यानी typealias T = NSDictionary typealias U = UserModel) को परिभाषित करने की आवश्यकता क्यों है जो प्रोटोकॉल के अनुरूप है? अग्रिम में धन्यवाद।
उन्हेलिग

मुझे नहीं पता कि उन्होंने क्यों स्विच asकिया as!। देवफोरम की जाँच करें।
हीथ बॉर्डर्स

typealias T=NSDictionaryऔर typealias U=UserModelआवश्यकता नहीं है। मैंने यह दर्शाने के लिए उदाहरण को अद्यतन किया।
हीथ बॉर्डर्स

2
जैसा! यह इंगित करने में विफल हो सकता है। इसे डेवलपर के लिए स्पष्ट करता है।
user965972

यह उत्तर के निचले भाग पर है।
हीथ बॉर्डर्स

4

जेनेरिक प्राप्त करने के लिए और साथ ही इसे इस तरह घोषित 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
एलेकॉप

-1

कैसे उपयोग करें और सामान्य व्यावसायिक उपयोग करें

प्रोटोकॉल जेनेरिक {

associatedtype T
associatedtype U

func operation(_ t:T)->U

}

// जेनेरिक प्रोटोकॉल का उपयोग करें

संरचना परीक्षण: सामान्य {

typealias T = UserModel
typealias U = Any

func operation(_ t: UserModel)->Any {
    let dict = ["name":"saurabh"]
    return dict
    
} 

}


-3

आप प्रकार-मिटाने के साथ टेम्पलेट विधियों का उपयोग कर सकते हैं ...

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

2
इस पोस्ट में कोई स्पष्टीकरण नहीं है। आपने इसे भी पोस्ट किया है जैसा कि stackoverflow.com/questions/28614990/…
user1427799
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.