delegates - तेजी से प्रतिनिधि?




swift delegation (8)

स्विफ्ट 4.0 में

कक्षा पर एक प्रतिनिधि बनाएं जिसे कुछ डेटा भेजने या अन्य वर्गों को कुछ कार्यक्षमता प्रदान करने की आवश्यकता है

पसंद

protocol GetGameStatus {
    var score: score { get }
    func getPlayerDetails()
}

इसके बाद उस वर्ग में जो इस प्रतिनिधि की पुष्टि करने जा रहा है

class SnakesAndLadders: GetGameStatus {
    func getPlayerDetails() {

 }
}

एक प्रतिनिधि बनने के बारे में कैसे जाता है, यानि NSUserNotificationCenterDelegate तेजी से?


ऊपर दिए गए समाधान थोड़ा युग्मित लगते थे और साथ ही साथ अन्य नियंत्रकों में एक ही प्रोटोकॉल का पुन: उपयोग करने से बचते हैं, यही कारण है कि मैं ऐसे समाधान के साथ आया हूं जो जेनेरिक टाइप-एरर का उपयोग करके अधिक मजबूत टाइप किया गया है।

@noreturn public func notImplemented(){
    fatalError("not implemented yet")
}


public protocol DataChangedProtocol: class{
    typealias DataType

    func onChange(t:DataType)
}

class AbstractDataChangedWrapper<DataType> : DataChangedProtocol{

    func onChange(t: DataType) {
        notImplemented()
    }
}


class AnyDataChangedWrapper<T: DataChangedProtocol> : AbstractDataChangedWrapper<T.DataType>{

    var base: T

    init(_ base: T ){
        self.base = base
    }

    override func onChange(t: T.DataType) {
        base.onChange(t)
    }
}


class AnyDataChangedProtocol<DataType> : DataChangedProtocol{

    var base: AbstractDataChangedWrapper<DataType>

    init<S: DataChangedProtocol where S.DataType == DataType>(_ s: S){
        self.base = AnyDataChangedWrapper(s)
    }

    func onChange(t: DataType) {
        base.onChange(t)
    }
}



class Source : DataChangedProtocol {
    func onChange(data: String) {
        print( "got new value \(data)" )
    }
}


class Target {
    var delegate: AnyDataChangedProtocol<String>?

    func reportChange(data:String ){
        delegate?.onChange(data)
    }
}


var source = Source()
var target = Target()

target.delegate = AnyDataChangedProtocol(source)
target.reportChange("newValue")    

आउटपुट : नया मूल्य नया वैल्यू मिला


प्रतिनिधि एक डिज़ाइन पैटर्न होते हैं जो एक ऑब्जेक्ट को किसी अन्य ऑब्जेक्ट पर संदेश भेजने की अनुमति देता है जब कोई विशिष्ट घटना होती है। एक ऑब्जेक्ट की कल्पना करें ए ए ऑब्जेक्ट बी को एक्शन करने के लिए कॉल करता है। एक बार कार्रवाई पूरी होने के बाद, वस्तु ए को पता होना चाहिए कि बी ने कार्य पूरा कर लिया है और आवश्यक कार्रवाई कर ली है, इसे प्रतिनिधियों की मदद से हासिल किया जा सकता है! स्विफ्ट 3 में चरण-दर-चरण प्रतिनिधियों को लागू करने वाला एक ट्यूटोरियल यहां दिया गया है

ट्यूटोरियल लिंक


प्रतिनिधियों ने हमेशा मुझे भ्रमित कर दिया जब तक मुझे एहसास हुआ कि एक प्रतिनिधि सिर्फ एक वर्ग है जो कुछ अन्य वर्ग के लिए काम करता है । ऐसा लगता है कि आप के लिए सभी गंदे काम करने के लिए कोई और है जो आप स्वयं नहीं करना चाहते हैं।

मैंने इसे चित्रित करने के लिए एक छोटी सी कहानी लिखी। यदि आप चाहें तो इसे खेल के मैदान में पढ़ें।

