प्रोटोकॉल का उपयोग केवल एक सामान्य बाधा के रूप में किया जा सकता है क्योंकि इसमें स्व या संबद्धता संबंधी आवश्यकताएं हैं


101

मेरे पास एक प्रोटोकॉल रिक्वेस्ट है और इसमें नीचे की तरह संबंधित मॉडल है।

public protocol RequestType: class {

    associatedtype Model
    var path: String { get set }

}

public extension RequestType {

    public func executeRequest(completionHandler: Result<Model, NSError> -> Void) {
        request.response(rootKeyPath: rootKeyPath) { [weak self] (response: Response<Model, NSError>) -> Void in
            completionHandler(response.result)
            guard let weakSelf = self else { return }
            if weakSelf.logging { debugPrint(response) }
        }
    }

}

अब मैं सभी विफल अनुरोधों की एक कतार बनाने की कोशिश कर रहा हूं।

public class RequestEventuallyQueue {

    static let requestEventuallyQueue = RequestEventuallyQueue()
    let queue = [RequestType]()

}

लेकिन मुझे लाइन में let queue = [RequestType]()यह त्रुटि मिलती है कि प्रोटोकॉल रिक्वेस्ट का उपयोग केवल एक सामान्य बाधा के रूप में किया जा सकता है क्योंकि इसमें स्व या संबद्धता संबंधी आवश्यकताएं हैं।

जवाबों:


152

उस समय के लिए मान लीजिए कि हम आपके प्रोटोकॉल को संबद्ध प्रकार का उपयोग करने वाली दिनचर्या को जोड़ने के लिए समायोजित करते हैं:

public protocol RequestType: class {
    associatedtype Model
    var path: String { get set }

    func frobulateModel(aModel: Model)
}

और स्विफ्ट आप RequestTypeजिस तरह से आप चाहते हैं की एक सरणी बनाने के लिए थे। मैं फ़ंक्शन में उन अनुरोध प्रकारों की एक सरणी पास कर सकता हूं:

func handleQueueOfRequests(queue: [RequestType]) {
    // frobulate All The Things!

    for request in queue {
       request.frobulateModel(/* What do I put here? */)
    }
}

मैं इस बात के लिए नीचे आता हूं कि मैं सभी चीजों को फिर से बनाना चाहता हूं, लेकिन मुझे यह जानना होगा कि कॉल में किस प्रकार का तर्क पारित करना है। मेरी कुछ RequestTypeसंस्थाएँ एक ले सकती हैं LegoModel, कुछ PlasticModelऔर ले सकती हैं , और कुछ और ले सकती हैं PeanutButterAndPeepsModel। स्विफ्ट अस्पष्टता से खुश नहीं है इसलिए यह आपको एक प्रोटोकॉल का एक वैरिएबल घोषित नहीं करने देगा जिसमें एक संबद्ध प्रकार है।

एक ही समय में, यह सही समझ में आता है, उदाहरण के लिए, RequestTypeजब हम जानते हैं कि उनमें से सभी का उपयोग करने का एक सरणी बनाएँ LegoModel। यह उचित लगता है, और यह है, लेकिन आपको इसे व्यक्त करने के लिए किसी तरह की आवश्यकता है।

ऐसा करने का एक तरीका एक वर्ग (या संरचना, या एनम) बनाना है जो एक वास्तविक प्रकार को अमूर्त मॉडल प्रकार के नाम से जोड़ता है:

class LegoRequestType: RequestType {
  typealias Model = LegoModel

  // Implement protocol requirements here
}

अब यह पूरी तरह से उचित है LegoRequestTypeकि हम एक सरणी की घोषणा करें क्योंकि यदि हम frobulateउन सभी को चाहते हैं तो हमें पता है कि हमें LegoModelप्रत्येक समय में पास करना होगा ।

एसोसिएटेड प्रकारों के साथ यह बारीकियों में कोई भी प्रोटोकॉल है जो उन्हें विशेष उपयोग करता है। स्विफ्ट स्टैण्डर्ड लाइब्रेरी में इस तरह के विशेष रूप से प्रोटोकॉल हैं Collectionया Sequence

आपको Collectionप्रोटोकॉल को लागू करने वाली चीजों की एक सरणी बनाने या अनुक्रम प्रोटोकॉल को लागू करने वाली चीजों का एक सेट बनाने की अनुमति देने के लिए , मानक लाइब्रेरी संरचना प्रकार बनाने के लिए "टाइप-इरेज़र" नामक एक तकनीक को नियुक्त करती है AnyCollection<T>या AnySequence<T>। स्टैक ओवरफ्लो उत्तर में समझाने के लिए टाइप-इरेज़र तकनीक जटिल है, लेकिन अगर आप वेब पर खोजते हैं तो इसके बारे में बहुत सारे लेख हैं।

मैं YouTube पर Alex Gallagher से प्रोटोकॉल के साथ एसोसिएटेड टाइप्स (PATs) पर एक वीडियो की सिफारिश कर सकता हूं ।


40
"आपका समाधान बहुत ही सामान्य है " solution
Adolfo

6
यह इस समस्या के लिए मैंने देखी सबसे अच्छी व्याख्याओं में से एक है
काबे ४२

1
इतना अच्छा स्पष्टीकरण, इतना एकल जवाब।
अल्मास आदिलबेक

1
फ्रोबुलेट का मतलब क्या होता है?
मोफवा

