खोज…


परिचय

प्रोटोकॉल एक ऑब्जेक्ट का उपयोग करने के तरीके को निर्दिष्ट करने का एक तरीका है। वे गुणों और विधियों के एक सेट का वर्णन करते हैं जो एक वर्ग, संरचना, या एनम को प्रदान करना चाहिए, हालांकि प्रोटोकॉल कार्यान्वयन पर कोई प्रतिबंध नहीं लगाते हैं।

टिप्पणियों

एक स्विफ्ट प्रोटोकॉल आवश्यकताओं का एक संग्रह है जिसे अनुरूप प्रकारों को लागू करना चाहिए। प्रोटोकॉल का उपयोग उन जगहों पर किया जा सकता है जहां एक प्रकार की उम्मीद की जाती है, उदाहरण के लिए एरे और जेनेरिक आवश्यकताएं।

प्रोटोकॉल सदस्य हमेशा पूरे प्रोटोकॉल के रूप में एक ही एक्सेस क्वालिफायर साझा करते हैं, और इसे अलग से निर्दिष्ट नहीं किया जा सकता है। यद्यपि एक प्रोटोकॉल ऊपर दिए गए उदाहरणों के अनुसार, गेट्टर या सेटर आवश्यकताओं के साथ उपयोग को प्रतिबंधित कर सकता है।

प्रोटोकॉल के बारे में अधिक जानकारी के लिए, द स्विफ्ट प्रोग्रामिंग लैंग्वेज देखें

ऑब्जेक्टिव-सी प्रोटोकॉल स्विफ्ट प्रोटोकॉल के समान हैं।

प्रोटोकॉल भी जावा इंटरफेस के लिए तुलनीय हैं।

प्रोटोकॉल मूल बातें

प्रोटोकॉल के बारे में

एक प्रोटोकॉल एक स्विफ्ट ऑब्जेक्ट प्रकार (वर्ग, संरचना या एनम) प्रोटोकॉल के अनुरूप होने के लिए शुरुआती, गुण, कार्य, सदस्यता और संबंधित प्रकार निर्दिष्ट करता है। कुछ भाषाओं में बाद की वस्तुओं की आवश्यकता के विशिष्ट विचारों को 'इंटरफेस' के रूप में जाना जाता है।

एक घोषित और परिभाषित प्रोटोकॉल अपनी उल्लिखित आवश्यकताओं के हस्ताक्षर के साथ स्वयं का एक प्रकार है, और, स्विफ्ट फ़ंक्शंस पैरामीटर और रिटर्न के अपने हस्ताक्षर के आधार पर एक प्रकार है।

प्रोटोकॉल एक्सटेंशन के रूप में जानी जाने वाली सुविधा के माध्यम से स्विफ्ट प्रोटोकॉल विनिर्देश वैकल्पिक, स्पष्ट रूप से आवश्यक और / या डिफ़ॉल्ट कार्यान्वयन हो सकते हैं। एक स्विफ्ट ऑब्जेक्ट प्रकार (वर्ग, संरचना या एनम) एक प्रोटोकॉल के अनुरूप होने की इच्छा रखता है जो अपने सभी निर्दिष्ट आवश्यकताओं के लिए एक्सटेंशन्स के साथ बाहर हो गया है केवल पूर्ण अनुरूप होने के लिए अपनी इच्छा को पूरा करने की आवश्यकता है। प्रोटोकॉल एक्सटेंशन की डिफ़ॉल्ट कार्यान्वयन सुविधा किसी प्रोटोकॉल के अनुरूप सभी दायित्वों को पूरा करने के लिए पर्याप्त हो सकती है।

प्रोटोकॉल अन्य प्रोटोकॉल द्वारा विरासत में मिला जा सकता है। यह प्रोटोकॉल एक्सटेंशन के साथ संयोजन में, प्रोटोकॉल का मतलब है और स्विफ्ट की महत्वपूर्ण विशेषता के रूप में सोचा जाना चाहिए।

