मुझे पता है कि प्रतिनिधि कैसे काम करते हैं, और मुझे पता है कि मैं उनका उपयोग कैसे कर सकता हूं।
लेकिन मैं उन्हें कैसे बनाऊं?
मुझे पता है कि प्रतिनिधि कैसे काम करते हैं, और मुझे पता है कि मैं उनका उपयोग कैसे कर सकता हूं।
लेकिन मैं उन्हें कैसे बनाऊं?
जवाबों:
एक उद्देश्य-सी प्रतिनिधि एक ऐसी वस्तु है जिसे delegate
किसी अन्य वस्तु को संपत्ति के लिए सौंपा गया है । एक बनाने के लिए, आप एक वर्ग को परिभाषित करते हैं जो आपके द्वारा रुचि रखने वाले प्रतिनिधि विधियों को लागू करता है और प्रतिनिधि वर्ग प्रोटोकॉल को लागू करने के रूप में उस वर्ग को चिह्नित करता है।
उदाहरण के लिए, मान लीजिए कि आपके पास ए UIWebView
। यदि आप इसके प्रतिनिधि को लागू करना चाहते हैंwebViewDidStartLoad:
तरीके , तो आप इस तरह एक वर्ग बना सकते हैं:
@interface MyClass<UIWebViewDelegate>
// ...
@end
@implementation MyClass
- (void)webViewDidStartLoad:(UIWebView *)webView {
// ...
}
@end
तब आप MyClass का एक उदाहरण बना सकते हैं और इसे वेब दृश्य के प्रतिनिधि के रूप में असाइन कर सकते हैं:
MyClass *instanceOfMyClass = [[MyClass alloc] init];
myWebView.delegate = instanceOfMyClass;
पर UIWebView
पक्ष, यह शायद इस के समान कोड अगर के लिए प्रतिनिधि प्रतिक्रिया को देखने के लिए है webViewDidStartLoad:
संदेश का उपयोग करrespondsToSelector:
और उचित होने पर भेज सकते हैं।
if([self.delegate respondsToSelector:@selector(webViewDidStartLoad:)]) {
[self.delegate webViewDidStartLoad:self];
}
स्वयं प्रतिनिधि संपत्ति आमतौर पर घोषित की जाती है weak
assign
लूप से बचने के लिए ( एआरसी में) या (पूर्व-एआरसी) , क्योंकि किसी वस्तु का प्रतिनिधि अक्सर उस वस्तु का एक मजबूत संदर्भ रखता है। (उदाहरण के लिए, एक दृश्य नियंत्रक अक्सर एक दृश्य का प्रतिनिधि होता है जिसमें यह शामिल होता है।)
अपने स्वयं के प्रतिनिधियों को परिभाषित करने के लिए, आपको प्रोटोकॉल पर Apple डॉक्स में चर्चा के अनुसार, कहीं न कहीं उनके तरीकों की घोषणा करनी होगी । आप आमतौर पर एक औपचारिक प्रोटोकॉल घोषित करते हैं। घोषणा, UIWebView.h से paraphrased, इस तरह दिखेगा:
@protocol UIWebViewDelegate <NSObject>
@optional
- (void)webViewDidStartLoad:(UIWebView *)webView;
// ... other methods here
@end
यह एक इंटरफ़ेस या सार बेस क्लास के अनुरूप है, क्योंकि यह UIWebViewDelegate
इस मामले में आपके प्रतिनिधि के लिए एक विशेष प्रकार बनाता है । प्रतिनिधि कार्यान्वयनकर्ताओं को यह प्रोटोकॉल अपनाना होगा:
@interface MyClass <UIWebViewDelegate>
// ...
@end
और फिर प्रोटोकॉल में विधियों को लागू करें। के रूप में प्रोटोकॉल में घोषित तरीकों के लिए@optional
(अधिकांश प्रतिनिधि विधियों की तरह), इसके लिए आपको -respondsToSelector:
किसी विशेष विधि को कॉल करने से पहले जांच करनी चाहिए।
प्रतिनिधि विधियों को आमतौर पर प्रतिनिधि वर्ग के नाम से शुरू किया जाता है, और प्रतिनिधि पैरामीटर को पहले पैरामीटर के रूप में लिया जाता है। वे अक्सर एक वसीयत-, का - या - का भी उपयोग करते हैं। इसलिए, webViewDidStartLoad:
(पहले पैरामीटर वेब दृश्य है) के बजायloadStarted
उदाहरण के लिए (कोई पैरामीटर नहीं) लेने के ।
यह जाँचने के बजाय कि क्या कोई प्रतिनिधि चयनकर्ता के लिए हर बार जब हम उसे संदेश देना चाहते हैं, तो आप उस सूचना को कैश कर सकते हैं जब प्रतिनिधि सेट होते हैं। ऐसा करने के लिए एक बहुत ही साफ तरीका एक बिटफील्ड का उपयोग करना है, इस प्रकार है:
@protocol SomethingDelegate <NSObject>
@optional
- (void)something:(id)something didFinishLoadingItem:(id)item;
- (void)something:(id)something didFailWithError:(NSError *)error;
@end
@interface Something : NSObject
@property (nonatomic, weak) id <SomethingDelegate> delegate;
@end
@implementation Something {
struct {
unsigned int didFinishLoadingItem:1;
unsigned int didFailWithError:1;
} delegateRespondsTo;
}
@synthesize delegate;
- (void)setDelegate:(id <SomethingDelegate>)aDelegate {
if (delegate != aDelegate) {
delegate = aDelegate;
delegateRespondsTo.didFinishLoadingItem = [delegate respondsToSelector:@selector(something:didFinishLoadingItem:)];
delegateRespondsTo.didFailWithError = [delegate respondsToSelector:@selector(something:didFailWithError:)];
}
}
@end
फिर, शरीर में, हम जाँच सकते हैं कि हमारा प्रतिनिधि हमारे संदेश delegateRespondsTo
को भेजने के बजाय, हमारी संरचना तक पहुँच बनाकर संदेशों को संभालता है-respondsToSelector:
को बार-बार ।
इससे पहले कि प्रोटोकॉल से ही अस्तित्व में है, यह एक का उपयोग एक आम बात थी श्रेणी पर NSObject
तरीकों एक प्रतिनिधि को लागू कर सकता है की घोषणा करने के। उदाहरण के लिए, CALayer
अभी भी यह करता है:
@interface NSObject(CALayerDelegate)
- (void)displayLayer:(CALayer *)layer;
// ... other methods here
@end
यह संकलक को बताता है कि कोई भी वस्तु लागू हो सकती है displayLayer:
।
फिर आप -respondsToSelector:
इस पद्धति को कॉल करने के लिए ऊपर बताए गए समान दृष्टिकोण का उपयोग करेंगे। प्रतिनिधि इस पद्धति को लागू करते delegate
हैं और संपत्ति सौंपते हैं, और यह वह है (कोई प्रोटोकॉल के अनुरूप नहीं है)। यह विधि Apple के पुस्तकालयों में आम है, लेकिन नए कोड को ऊपर और अधिक आधुनिक प्रोटोकॉल दृष्टिकोण का उपयोग करना चाहिए, क्योंकि यह दृष्टिकोण प्रदूषित करता है NSObject
(जो स्वत: पूर्ण को कम उपयोगी बनाता है) और संकलक के लिए आपको टाइपो और समान त्रुटियों के बारे में चेतावनी देना कठिन बनाता है।
unsigned int
टाइप BOOL
ऑफ रिटर्न की जरूरत delegate respondsToSelector
है BOOL
।
स्वीकृत उत्तर बहुत अच्छा है, लेकिन यदि आप 1 मिनट के उत्तर की तलाश कर रहे हैं, तो यह कोशिश करें:
MyClass.h फ़ाइल को इस तरह दिखना चाहिए (टिप्पणियों के साथ प्रतिनिधि लाइनें जोड़ें!)
#import <BlaClass/BlaClass.h>
@class MyClass; //define class, so protocol can see MyClass
@protocol MyClassDelegate <NSObject> //define delegate protocol
- (void) myClassDelegateMethod: (MyClass *) sender; //define delegate method to be implemented within another class
@end //end protocol
@interface MyClass : NSObject {
}
@property (nonatomic, weak) id <MyClassDelegate> delegate; //define MyClassDelegate as delegate
@end
MyClass.m फ़ाइल को इस तरह दिखना चाहिए
#import "MyClass.h"
@implementation MyClass
@synthesize delegate; //synthesise MyClassDelegate delegate
- (void) myMethodToDoStuff {
[self.delegate myClassDelegateMethod:self]; //this will call the method implemented in your other class
}
@end
किसी अन्य कक्षा में अपने प्रतिनिधि का उपयोग करने के लिए (UIViewController को इस मामले में MyVC कहा जाता है) MyVC.h:
#import "MyClass.h"
@interface MyVC:UIViewController <MyClassDelegate> { //make it a delegate for MyClassDelegate
}
MyVC.m:
myClass.delegate = self; //set its delegate to self somewhere
प्रतिनिधि पद्धति लागू करें
- (void) myClassDelegateMethod: (MyClass *) sender {
NSLog(@"Delegates are great!");
}
myClass
MyVC.m के अंदर तत्काल कहां है ?
प्रतिनिधि समर्थन बनाने के लिए औपचारिक प्रोटोकॉल विधि का उपयोग करते समय, मैंने पाया है कि आप कुछ जोड़कर उचित प्रकार की जाँच (यद्यपि, क्रम, समय संकलित नहीं) सुनिश्चित कर सकते हैं:
if (![delegate conformsToProtocol:@protocol(MyDelegate)]) {
[NSException raise:@"MyDelegate Exception"
format:@"Parameter does not conform to MyDelegate protocol at line %d", (int)__LINE__];
}
अपने प्रतिनिधि एक्सेसर (सेटडेलगेट) कोड में। यह गलतियों को कम करने में मदद करता है।
कृप्या! आईओएस में डेलिगेट्स कैसे काम करता है यह समझने के लिए स्टेप ट्यूटोरियल द्वारा सरल चरण के नीचे की जाँच करें।
मैंने दो ViewControllers बनाए हैं (एक से दूसरे में डेटा भेजने के लिए)
हो सकता है कि आप जो कुछ याद कर रहे हैं उसकी तर्ज पर यह अधिक हो:
यदि आप सी + + जैसे दृष्टिकोण से आ रहे हैं, तो प्रतिनिधियों को थोड़ा सा उपयोग हो रहा है - लेकिन मूल रूप से 'वे सिर्फ काम करते हैं'।
जिस तरह से यह काम करता है वह यह है कि आपने NSWindow के प्रतिनिधि के रूप में कुछ ऑब्जेक्ट सेट किया है, लेकिन आपकी ऑब्जेक्ट में कई संभावित प्रतिनिधि विधियों में से एक या कुछ के लिए कार्यान्वयन (विधियाँ) हैं। तो कुछ होता है, और NSWindow
अपनी वस्तु को कॉल करना चाहता है - यह सिर्फ ऑब्जेक्टिव-सी का उपयोग करता हैrespondsToSelector
विधि निर्धारित करने के लिए कि क्या आपका ऑब्जेक्ट उस विधि को कॉल करता है, और फिर उसे कॉल करता है। इस तरह से उद्देश्य-सी काम करता है - मांग पर तरीकों को देखा जाता है।
यह पूरी तरह से तुच्छ है अपनी वस्तुओं के साथ ऐसा करने के लिए, कुछ खास नहीं चल रहा है, आप उदाहरण के लिए NSArray
27 ऑब्जेक्ट्स, सभी विभिन्न प्रकार की ऑब्जेक्ट्स हो सकते हैं, उनमें से केवल 18 में से कुछ में विधि -(void)setToBue;
9 अन्य नहीं है। इसलिए setToBlue
सभी 18 को कॉल करने की आवश्यकता है, जो कुछ इस तरह से किया जाता है:
for (id anObject in myArray)
{
if ([anObject respondsToSelector:@selector(@"setToBlue")])
[anObject setToBlue];
}
प्रतिनिधियों के बारे में दूसरी बात यह है कि उन्हें बनाए नहीं रखा जाता है, इसलिए आपको हमेशा प्रतिनिधि को nil
अपनी MyClass dealloc
पद्धति में सेट करना होगा ।
Apple द्वारा अनुशंसित एक अच्छे अभ्यास के रूप में, यह प्रोटोकॉल के अनुरूप होने के लिए प्रतिनिधि (जो कि एक प्रोटोकॉल है, परिभाषा के अनुसार) के लिए अच्छा NSObject
है।
@protocol MyDelegate <NSObject>
...
@end
अपने प्रतिनिधि के भीतर वैकल्पिक विधियाँ बनाने के लिए (अर्थात जिन विधियों को आवश्यक रूप से कार्यान्वित करने की आवश्यकता नहीं है), आप @optional
इस तरह एनोटेशन का उपयोग कर सकते हैं :
@protocol MyDelegate <NSObject>
...
...
// Declaration for Methods that 'must' be implemented'
...
...
@optional
...
// Declaration for Methods that 'need not necessarily' be implemented by the class conforming to your delegate
...
@end
इसलिए जब आप वैकल्पिक के रूप में निर्दिष्ट विधियों का उपयोग कर रहे हैं, तो आपको (आपकी कक्षा में) यह देखने की ज़रूरत है respondsToSelector
कि क्या दृश्य (जो आपके प्रतिनिधि के अनुरूप है) ने वास्तव में आपके वैकल्पिक तरीके को लागू किया है या नहीं।
मुझे लगता है कि ये सभी उत्तर प्रतिनिधियों को समझने के बाद बहुत मायने रखते हैं। व्यक्तिगत रूप से मैं C / C ++ की भूमि से आया था और उससे पहले प्रक्रियात्मक भाषाएं जैसे कि फोरट्रान इत्यादि, यहाँ मेरा 2 मिनट C ++ प्रतिमान में इसी तरह के एनालॉग को खोजने के लिए है।
यदि मैं प्रतिनिधियों को C ++ / Java प्रोग्रामर को समझाऊं तो मैं कहूंगा
डेलीगेट्स क्या हैं? ये एक अन्य वर्ग के भीतर कक्षाओं के लिए स्थिर संकेत हैं। एक बार जब आप एक पॉइंटर असाइन करते हैं, तो आप उस क्लास में फ़ंक्शन / विधियों को कॉल कर सकते हैं। इसलिए आपकी कक्षा के कुछ कार्य "प्रत्यायोजित" हैं (C ++ दुनिया में - एक वर्ग ऑब्जेक्ट पॉइंटर द्वारा पॉइंटर को) दूसरे वर्ग को।
प्रोटोकॉल क्या हैं? वैचारिक रूप से यह उसी उद्देश्य के रूप में कार्य करता है जैसा कि आप जिस कक्षा के प्रतिनिधि फाइल के रूप में असाइन कर रहे हैं, उसकी हेडर फाइल। एक प्रोटोकॉल यह परिभाषित करने का एक स्पष्ट तरीका है कि कक्षा में कौन से तरीकों को लागू करने की आवश्यकता है, जो एक वर्ग के भीतर एक प्रतिनिधि के रूप में निर्धारित किया गया था।
मैं C ++ में कुछ ऐसा कैसे कर सकता हूं? यदि आपने C ++ में ऐसा करने की कोशिश की, तो आप कक्षा की परिभाषा में कक्षाओं (ऑब्जेक्ट्स) को पॉइंटर्स को परिभाषित करके और फिर उन्हें अन्य वर्गों तक वायरिंग करेंगे जो आपके बेस क्लास के प्रतिनिधियों को अतिरिक्त कार्य प्रदान करेंगे। लेकिन इस वायरिंग को कोड के भीतर अंकित करना होगा और यह अनाड़ी और त्रुटि प्रवण होगा। उद्देश्य सी सिर्फ यह मानता है कि प्रोग्रामर इस डिकिपलाइन को बनाए रखने के लिए सबसे अच्छे नहीं हैं और एक स्वच्छ कार्यान्वयन को लागू करने के लिए संकलक प्रतिबंध प्रदान करता है।
एक प्रतिनिधि केवल एक वर्ग है जो किसी अन्य वर्ग के लिए कुछ काम करता है। कुछ हद तक मूर्खतापूर्ण (लेकिन उम्मीद है कि ज्ञानवर्धक) प्लेग्राउंड उदाहरण के लिए निम्नलिखित कोड पढ़ें जो दिखाता है कि यह स्विफ्ट में कैसे किया जाता है।
// A protocol is just a list of methods (and/or properties) that must
// be used by any class that adopts the protocol.
protocol OlderSiblingDelegate: class {
// This protocol only defines one required method
func getYourNiceOlderSiblingAGlassOfWater() -> String
}
class BossyBigBrother {
// The delegate is the BossyBigBrother's slave. This position can
// be assigned later to whoever is available (and conforms to the
// protocol).
weak var delegate: OlderSiblingDelegate?
func tellSomebodyToGetMeSomeWater() -> String? {
// The delegate is optional because there might not be anyone
// nearby to boss around.
return delegate?.getYourNiceOlderSiblingAGlassOfWater()
}
}
// PoorLittleSister conforms to the OlderSiblingDelegate protocol
class PoorLittleSister: OlderSiblingDelegate {
// This method is repquired by the protocol, but the protocol said
// nothing about how it needs to be implemented.
func getYourNiceOlderSiblingAGlassOfWater() -> String {
return "Go get it yourself!"
}
}
// initialize the classes
let bigBro = BossyBigBrother()
let lilSis = PoorLittleSister()
// Set the delegate
// bigBro could boss around anyone who conforms to the
// OlderSiblingDelegate protocol, but since lilSis is here,
// she is the unlucky choice.
bigBro.delegate = lilSis
// Because the delegate is set, there is a class to do bigBro's work for him.
// bigBro tells lilSis to get him some water.
if let replyFromLilSis = bigBro.tellSomebodyToGetMeSomeWater() {
print(replyFromLilSis) // "Go get it yourself!"
}
वास्तविक अभ्यास में, प्रतिनिधियों को अक्सर निम्नलिखित स्थितियों में उपयोग किया जाता है
वर्गों को पहले से एक दूसरे के बारे में कुछ भी जानने की जरूरत नहीं है सिवाय इसके कि प्रतिनिधि वर्ग आवश्यक प्रोटोकॉल के अनुरूप हो।
मैं निम्नलिखित दो लेखों को पढ़ने की अत्यधिक सलाह देता हूं। उन्होंने मुझे यह समझने में मदद की कि डॉक्युमेंटेशन की तुलना में प्रतिनिधियों को और भी बेहतर बनाया गया है।
ठीक है, यह वास्तव में सवाल का जवाब नहीं है, लेकिन अगर आप देख रहे हैं कि कैसे अपने खुद के प्रतिनिधि बनाने के लिए हो सकता है कि कुछ बहुत सरल आप के लिए एक बेहतर जवाब हो सकता है।
मैं शायद ही अपने प्रतिनिधियों को लागू करता हूं क्योंकि मुझे शायद ही कभी आवश्यकता होती है। मेरे पास एक प्रतिनिधि के लिए केवल एक प्रतिनिधि हो सकता है। इसलिए यदि आप चाहते हैं कि आपका प्रतिनिधि एक तरह से संचार / पासिंग डेटा की तुलना में आप सूचनाओं के साथ ज्यादा बेहतर हो।
NSNotification ऑब्जेक्ट को एक से अधिक प्राप्तकर्ताओं को पास कर सकता है और इसका उपयोग करना बहुत आसान है। यह इस तरह काम करता है:
MyClass.m फ़ाइल को इस तरह दिखना चाहिए
#import "MyClass.h"
@implementation MyClass
- (void) myMethodToDoStuff {
//this will post a notification with myClassData (NSArray in this case) in its userInfo dict and self as an object
[[NSNotificationCenter defaultCenter] postNotificationName:@"myClassUpdatedData"
object:self
userInfo:[NSDictionary dictionaryWithObject:selectedLocation[@"myClassData"] forKey:@"myClassData"]];
}
@end
अन्य कक्षाओं में अपनी अधिसूचना का उपयोग करने के लिए: पर्यवेक्षक के रूप में कक्षा जोड़ें:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(otherClassUpdatedItsData:) name:@"myClassUpdatedData" object:nil];
चयनकर्ता को लागू करें:
- (void) otherClassUpdatedItsData:(NSNotification *)note {
NSLog(@"*** Other class updated its data ***");
MyClass *otherClass = [note object]; //the object itself, you can call back any selector if you want
NSArray *otherClassData = [note userInfo][@"myClassData"]; //get myClass data object and do whatever you want with it
}
अगर एक पर्यवेक्षक के रूप में अपनी कक्षा को हटाने के लिए मत भूलना
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
मान लीजिए कि आपके पास एक वर्ग है जिसे आपने विकसित किया है और एक प्रतिनिधि संपत्ति की घोषणा करना चाहते हैं जब कोई घटना घटती है तो उसे सूचित करने में सक्षम हो सकता है:
@class myClass;
@protocol myClassDelegate <NSObject>
-(void)myClass:(MyClass*)myObject requiredEventHandlerWithParameter:(ParamType*)param;
@optional
-(void)myClass:(MyClass*)myObject optionalEventHandlerWithParameter:(ParamType*)param;
@end
@interface MyClass : NSObject
@property(nonatomic,weak)id< MyClassDelegate> delegate;
@end
इसलिए आप MyClass
हेडर फ़ाइल (या एक अलग हेडर फ़ाइल) में एक प्रोटोकॉल की घोषणा करते हैं, और आवश्यक / वैकल्पिक घटना संचालकों की घोषणा करते हैं जिसे आपके प्रतिनिधि को लागू करना चाहिए / करना चाहिए, फिर MyClass
प्रकार की संपत्ति घोषित करें ( id< MyClassDelegate>
) जिसका अर्थ है कि कोई भी उद्देश्य सी वर्ग जो इसके अनुरूप है प्रोटोकॉल MyClassDelegate
, आप देखेंगे कि प्रतिनिधि संपत्ति को कमजोर घोषित किया गया है, चक्र को बनाए रखने के लिए यह बहुत महत्वपूर्ण है (सबसे अधिक बार प्रतिनिधि को बनाए रखता है)MyClass
उदाहरण को इसलिए यदि आपने प्रतिनिधि को बनाए रखने की घोषणा की है, तो दोनों एक दूसरे को बनाए रखेंगे और न ही उनमें से कभी भी जारी किया जाएगा)।
आप यह भी देखेंगे कि प्रोटोकॉल के तरीके MyClass
प्रतिनिधि के रूप में उदाहरण को पैरामीटर के रूप में पास करते हैं , यह सबसे अच्छा अभ्यास है यदि प्रतिनिधि MyClass
उदाहरण के लिए कुछ तरीकों को कॉल करना चाहता है और यह भी मदद करता है जब प्रतिनिधि खुद MyClassDelegate
को कई MyClass
उदाहरणों के रूप में घोषित करता है , जैसे कि जब आपके पास कई हैं UITableView's
अपने आप में उदाहरण ViewController
और खुद को UITableViewDelegate
उन सभी के रूप में घोषित करता है ।
और अपने अंदर MyClass
आप इस तरह से घोषित घटनाओं के साथ प्रतिनिधि को सूचित करें:
if([_delegate respondsToSelector:@selector(myClass: requiredEventHandlerWithParameter:)])
{
[_delegate myClass:self requiredEventHandlerWithParameter:(ParamType*)param];
}
आप पहले जांच लें कि क्या आपका प्रतिनिधि प्रोटोकॉल पद्धति पर प्रतिक्रिया देता है जिसे आप उस स्थिति में कॉल करने वाले हैं जब प्रतिनिधि इसे लागू नहीं करता है और ऐप तब क्रैश हो जाएगा (भले ही प्रोटोकॉल विधि की आवश्यकता हो)।
प्रतिनिधियों को बनाने के लिए यहां एक सरल विधि है
.H फ़ाइल में प्रोटोकॉल बनाएँ। सुनिश्चित करें कि UIViewController के नाम के बाद @class का उपयोग कर प्रोटोकॉल से पहले परिभाषित किया गया है< As the protocol I am going to use is UIViewController class>.
चरण: 1: "YourViewController" नामक एक नया वर्ग प्रोटोकॉल बनाएं जो UIViewController वर्ग का उपवर्ग होगा और इस वर्ग को दूसरे ViewController के लिए असाइन करेगा।
चरण: 2: "YourViewController" फ़ाइल पर जाएं और इसे नीचे के रूप में संशोधित करें:
#import <UIKit/UIkit.h>
@class YourViewController;
@protocol YourViewController Delegate <NSObject>
@optional
-(void)defineDelegateMethodName: (YourViewController *) controller;
@required
-(BOOL)delegateMethodReturningBool: (YourViewController *) controller;
@end
@interface YourViewController : UIViewController
//Since the property for the protocol could be of any class, then it will be marked as a type of id.
@property (nonatomic, weak) id< YourViewController Delegate> delegate;
@end
प्रोटोकॉल व्यवहार में परिभाषित तरीकों को प्रोटोकॉल की परिभाषा के भाग के रूप में @optional और @required के साथ नियंत्रित किया जा सकता है।
चरण: 3: प्रतिनिधि का कार्यान्वयन
#import "delegate.h"
@interface YourDelegateUser ()
<YourViewControllerDelegate>
@end
@implementation YourDelegateUser
- (void) variousFoo {
YourViewController *controller = [[YourViewController alloc] init];
controller.delegate = self;
}
-(void)defineDelegateMethodName: (YourViewController *) controller {
// handle the delegate being called here
}
-(BOOL)delegateMethodReturningBool: (YourViewController *) controller {
// handle the delegate being called here
return YES;
}
@end
// परीक्षण करें कि क्या विधि को कॉल करने से पहले परिभाषित किया गया है
- (void) someMethodToCallDelegate {
if ([[self delegate] respondsToSelector:@selector(defineDelegateMethodName:)]) {
[self.delegate delegateMethodName:self];
}
}
अपना स्वयं का प्रतिनिधि बनाने के लिए, पहले आपको एक प्रोटोकॉल बनाने और कार्यान्वयन के बिना आवश्यक तरीकों की घोषणा करने की आवश्यकता है। और फिर इस प्रोटोकॉल को अपने हेडर वर्ग में लागू करें जहां आप प्रतिनिधि या प्रतिनिधि विधियों को लागू करना चाहते हैं।
एक प्रोटोकॉल नीचे के रूप में घोषित किया जाना चाहिए:
@protocol ServiceResponceDelegate <NSObject>
- (void) serviceDidFailWithRequestType:(NSString*)error;
- (void) serviceDidFinishedSucessfully:(NSString*)success;
@end
यह सेवा वर्ग है जहां कुछ कार्य किया जाना चाहिए। यह दिखाता है कि प्रतिनिधि को कैसे परिभाषित किया जाए और प्रतिनिधि को कैसे सेट किया जाए। कार्य पूरा होने के बाद कार्यान्वयन वर्ग में प्रतिनिधि के तरीकों को बुलाया जाता है।
@interface ServiceClass : NSObject
{
id <ServiceResponceDelegate> _delegate;
}
- (void) setDelegate:(id)delegate;
- (void) someTask;
@end
@implementation ServiceClass
- (void) setDelegate:(id)delegate
{
_delegate = delegate;
}
- (void) someTask
{
/*
perform task
*/
if (!success)
{
[_delegate serviceDidFailWithRequestType:@”task failed”];
}
else
{
[_delegate serviceDidFinishedSucessfully:@”task success”];
}
}
@end
यह मुख्य दृश्य वर्ग है जहां से प्रतिनिधि को स्वयं को सेट करके सेवा वर्ग कहा जाता है। और हेडर क्लास में भी प्रोटोकॉल लागू किया जाता है।
@interface viewController: UIViewController <ServiceResponceDelegate>
{
ServiceClass* _service;
}
- (void) go;
@end
@implementation viewController
//
//some methods
//
- (void) go
{
_service = [[ServiceClass alloc] init];
[_service setDelegate:self];
[_service someTask];
}
यही है, और इस कक्षा में प्रतिनिधि विधियों को लागू करने से, ऑपरेशन / कार्य पूरा होने के बाद नियंत्रण वापस आ जाएगा।
अस्वीकरण: यह Swift
कैसे बनाने के लिए का एक संस्करण है delegate
।
तो, प्रतिनिधियों क्या हैं? ... सॉफ्टवेयर विकास में, सामान्य पुन: प्रयोज्य समाधान आर्किटेक्चर हैं जो किसी दिए गए संदर्भ के भीतर आमतौर पर होने वाली समस्याओं को हल करने में मदद करते हैं, ये "टेम्पलेट", इसलिए बोलने के लिए, डिजाइन पैटर्न के रूप में जाना जाता है। डेलिगेट्स एक डिज़ाइन पैटर्न है जो किसी वस्तु को किसी विशिष्ट घटना के होने पर दूसरी वस्तु को संदेश भेजने की अनुमति देता है। एक वस्तु की कल्पना करें एक ए क्रिया करने के लिए एक वस्तु बी को बुलाता है। एक बार कार्रवाई पूरी हो जाने के बाद, ऑब्जेक्ट A को पता होना चाहिए कि B ने कार्य पूरा कर लिया है और आवश्यक कार्रवाई कर रहा है, यह प्रतिनिधियों की सहायता से प्राप्त किया जा सकता है!
एक बेहतर व्याख्या के लिए, मैं आपको दिखाने जा रहा हूं कि एक साधारण आवेदन में स्विफ्ट के साथ, कक्षाओं के बीच डेटा पास करने वाले कस्टम प्रतिनिधि कैसे बनाएं, इस स्टार्टर प्रोजेक्ट को डाउनलोड या क्लोन करके शुरू करें और इसे चलाएं!
आप दो वर्गों के साथ एक ऐप देख सकते हैं, ViewController A
और ViewController B
। B के दो विचार हैं कि टैप करने पर पृष्ठभूमि का रंग बदल जाता है ViewController
, कुछ भी जटिल नहीं है? अब अच्छी तरह से सोचें कि क्लास ए के बैकग्राउंड कलर को बदलने का एक आसान तरीका क्या है, जब क्लास बी के दृश्य टैप किए जाते हैं।
समस्या यह है कि यह दृश्य कक्षा बी का हिस्सा हैं और कक्षा ए के बारे में कोई विचार नहीं है, इसलिए हमें इस दो वर्गों के बीच संवाद करने का एक तरीका खोजने की आवश्यकता है, और यही वह स्थान है जहाँ प्रतिनिधिमंडल चमकता है। मैंने कार्यान्वयन को 6 चरणों में विभाजित किया है ताकि आप ज़रूरत पड़ने पर इसे एक धोखा पत्र के रूप में उपयोग कर सकें।
चरण 1: क्लासबीवीसी फ़ाइल में प्राग्मा मार्क चरण 1 के लिए देखें और इसे जोड़ें
//MARK: step 1 Add Protocol here.
protocol ClassBVCDelegate: class {
func changeBackgroundColor(_ color: UIColor?)
}
पहला कदम एक बनाना है protocol
, इस मामले में, हम कक्षा बी में प्रोटोकॉल बनाएंगे, प्रोटोकॉल के अंदर आप अपने कार्यान्वयन की आवश्यकताओं के आधार पर कई फ़ंक्शन बना सकते हैं जो आप चाहते हैं। इस मामले में, हमारे पास केवल एक सरल कार्य है जो UIColor
एक तर्क के रूप में एक वैकल्पिक स्वीकार करता है। एक अच्छा अभ्यास शब्द जोड़कर अपने प्रोटोकॉल नाम के लिए है delegate
इस मामले में वर्ग के नाम के अंत में,, ClassBVCDelegate
।
चरण 2: प्राग्मा चिह्न चरण 2 के लिए देखें ClassVBC
और इसे जोड़ें
//MARK: step 2 Create a delegate property here.
weak var delegate: ClassBVCDelegate?
यहां हम सिर्फ कक्षा के लिए एक प्रतिनिधि संपत्ति बनाते हैं, इस संपत्ति को protocol
प्रकार को अपनाना चाहिए , और यह वैकल्पिक होना चाहिए। इसके अलावा, आपको चक्र और संभावित मेमोरी लीक से बचने के लिए संपत्ति से पहले कमजोर कीवर्ड जोड़ना चाहिए, अगर आपको नहीं पता कि इसका मतलब क्या है तो अभी के लिए चिंता न करें, बस इस कीवर्ड को जोड़ना याद रखें।
चरण 3: handleTap अंदर pragma निशान चरण 3 के लिए देखो method
में ClassBVC
और इस ऐड
//MARK: step 3 Add the delegate method call here.
delegate?.changeBackgroundColor(tapGesture.view?.backgroundColor)
एक बात जो आपको पता होनी चाहिए, ऐप को चलाएं और किसी भी दृश्य पर टैप करें, आपको कोई नया व्यवहार दिखाई नहीं देगा और यह सही है लेकिन जिस चीज़ को मैं इंगित करना चाहता हूं वह यह है कि प्रतिनिधि के कॉल करने पर ऐप क्रैश नहीं हो रहा है, और यह इसलिए है क्योंकि हम इसे एक वैकल्पिक मूल्य के रूप में बनाते हैं और यही कारण है कि यह तब भी दुर्घटनाग्रस्त नहीं होगा जब तक कि प्रतिनिधि अभी तक मौजूद नहीं है। आइए अब ClassAVC
फाइल करते हैं और इसे बनाते हैं, प्रत्यायोजित।
चरण 4: हैंडल पद्धति के अंदर प्राग्मा मार्क चरण 4 के लिए देखें ClassAVC
और इसे अपने वर्ग प्रकार के बगल में इस तरह जोड़ें।
//MARK: step 4 conform the protocol here.
class ClassAVC: UIViewController, ClassBVCDelegate {
}
अब ClassAVC ने ClassBVCDelegate
प्रोटोकॉल अपनाया , आप देख सकते हैं कि आपका कंपाइलर आपको एक त्रुटि दे रहा है, जो कहता है कि "Type 'ClassAVC प्रोटोकॉल' ClassBVCDelegate 'के अनुरूप नहीं है और इसका केवल यह अर्थ है कि आपने अभी तक प्रोटोकॉल के तरीकों का उपयोग नहीं किया है, कल्पना करें कि जब क्लास ए प्रोटोकॉल को अपनाता है, तो क्लास बी के साथ एक अनुबंध पर हस्ताक्षर करने जैसा होता है और यह अनुबंध कहता है कि "कोई भी वर्ग मुझे अपनाता है जो मेरे कार्यों का उपयोग करना चाहिए!"
त्वरित ध्यान दें: यदि आप एक ऐसी Objective-C
पृष्ठभूमि से आते हैं जो आप शायद सोच रहे हैं कि आप उस पद्धति को वैकल्पिक बनाते हुए उस त्रुटि को भी बंद कर सकते हैं, लेकिन मेरे आश्चर्य के लिए, और शायद आपकी, Swift
भाषा वैकल्पिक का समर्थन नहीं करती है protocols
, यदि आप ऐसा करना चाहते हैं, तो आप इसे बना सकते हैं आपके विस्तार के लिए protocol
या आपके protocol
कार्यान्वयन में @objc कीवर्ड का उपयोग करें ।
व्यक्तिगत रूप से, अगर मुझे अलग-अलग वैकल्पिक तरीकों के साथ एक प्रोटोकॉल बनाना है तो मैं इसे अलग-अलग रूप में तोड़ना पसंद करूंगा protocols
, इस तरह मैं अपनी वस्तुओं को एक ही जिम्मेदारी देने की अवधारणा का पालन करूंगा, लेकिन यह विशिष्ट कार्यान्वयन के आधार पर भिन्न हो सकता है।
यहाँ वैकल्पिक तरीकों के बारे में एक अच्छा लेख है।
चरण 5: सीग विधि की तैयारी के अंदर pragma मार्क चरण 5 के लिए देखें और इसे जोड़ें
//MARK: step 5 create a reference of Class B and bind them through the `prepareforsegue` method.
if let nav = segue.destination as? UINavigationController, let classBVC = nav.topViewController as? ClassBVC {
classBVC.delegate = self
}
यहाँ हम केवल एक उदाहरण बना रहे हैं ClassBVC
और अपने प्रतिनिधि को स्वयं असाइन करते हैं, लेकिन यहाँ स्वयं क्या है? ठीक है, स्व हैClassAVC
जो प्रत्यायोजित किया गया है!
चरण 6: अंत में, चरण 6 के लिए खोज करें ClassAVC
और चलो के कार्यों का उपयोग करें protocol
, टाइप करना शुरू करें func changeBackgroundColor और आप देखेंगे कि यह आपके लिए इसे ऑटो-पूरा कर रहा है। आप इसके अंदर कोई भी कार्यान्वयन जोड़ सकते हैं, इस उदाहरण में, हम सिर्फ पृष्ठभूमि का रंग बदल देंगे, इसे जोड़ सकते हैं।
//MARK: step 6 finally use the method of the contract
func changeBackgroundColor(_ color: UIColor?) {
view.backgroundColor = color
}
अब ऐप चलाएं!
Delegates
हर जगह हैं और आप शायद उन्हें बिना किसी नोटिस के भी उपयोग करते हैं, यदि आप tableview
अतीत में आपने प्रतिनिधिमंडल का उपयोग किया था, तो UIKIT
उनके आसपास कई तरह के काम और कई अन्य frameworks
भी, वे इन मुख्य समस्याओं को हल करते हैं।
बधाई हो, आप सिर्फ एक कस्टम प्रतिनिधि को लागू करते हैं, मुझे पता है कि आप शायद सोच रहे हैं, बस इसके लिए इतनी परेशानी? यदि आप एक iOS
डेवलपर बनना चाहते हैं, तो समझने के लिए प्रतिनिधिमंडल एक बहुत ही महत्वपूर्ण डिजाइन पैटर्न है , और हमेशा ध्यान रखें कि वस्तुओं के बीच उनका एक से एक संबंध है।
आप यहां मूल ट्यूटोरियल देख सकते हैं
उत्तर वास्तव में उत्तर दिया गया है, लेकिन मैं आपको एक प्रतिनिधि बनाने के लिए "धोखा पत्र" देना चाहूंगा:
DELEGATE SCRIPT
CLASS A - Where delegate is calling function
@protocol <#Protocol Name#> <NSObject>
-(void)delegateMethod;
@end
@interface <#Some ViewController#> : <#UIViewController#>
@property (nonatomic, assign) id <<#Protocol Name#>> delegate;
@end
@implementation <#Some ViewController#>
-(void)someMethod {
[self.delegate methodName];
}
@end
CLASS B - Where delegate is called
@interface <#Other ViewController#> (<#Delegate Name#>) {}
@end
@implementation <#Other ViewController#>
-(void)otherMethod {
CLASSA *classA = [[CLASSA alloc] init];
[classA setDelegate:self];
}
-delegateMethod() {
}
@end
ViewController.h
@protocol NameDelegate <NSObject>
-(void)delegateMEthod: (ArgType) arg;
@end
@property id <NameDelegate> delegate;
ViewController.m
[self.delegate delegateMEthod: argument];
MainViewController.m
ViewController viewController = [ViewController new];
viewController.delegate = self;
तरीका:
-(void)delegateMEthod: (ArgType) arg{
}
मेरे विचार से उस प्रतिनिधि पद्धति के लिए अलग वर्ग बनाएँ और आप जहाँ चाहें, वहाँ उपयोग कर सकते हैं।
मेरे कस्टम DropDownClass.h में
typedef enum
{
DDSTATE,
DDCITY
}DropDownType;
@protocol DropDownListDelegate <NSObject>
@required
- (void)dropDownDidSelectItemWithString:(NSString*)itemString DropDownType:(DropDownType)dropDownType;
@end
@interface DropDownViewController : UIViewController
{
BOOL isFiltered;
}
@property (nonatomic, assign) DropDownType dropDownType;
@property (weak) id <DropDownListDelegate> delegate;
@property (strong, nonatomic) NSMutableArray *array1DropDown;
@property (strong, nonatomic) NSMutableArray *array2DropDown;
उसके बाद in.m फ़ाइल ऑब्जेक्ट्स के साथ सरणी बनाएँ,
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
CGFloat rowHeight = 44.0f;
return rowHeight;
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return isFiltered?[self.array1DropDown count]:[self.array2DropDown count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *simpleTableIdentifier = @"TableCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
if (self.delegate) {
if (self.dropDownType == DDCITY) {
cell.textLabel.text = [self.array1DropDown objectAtIndex:indexPath.row];
}
else if (self.dropDownType == DDSTATE) {
cell.textLabel.text = [self.array2DropDown objectAtIndex:indexPath.row];
}
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self dismissViewControllerAnimated:YES completion:^{
if(self.delegate){
if(self.dropDownType == DDCITY){
[self.delegate dropDownDidSelectItemWithString:[self.array1DropDown objectAtIndex:indexPath.row] DropDownType:self.dropDownType];
}
else if (self.dropDownType == DDSTATE) {
[self.delegate dropDownDidSelectItemWithString:[self.array2DropDown objectAtIndex:indexPath.row] DropDownType:self.dropDownType];
}
}
}];
}
यहां सभी कस्टम प्रतिनिधि वर्ग के लिए निर्धारित किए गए हैं। इसके बाद आप इस प्रतिनिधि पद्धति का उपयोग कर सकते हैं, जहां आप चाहते हैं। उदाहरण के लिए ...
उसके बाद मेरे एक और दृश्यमंच आयात में
इस तरह से प्रतिनिधि पद्धति को बुलाने के लिए कार्रवाई करें
- (IBAction)dropDownBtn1Action:(id)sender {
DropDownViewController *vehicleModelDropView = [[DropDownViewController alloc]init];
vehicleModelDropView.dropDownType = DDCITY;
vehicleModelDropView.delegate = self;
[self presentViewController:vehicleModelDropView animated:YES completion:nil];
}
इसके बाद डेलिगेट विधि को इस तरह से कॉल करें
- (void)dropDownDidSelectItemWithString:(NSString *)itemString DropDownType:(DropDownType)dropDownType {
switch (dropDownType) {
case DDCITY:{
if(itemString.length > 0){
//Here i am printing the selected row
[self.dropDownBtn1 setTitle:itemString forState:UIControlStateNormal];
}
}
break;
case DDSTATE: {
//Here i am printing the selected row
[self.dropDownBtn2 setTitle:itemString forState:UIControlStateNormal];
}
default:
break;
}
}
प्रतिनिधि: - बनाएँ
@protocol addToCartDelegate <NSObject>
-(void)addToCartAction:(ItemsModel *)itemsModel isAdded:(BOOL)added;
@end
आप डेटा भेज रहे हैं यह देखने के लिए प्रतिनिधि भेजें और भेजें
[self.delegate addToCartAction:itemsModel isAdded:YES];
//1.
//Custom delegate
@protocol TB_RemovedUserCellTag <NSObject>
-(void)didRemoveCellWithTag:(NSInteger)tag;
@end
//2.
//Create a weak reference in a class where you declared the delegate
@property(weak,nonatomic)id <TB_RemovedUserCellTag> removedCellTagDelegate;
//3.
// use it in the class
[self.removedCellTagDelegate didRemoveCellWithTag:self.tag];
//4. import the header file in the class where you want to conform to the protocol
@interface MyClassUsesDelegate ()<TB_RemovedUserCellTag>
@end
// 5। कक्षा में विधि को लागू करें .m - (शून्य) didRemoveCellWithTag: (NSInteger) टैग {NSLog @ ("टैग% d", टैग);
}
आइए एक उदाहरण के साथ शुरू करते हैं, यदि हम ऑनलाइन उत्पाद खरीदते हैं, तो यह अलग-अलग टीमों द्वारा संचालित शिपिंग / डिलीवरी जैसी प्रक्रिया से गुजरता है। अगर शिपिंग पूरी हो जाती है, तो शिपिंग टीम को डिलीवरी टीम को सूचित करना चाहिए और यह एक से एक संचार होना चाहिए क्योंकि यह जानकारी प्रसारित करता है। अन्य लोगों के लिए ओवरहेड हो जाएगा / विक्रेता इस जानकारी को केवल आवश्यक लोगों तक पहुंचाना चाहते हैं।
इसलिए अगर हम अपने ऐप के संदर्भ में सोचते हैं, तो एक घटना ऑनलाइन ऑर्डर हो सकती है और अलग-अलग टीमें एक से अधिक विचारों की तरह हो सकती हैं।
यहाँ कोड को नौवहन दृश्य के रूप में शिपिंग टीम और डिलिवरी दृश्य को डिलीवरी टीम माना गया है:
//Declare the protocol with functions having info which needs to be communicated
protocol ShippingDelegate : class {
func productShipped(productID : String)
}
//shippingView which shows shipping status of products
class ShippingView : UIView
{
weak var delegate:ShippingDelegate?
var productID : String
@IBAction func checkShippingStatus(sender: UIButton)
{
// if product is shipped
delegate?.productShipped(productID: productID)
}
}
//Delivery view which shows delivery status & tracking info
class DeliveryView: UIView,ShippingDelegate
{
func productShipped(productID : String)
{
// update status on view & perform delivery
}
}
//Main page on app which has both views & shows updated info on product whole status
class ProductViewController : UIViewController
{
var shippingView : ShippingView
var deliveryView : DeliveryView
override func viewDidLoad() {
super.viewDidLoad()
// as we want to update shipping info on delivery view, so assign delegate to delivery object
// whenever shipping status gets updated it will call productShipped method in DeliveryView & update UI.
shippingView.delegate = deliveryView
//
}
}