एक ज़माने में...

// MARK: Background to the story

// A protocol is like a list of rules that need to be followed.
protocol OlderSiblingDelegate: class {
    // The following command (ie, method) must be obeyed by any 
    // underling (ie, delegate) of the older sibling.
    func getYourNiceOlderSiblingAGlassOfWater()
}

// MARK: Characters in the story

class BossyBigBrother {

    // I can make whichever little sibling is around at 
    // the time be my delegate (ie, slave)
    weak var delegate: OlderSiblingDelegate?

    func tellSomebodyToGetMeSomeWater() {
        // The delegate is optional because even though 
        // I'm thirsty, there might not be anyone nearby 
        // that I can boss around.
        delegate?.getYourNiceOlderSiblingAGlassOfWater()
    }
}

// Poor little sisters have to follow (or at least acknowledge) 
// their older sibling's rules (ie, protocol)
class PoorLittleSister: OlderSiblingDelegate {

    func getYourNiceOlderSiblingAGlassOfWater() {
        // Little sis follows the letter of the law (ie, protocol),
        // but no one said exactly how she had to respond.
        print("Go get it yourself!")
    }
}

// MARK: The Story

// Big bro is laying on the couch watching basketball on TV.
let bigBro = BossyBigBrother()

// He has a little sister named Sally.
let sally = PoorLittleSister()

// Sally walks into the room. How convenient! Now big bro 
// has someone there to boss around.
bigBro.delegate = sally

// So he tells her to get him some water.
bigBro.tellSomebodyToGetMeSomeWater()

// Unfortunately no one lived happily ever after...

// The end.

समीक्षा में, प्रतिनिधि पैटर्न बनाने और उपयोग करने के लिए तीन महत्वपूर्ण भाग हैं।

  1. प्रोटोकॉल जो परिभाषित करता है कि कार्यकर्ता को क्या करना है
  2. बॉस क्लास जिसमें एक प्रतिनिधि चर है, जिसका उपयोग कार्यकर्ता वर्ग को यह बताने के लिए करता है कि क्या करना है
  3. कार्यकर्ता वर्ग जो प्रोटोकॉल को गोद लेता है और जो आवश्यक है करता है

असली जीवन

उपरोक्त हमारे बॉसी बिग ब्रदर की कहानी की तुलना में, प्रतिनिधियों को अक्सर निम्नलिखित व्यावहारिक अनुप्रयोगों के लिए उपयोग किया जाता है:

  1. संचार : एक वर्ग को किसी अन्य वर्ग को कुछ जानकारी भेजने की आवश्यकता है।
    • कोड उदाहरण 1: डेटा को एक व्यू कंट्रोलर से दूसरे में भेजना
    • कोड उदाहरण 2: किसी कस्टम कीबोर्ड से टेक्स्ट फ़ील्ड में टेक्स्ट इनपुट भेजना
  2. अनुकूलन : एक वर्ग किसी अन्य वर्ग को इसे अनुकूलित करने की अनुमति देना चाहता है।

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

मैं निम्नलिखित दो लेख पढ़ने की अत्यधिक अनुशंसा करता हूं। उन्होंने documentation तुलना में प्रतिनिधियों को भी बेहतर समझने में मेरी मदद की।

एक और नोट

प्रतिनिधि जो अन्य वर्गों का संदर्भ नहीं लेते हैं, उनके पास मजबूत संदर्भ चक्र से बचने के लिए weak कीवर्ड का उपयोग करना चाहिए। अधिक जानकारी के लिए यह उत्तर देखें।


मुझे @MakeAppPie के पोस्ट में कुछ सुधार हुए हैं

सबसे पहले जब आप प्रतिनिधि प्रोटोकॉल बना रहे हैं तो इसे कक्षा प्रोटोकॉल के अनुरूप होना चाहिए। उदाहरण में नीचे की तरह।

protocol ProtocolDelegate: class {
    func myMethod(controller:ViewController, text:String)
}