प्रोटोकॉल और विस्तार स्विफ्ट के व्यापक उद्देश्यों और कार्यक्रम के डिजाइन लचीलेपन और विकास प्रक्रियाओं के दृष्टिकोणों को साकार करने के लिए महत्वपूर्ण हैं। स्विफ्ट के प्रोटोकॉल और एक्सटेंशन क्षमता का प्राथमिक घोषित उद्देश्य प्रोग्राम आर्किटेक्चर और विकास में कंपोजिशन डिजाइन की सुविधा है। इसे प्रोटोकॉल ओरिएंटेड प्रोग्रामिंग कहा जाता है। जंग लगी पुरानी इमारते इसे OOP डिज़ाइन पर ध्यान केंद्रित करने से बेहतर मानती हैं।

प्रोटोकॉल उन इंटरफेस को परिभाषित करते हैं, जिन्हें किसी भी संरचना , वर्ग , या एनम द्वारा लागू किया जा सकता है:

protocol MyProtocol {
    init(value: Int)                      // required initializer
    func doSomething() -> Bool            // instance method
    var message: String { get }           // instance read-only property
    var value: Int { get set }            // read-write instance property
    subscript(index: Int) -> Int { get }  // instance subscript
    static func instructions() -> String  // static method
    static var max: Int { get }           // static read-only property
    static var total: Int { get set }     // read-write static property
}

प्रोटोकॉल में परिभाषित गुणों को या तो { get } या { get set } रूप में एनोटेट किया जाना चाहिए। { get } अर्थ है कि संपत्ति प्राप्य होनी चाहिए, और इसलिए इसे किसी भी प्रकार की संपत्ति के रूप में लागू किया जा सकता है। { get set } अर्थ है कि संपत्ति को व्यवस्थित होने के साथ-साथ प्राप्य भी होना चाहिए।

एक संरचना, वर्ग, या एनम एक प्रोटोकॉल के अनुरूप हो सकता है:

struct MyStruct : MyProtocol {
    // Implement the protocol's requirements here
}
class MyClass : MyProtocol {
    // Implement the protocol's requirements here
}
enum MyEnum : MyProtocol {
    case caseA, caseB, caseC
    // Implement the protocol's requirements here
}

एक प्रोटोकॉल किसी भी विस्तार के माध्यम से अपनी आवश्यकताओं के लिए एक डिफ़ॉल्ट कार्यान्वयन को परिभाषित कर सकता है:

extension MyProtocol {
    
    // default implementation of doSomething() -> Bool
    // conforming types will use this implementation if they don't define their own
    func doSomething() -> Bool {
        print("do something!")
        return true
    }
}

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

func doStuff(object: MyProtocol) {
    // All of MyProtocol's requirements are available on the object
    print(object.message)
    print(object.doSomething())
}

let items : [MyProtocol] = [MyStruct(), MyClass(), MyEnum.caseA]

आप एक अमूर्त प्रकार को भी परिभाषित कर सकते हैं जो कई प्रोटोकॉल के अनुरूप होता है:

3.0

स्विफ्ट 3 या बेहतर के साथ, यह एक एम्परसेंड ( & ) के साथ प्रोटोकॉल की सूची को अलग करके किया जाता है:

func doStuff(object: MyProtocol & AnotherProtocol) {
    // ...
}

let items : [MyProtocol & AnotherProtocol] = [MyStruct(), MyClass(), MyEnum.caseA]
3.0

पुराने संस्करणों में सिंटैक्स protocol<...> जहां प्रोटोकॉल कोण कोष्ठक के बीच अल्पविराम से अलग की गई सूची होती है <>

protocol AnotherProtocol {
    func doSomethingElse()
}

func doStuff(object: protocol<MyProtocol, AnotherProtocol>) {
    
    // All of MyProtocol & AnotherProtocol's requirements are available on the object
    print(object.message)
    object.doSomethingElse()
}

// MyStruct, MyClass & MyEnum must now conform to both MyProtocol & AnotherProtocol
let items : [protocol<MyProtocol, AnotherProtocol>] = [MyStruct(), MyClass(), MyEnum.caseA]

मौजूदा प्रकार एक प्रोटोकॉल के अनुरूप बढ़ाया जा सकता है:

extension String : MyProtocol {
    // Implement any requirements which String doesn't already satisfy
}