1
यह उत्तर फ्रोबुलेट शब्द के उपयोग को बढ़ावा देने के लिए एक महान बहाना था।
स्कॉट्टीब्लाड्स

16

स्विफ्ट 5.1 से - Xcode 11

आप कुछ ऐसा हासिल करने के लिए एक अपारदर्शी परिणाम प्रकार का उपयोग कर सकते हैं ।

इसकी कल्पना करें:

protocol ProtocolA {
    associatedtype number
}

class ClassA: ProtocolA {
    typealias number = Double
}

तो निम्नलिखित त्रुटि उत्पन्न करता है:

var objectA: ProtocolA = ClassA() /* Protocol can only be used as a generic constraint because it has Self or associatedType requirements */

लेकिन टाइप करने से पहले कीवर्ड को जोड़कर अपारदर्शी बनाने से someसमस्या ठीक हो जाएगी और आमतौर पर केवल वही चीज़ चाहिए जो हम चाहते हैं:

var objectA: some ProtocolA = ClassA()

4

आपके कोड के डिज़ाइन में थोड़ा सा बदलाव इसे संभव बना सकता है। अपने प्रोटोकॉल पदानुक्रम के शीर्ष पर एक रिक्त, गैर-संबद्ध टाइप, प्रोटोकॉल जोड़ें। इस कदर...

public protocol RequestTypeBase: class{}

public protocol RequestType: RequestTypeBase {

    associatedtype Model
    var path: Model? { get set } //Make it type of Model

}
public class RequestEventuallyQueue {

    static let requestEventuallyQueue = RequestEventuallyQueue()
    var queue = [RequestTypeBase]() //This has to be 'var' not 'let'

}

एक अन्य उदाहरण, प्रोटोकॉल RequestType से निकाली गई कक्षाओं के साथ, एक कतार बनाना और उचित प्रकार प्रिंट करने के लिए एक फ़ंक्शन को कतार से गुजरना

public class RequestA<AType>: RequestType{
   public typealias Model = AType
   public var path: AType?
}
public class RequestB<BType>: RequestType{
   public typealias Model = BType
   public var path: BType?
}

var queue = [RequestTypeBase]()

let aRequest: RequestA = RequestA<String>()
aRequest.path = "xyz://pathA"

queue.append(aRequest)

let bRequest: RequestB = RequestB<String>()
bRequest.path = "xyz://pathB"

queue.append(bRequest)

let bURLRequest: RequestB = RequestB<URL>()
bURLRequest.path = URL(string: "xyz://bURLPath")

queue.append(bURLRequest)

func showFailed(requests: [RequestTypeBase]){

    for request in requests{
        if let request = request as? RequestA<String>{
            print(request.path!)
        }else if let request = request as? RequestB<String>{
            print(request.path!)
        }else if let request = request as? RequestB<URL>{
            print(request.path!)
        }

    }
}

showFailed(requests: queue)

4

स्विफ्ट 5.1

एक उदाहरण है कि आप एक संबंधित प्रकार और आधार प्रोटोकॉल को लागू करके जेनेरिक प्रोटोकॉल का उपयोग कैसे कर सकते हैं :

import Foundation

protocol SelectOptionDataModelProtocolBase: class{}

protocol SelectOptionDataModelProtocol: SelectOptionDataModelProtocolBase {
    associatedtype T
    
    var options: Array<T> { get }
    
    var selectedIndex: Int { get set }
    
}

class SelectOptionDataModel<A>: SelectOptionDataModelProtocol {
    typealias T = A
    
    var options: Array<T>
    
    var selectedIndex: Int
    
    init(selectedIndex _selectedIndex: Int, options _options: Array<T>) {
        self.options = _options
        self.selectedIndex = _selectedIndex
    }
    
}

और एक उदाहरण नियंत्रक देखें:

import UIKit

struct Car {
    var name: String?
    var speed: Int?
}

class SelectOptionViewController: UIViewController {
    
    // MARK: - IB Outlets
    
    // MARK: - Properties
    
    var dataModel1: SelectOptionDataModelProtocolBase?
    var dataModel2: SelectOptionDataModelProtocolBase?
    var dataModel3: SelectOptionDataModelProtocolBase?

    // MARK: - Initialisation
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    convenience init() {
        self.init(title: "Settings ViewController")
    }
    
    init(title _title: String) {
        super.init(nibName: nil, bundle: nil)
        
        self.title = _title
        
        self.dataModel1 = SelectOptionDataModel<String>(selectedIndex: 0, options: ["option 1", "option 2", "option 3"])
        self.dataModel2 = SelectOptionDataModel<Int>(selectedIndex: 0, options: [1, 2, 3])
        self.dataModel3 = SelectOptionDataModel<Car>(selectedIndex: 0, options: [Car(name: "BMW", speed: 90), Car(name: "Toyota", speed: 60), Car(name: "Subaru", speed: 120)])

    }
    
    // MARK: - IB Actions
    
    
    // MARK: - View Life Cycle

    
}

0

यह त्रुटि निम्न परिदृश्य में भी हो सकती है:

protocol MyProtocol {
    assosciatedtype SomeClass
    func myFunc() -> SomeClass
}

struct MyStuct {
    var myVar = MyProtocol
}

इस मामले में, आप सभी को समस्या को ठीक करने के लिए जेनरिक का उपयोग करना है:

protocol MyProtocol {
    assosciatedtype SomeClass
    func myFunc() -> SomeClass
}

struct MyStuct<T: MyProtocol> {
    var myVar = T
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.