दूसरा, चक्र को बरकरार रखने से बचने के लिए आपका प्रतिनिधि कमजोर होना चाहिए।

class ViewController: UIViewController {
    weak var delegate: ProtocolDelegate?
}

अंत में, आप सुरक्षित हैं क्योंकि आपका प्रोटोकॉल एक वैकल्पिक मान है। इसका मतलब है कि इसका "शून्य" संदेश इस संपत्ति को नहीं भेजा जाएगा। यह respondToselector में respondToselector साथ सशर्त बयान के समान है लेकिन यहां आपके पास एक पंक्ति में सबकुछ है:

if ([self.delegate respondsToSelector:@selector(myMethod:text:)]) {
    [self.delegate myMethod:self text:@"you Text"];
}

आपके ऊपर एक ओबीजे-सी उदाहरण है और नीचे आपके पास यह दिखने का स्विफ्ट उदाहरण है।

delegate?.myMethod(self, text:"your Text")

यह ओबीजे-सी से अलग नहीं है। सबसे पहले, आपको अपनी कक्षा घोषणा में प्रोटोकॉल निर्दिष्ट करना होगा, जैसे निम्न:

class MyClass: NSUserNotificationCenterDelegate

कार्यान्वयन निम्नलिखित की तरह दिखेगा:

// NSUserNotificationCenterDelegate implementation
func userNotificationCenter(center: NSUserNotificationCenter, didDeliverNotification notification: NSUserNotification) {
    //implementation
}

func userNotificationCenter(center: NSUserNotificationCenter, didActivateNotification notification: NSUserNotification) {
    //implementation
}

func userNotificationCenter(center: NSUserNotificationCenter, shouldPresentNotification notification: NSUserNotification) -> Bool {
    //implementation
    return true
}

बेशक, आपको प्रतिनिधि को सेट करना होगा। उदाहरण के लिए:

NSUserNotificationCenter.defaultUserNotificationCenter().delegate = self;

कदम से बहुत आसान कदम (100% काम और परीक्षण)

चरण 1: प्रथम दृश्य नियंत्रक पर विधि बनाएं

 func updateProcessStatus(isCompleted : Bool){
    if isCompleted{
        self.labelStatus.text = "Process is completed"
    }else{
        self.labelStatus.text = "Process is in progress"
    }
}

चरण 2: दूसरी दृश्य नियंत्रक को धक्का देते समय प्रतिनिधि सेट करें

@IBAction func buttonAction(_ sender: Any) {

    let secondViewController = self.storyboard?.instantiateViewController(withIdentifier: "secondViewController") as! secondViewController
    secondViewController.delegate = self
    self.navigationController?.pushViewController(secondViewController, animated: true)
}

चरण 3: प्रतिनिधि को सेट करें

क्लास व्यू कंट्रोलर : UIViewController, ProcessStatusDelegate {

चरण 4: प्रोटोकॉल बनाएं

protocol ProcessStatusDelegate:NSObjectProtocol{
func updateProcessStatus(isCompleted : Bool)
}

चरण 5: एक चर ले लो

var delegate:ProcessStatusDelegate?

चरण 6: पिछली दृश्य नियंत्रक कॉल प्रतिनिधि विधि पर वापस जाने के दौरान पहले नियंत्रक को डेटा के साथ सूचित करें

@IBAction func buttonActionBack(_ sender: Any) {
    delegate?.updateProcessStatus(isCompleted: true)
    self.navigationController?.popViewController(animated: true)
}

@IBAction func buttonProgress(_ sender: Any) {
    delegate?.updateProcessStatus(isCompleted: false)
    self.navigationController?.popViewController(animated: true)

}

सरल उदाहरण:

protocol Work: class {
    func doSomething()
}

class Manager {
    weak var delegate: Work?
    func passAlong() {
        delegate?.doSomething()
    }
}

class Employee: Work {
    func doSomething() {
        print("Working on it")
    }
}

let manager = Manager()
let developer = Employee()
manager.delegate = developer
manager.passAlong() // PRINTS: Working on it