संबद्ध प्रकार की आवश्यकताएं

प्रोटोकॉल associatedtype कीवर्ड का उपयोग करके संबंधित प्रकार की आवश्यकताओं को परिभाषित कर सकते हैं:

protocol Container {
    associatedtype Element
    var count: Int { get }
    subscript(index: Int) -> Element { get set }
}

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

// These are NOT allowed, because Container has associated type requirements:
func displayValues(container: Container) { ... }
class MyClass { let container: Container }
// > error: protocol 'Container' can only be used as a generic constraint
// > because it has Self or associated type requirements

// These are allowed:
func displayValues<T: Container>(container: T) { ... }
class MyClass<T: Container> { let container: T }

एक प्रकार जो प्रोटोकॉल के अनुरूप होता है, एक associatedtype प्रकार को स्पष्ट रूप से संतुष्ट कर सकता है, एक दिए गए प्रकार को प्रदान करके जहां प्रोटोकॉल associatedtype के प्रकट होने की उम्मीद करता है:

struct ContainerOfOne<T>: Container {
    let count = 1          // satisfy the count requirement
    var value: T
    
    // satisfy the subscript associatedtype requirement implicitly,
    // by defining the subscript assignment/return type as T
    // therefore Swift will infer that T == Element
    subscript(index: Int) -> T {
        get {
            precondition(index == 0)
            return value
        }
        set {
            precondition(index == 0)
            value = newValue
        }
    }
}

let container = ContainerOfOne(value: "Hello")

(ध्यान दें कि इस उदाहरण में स्पष्टता जोड़ने के लिए, जेनेरिक प्लेसहोल्डर प्रकार को T नाम दिया गया है - एक अधिक उपयुक्त नाम Element होगा, जो प्रोटोकॉल के associatedtype Element को छाया देगा। कंपाइलर अभी भी अनुमान लगाएगा कि जेनेरिक प्लेसहोल्डर Element का उपयोग associatedtype Element को संतुष्ट करने के लिए किया जाता है। associatedtype Element आवश्यकता।)

एक associatedtype भी एक typealias के उपयोग के माध्यम से स्पष्ट रूप से संतुष्ट हो सकती है:

struct ContainerOfOne<T>: Container {

    typealias Element = T
    subscript(index: Int) -> Element { ... }

    // ...
}

वही एक्सटेंशन के लिए जाता है:

// Expose an 8-bit integer as a collection of boolean values (one for each bit).
extension UInt8: Container {

    // as noted above, this typealias can be inferred
    typealias Element = Bool

    var count: Int { return 8 }
    subscript(index: Int) -> Bool {
        get {
            precondition(0 <= index && index < 8)
            return self & 1 << UInt8(index) != 0
        }
        set {
            precondition(0 <= index && index < 8)
            if newValue {
                self |= 1 << UInt8(index)
            } else {
                self &= ~(1 << UInt8(index))
            }
        }
    }
}

यदि अनुरूप प्रकार पहले से ही आवश्यकता को पूरा करता है, तो किसी कार्यान्वयन की आवश्यकता नहीं है:

extension Array: Container {}  // Array satisfies all requirements, including Element

प्रतिनिधि पैटर्न

एक प्रतिनिधि एक सामान्य डिज़ाइन पैटर्न है जो कोको और कोकोआटाउट फ्रेमवर्क में उपयोग किया जाता है, जहां एक वर्ग दूसरे को कुछ कार्यक्षमता लागू करने के लिए जिम्मेदारी सौंपता है। यह चिंताओं के पृथक्करण के एक सिद्धांत का अनुसरण करता है, जहां एक अलग प्रतिनिधि उदाहरण विशिष्ट उपयोग के मामले में ढांचा वर्ग सामान्य कार्यक्षमता को लागू करता है।

प्रतिनिधि संचार में देखने का एक अन्य तरीका वस्तु संचार के संदर्भ में है। Objects अक्सर एक दूसरे से बात करने की आवश्यकता होती है और ऐसा करने के लिए किसी ऑब्जेक्ट को किसी अन्य ऑब्जेक्ट का प्रतिनिधि बनने के लिए एक protocol आवश्यकता होती है। एक बार यह सेटअप हो जाने के बाद, जब दिलचस्प चीजें होती हैं, तो दूसरी वस्तु अपने प्रतिनिधियों से बात करती है।

उदाहरण के लिए, डेटा की एक सूची प्रदर्शित करने के लिए उपयोगकर्ताप्रकार में एक दृश्य केवल इस बात के तर्क के लिए जिम्मेदार होना चाहिए कि डेटा कैसे प्रदर्शित किया जाता है, यह तय करने के लिए नहीं कि क्या डेटा प्रदर्शित किया जाना चाहिए।

आइए अधिक ठोस उदाहरण में गोता लगाएँ। यदि आपके पास दो कक्षाएं हैं, तो एक माता-पिता और एक बच्चा:

class Parent { }
class Child { }

और आप बच्चे से बदलाव के माता-पिता को सूचित करना चाहते हैं।

स्विफ्ट में, प्रतिनिधियों को एक protocol घोषणा का उपयोग करके कार्यान्वित किया जाता है और इसलिए हम एक protocol घोषित करेंगे जो delegate लागू करेंगे। यहां प्रतिनिधि parent वस्तु है।

protocol ChildDelegate: class {
    func childDidSomething()
}

बच्चे को प्रतिनिधि के संदर्भ को संग्रहीत करने के लिए एक संपत्ति घोषित करने की आवश्यकता है:

class Child {
    weak var delegate: ChildDelegate?
}

ध्यान दें कि चर delegate एक वैकल्पिक है और प्रोटोकॉल ChildDelegate केवल वर्ग प्रकार द्वारा कार्यान्वित होने के लिए चिह्नित है (इसके बिना delegate चर को किसी भी चक्र को बनाए रखने से बचने के लिए एक weak संदर्भ के रूप में घोषित नहीं किया जा सकता है। इसका मतलब है कि यदि delegate चर अब नहीं है। कहीं और संदर्भित, इसे जारी किया जाएगा)। ऐसा इसलिए होता है कि अभिभावक वर्ग प्रतिनिधि को तभी पंजीकृत करता है जब उसकी जरूरत होती है और वह उपलब्ध होता है।

इसके अलावा हमारे प्रतिनिधि को weak रूप में चिह्नित करने के लिए हमें अपने चाइल्डडेलेगेट प्रोटोकॉल को प्रोटोकॉल घोषणा में class कीवर्ड जोड़कर संदर्भ प्रकारों के लिए बाध्य करना चाहिए।

इस उदाहरण में, जब बच्चा कुछ करता है और उसे अपने माता-पिता को सूचित करने की आवश्यकता होती है, तो बच्चा फोन करेगा:

delegate?.childDidSomething()

यदि प्रतिनिधि को परिभाषित किया गया है, तो प्रतिनिधि को सूचित किया जाएगा कि बच्चे ने कुछ किया है।

अभिभावक वर्ग को ChildDelegate प्रोटोकॉल का विस्तार करने की आवश्यकता होगी ताकि वह अपने कार्यों का जवाब दे सके। यह सीधे मूल वर्ग पर किया जा सकता है:

class Parent: ChildDelegate {
    ...

    func childDidSomething() {
        print("Yay!")
    }
}

या एक्सटेंशन का उपयोग करना:

extension Parent: ChildDelegate {
    func childDidSomething() {
        print("Yay!")
    }
}

माता-पिता को भी बच्चे को यह बताना होगा कि यह बच्चे का प्रतिनिधि है:

// In the parent
let child = Child()
child.delegate = self

डिफ़ॉल्ट रूप से एक स्विफ्ट protocol वैकल्पिक फ़ंक्शन को लागू करने की अनुमति नहीं देता है। यह केवल तभी निर्दिष्ट किया जा सकता है जब आपका प्रोटोकॉल @objc विशेषता और optional संशोधक के साथ चिह्नित हो।

उदाहरण के लिए, UITableView iOS में एक टेबल व्यू के सामान्य व्यवहार को लागू करता है, लेकिन उपयोगकर्ता को UITableViewDelegate और UITableViewDataSource नामक दो डेलिगेट वर्गों को लागू करना चाहिए, जो लागू करते हैं कि विशिष्ट सेल कैसे दिखते हैं और व्यवहार करते हैं।

@objc public protocol UITableViewDelegate : NSObjectProtocol, UIScrollViewDelegate {
        
        // Display customization
        optional public func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath)
        optional public func tableView(tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int)
        optional public func tableView(tableView: UITableView, willDisplayFooterView view: UIView, forSection section: Int)
        optional public func tableView(tableView: UITableView, didEndDisplayingCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath)
        ...
}

आप इस प्रोटोकॉल को अपनी कक्षा की परिभाषा को बदलकर लागू कर सकते हैं, उदाहरण के लिए:

class MyViewController : UIViewController, UITableViewDelegate

प्रोटोकॉल परिभाषा ( UITableViewDelegate इस मामले में) में optional से चिह्नित किसी भी तरीके को लागू नहीं किया जाना चाहिए।

एक विशिष्ट अनुरूपता वर्ग के लिए प्रोटोकॉल विस्तार

आप किसी विशिष्ट वर्ग के लिए डिफ़ॉल्ट प्रोटोकॉल कार्यान्वयन लिख सकते हैं।

protocol MyProtocol {
    func doSomething()
}

extension MyProtocol where Self: UIViewController {
    func doSomething() {
        print("UIViewController default protocol implementation")
    }
}

class MyViewController: UIViewController, MyProtocol { }

let vc = MyViewController()
vc.doSomething() // Prints "UIViewController default protocol implementation"

RawRepresentable प्रोटोकॉल (एक्स्टेंसिबल Enum) का उपयोग करना

// RawRepresentable has an associatedType RawValue.
// For this struct, we will make the compiler infer the type
// by implementing the rawValue variable with a type of String
//
// Compiler infers RawValue = String without needing typealias
//
struct NotificationName: RawRepresentable {
    let rawValue: String

    static let dataFinished = NotificationNames(rawValue: "DataFinishedNotification")
}

मामलों को जोड़ने के लिए इस संरचना को कहीं और बढ़ाया जा सकता है

extension NotificationName {
    static let documentationLaunched = NotificationNames(rawValue: "DocumentationLaunchedNotification")
}

और एक इंटरफ़ेस किसी भी RawRepresentable प्रकार या विशेष रूप से आपके एनम संरचना के आसपास डिज़ाइन कर सकता है

func post(notification notification: NotificationName) -> Void {
    // use notification.rawValue
}

कॉल साइट पर, आप टाइप नोटिफिकेशननाम के लिए डॉट सिंटैक्स शॉर्टहैंड का उपयोग कर सकते हैं

post(notification: .dataFinished)

सामान्य RawRepresentable फ़ंक्शन का उपयोग करना

// RawRepresentable has an associate type, so the 
// method that wants to accept any type conforming to
// RawRepresentable needs to be generic
func observe<T: RawRepresentable>(object: T) -> Void {
    // object.rawValue
}

क्लास-ओनली प्रोटोकॉल

एक प्रोटोकॉल यह निर्दिष्ट कर सकता है कि केवल एक वर्ग अपनी विरासत सूची में class कीवर्ड का उपयोग करके इसे लागू कर सकता है। इस सूची में किसी भी अन्य वंशानुगत प्रोटोकॉल से पहले यह कीवर्ड प्रदर्शित होना चाहिए।

protocol ClassOnlyProtocol: class, SomeOtherProtocol {
    // Protocol requirements 
}

यदि एक गैर-वर्ग प्रकार ClassOnlyProtocol को लागू करने का प्रयास करता है, तो एक संकलक त्रुटि उत्पन्न होगी।

struct MyStruct: ClassOnlyProtocol { 
    // error: Non-class type 'MyStruct' cannot conform to class protocol 'ClassOnlyProtocol'  
}

अन्य प्रोटोकॉल ClassOnlyProtocol से विरासत में मिल सकते हैं, लेकिन उन्हें केवल उसी कक्षा की आवश्यकता होगी।

protocol MyProtocol: ClassOnlyProtocol {
    // ClassOnlyProtocol Requirements
    // MyProtocol Requirements
}

class MySecondClass: MyProtocol {
    // ClassOnlyProtocol Requirements
    // MyProtocol Requirements
}

कक्षा-केवल प्रोटोकॉल के संदर्भ शब्दार्थ

एक वर्ग-केवल प्रोटोकॉल का उपयोग करना संदर्भ के अर्थ विज्ञान के लिए अनुमति देता है जब अनुरूप प्रकार अज्ञात होता है।

protocol Foo : class {
    var bar : String { get set }
}

func takesAFoo(foo:Foo) {

    // this assignment requires reference semantics,
    // as foo is a let constant in this scope.
    foo.bar = "new value"
}

इस उदाहरण में, चूंकि Foo एक वर्ग-केवल प्रोटोकॉल है, इसलिए bar को असाइनमेंट मान्य है क्योंकि कंपाइलर जानता है कि foo एक वर्ग प्रकार है, और इसलिए इसमें संदर्भ शब्दार्थ है।

यदि Foo एक वर्ग-केवल प्रोटोकॉल नहीं था, तो एक संकलक त्रुटि उत्पन्न होगी - जैसा कि अनुरूप प्रकार एक मूल्य प्रकार हो सकता है, जिसे परिवर्तनशील होने के लिए एक var एनोटेशन की आवश्यकता होगी।

protocol Foo {
    var bar : String { get set }
}

func takesAFoo(foo:Foo) {
    foo.bar = "new value" // error: Cannot assign to property: 'foo' is a 'let' constant
}

func takesAFoo(foo:Foo) {
    var foo = foo // mutable copy of foo
    foo.bar = "new value" // no error – satisfies both reference and value semantics
}

प्रोटोकॉल प्रकार के कमजोर चर

weak संशोधक को प्रोटोकॉल प्रकार के एक चर पर लागू करते समय, उस प्रोटोकॉल प्रकार को केवल कक्षा में होना चाहिए, क्योंकि weak को केवल संदर्भ प्रकारों पर लागू किया जा सकता है।

weak var weakReference : ClassOnlyProtocol?

हैशेबल प्रोटोकॉल को लागू करना

में इस्तेमाल किया प्रकार Sets और Dictionaries(key) के अनुरूप होना चाहिए Hashable प्रोटोकॉल है जो से विरासत में मिली Equatable प्रोटोकॉल।

कस्टम प्रकार Hashable प्रोटोकॉल के अनुरूप होना चाहिए

  • एक गणना की गई संपत्ति hashValue
  • समानता ऑपरेटरों में से एक को परिभाषित करें == या !=

उदाहरण के लिए एक कस्टम struct लिए Hashable प्रोटोकॉल को लागू करता है:

struct Cell {
    var row: Int
    var col: Int
    
    init(_ row: Int, _ col: Int) {
        self.row = row
        self.col = col
    }
}

extension Cell: Hashable {
    
    // Satisfy Hashable requirement
    var hashValue: Int {
        get {
            return row.hashValue^col.hashValue
        }
    }

    // Satisfy Equatable requirement
    static func ==(lhs: Cell, rhs: Cell) -> Bool {
        return lhs.col == rhs.col && lhs.row == rhs.row
    }
    
}

// Now we can make Cell as key of dictonary
var dict = [Cell : String]()

dict[Cell(0, 0)] = "0, 0"
dict[Cell(1, 0)] = "1, 0"
dict[Cell(0, 1)] = "0, 1"

// Also we can create Set of Cells
var set = Set<Cell>()

set.insert(Cell(0, 0))
set.insert(Cell(1, 0))

नोट : यह आवश्यक नहीं है कि कस्टम प्रकार के विभिन्न मूल्यों में अलग-अलग हैश मूल्य हैं, टकराव स्वीकार्य हैं। यदि हैश मान समान हैं, तो वास्तविक समानता निर्धारित करने के लिए समानता ऑपरेटर का उपयोग किया जाएगा।



Modified text is an extract of the original Stack Overflow Documentation
के तहत लाइसेंस प्राप्त है CC BY-SA 3.0
से संबद्ध नहीं है Stack Overflow