उद्देश्य-सी में कॉलबैक कैसे करें


119

उद्देश्य-सी में कॉल बैक फ़ंक्शन कैसे करें?

मैं कुछ पूर्ण उदाहरण देखना चाहूंगा और मुझे इसे समझना चाहिए।

जवाबों:


94

आम तौर पर, उद्देश्य C में कॉलबैक प्रतिनिधियों के साथ किया जाता है। यहाँ एक कस्टम प्रतिनिधि कार्यान्वयन का एक उदाहरण है;


शीर्ष लेख फ़ाइल:

@interface MyClass : NSObject {
    id delegate;
}
- (void)setDelegate:(id)delegate;
- (void)doSomething;
@end

@interface NSObject(MyDelegateMethods)
- (void)myClassWillDoSomething:(MyClass *)myClass;
- (void)myClassDidDoSomething:(MyClass *)myClass;
@end

कार्यान्वयन (.m) फ़ाइल

@implementation MyClass
- (void)setDelegate:(id)aDelegate {
    delegate = aDelegate; /// Not retained
}

- (void)doSomething {
    [delegate myClassWillDoSomething:self];
    /* DO SOMETHING */
    [delegate myClassDidDoSomething:self];
}
@end

यह सामान्य दृष्टिकोण को दर्शाता है। आप NSObject पर एक श्रेणी बनाते हैं जो आपके कॉलबैक विधियों के नामों की घोषणा करता है। NSObject वास्तव में इन विधियों को लागू नहीं करता है। इस प्रकार की श्रेणी को एक अनौपचारिक प्रोटोकॉल कहा जाता है, आप बस कह रहे हैं कि कई ऑब्जेक्ट इन विधियों को लागू कर सकते हैं। वे आगे चयनकर्ता के प्रकार के हस्ताक्षर की घोषणा करने का एक तरीका हैं।

आगे आपके पास कुछ ऑब्जेक्ट "MyClass" के प्रतिनिधि होंगे और MyClass प्रतिनिधि को प्रतिनिधि के तरीके को उपयुक्त बताते हैं। यदि आपके प्रतिनिधि कॉलबैक वैकल्पिक हैं, तो आप आम तौर पर उन्हें प्रेषण साइट पर कुछ इस तरह से रख सकते हैं, जैसे "अगर ([प्रतिनिधि का जवाब है। उत्तर: @selector (myClassWillDoSomething :)) {"। मेरे उदाहरण में, प्रतिनिधि को दोनों तरीकों को लागू करने की आवश्यकता है।

अनौपचारिक प्रोटोकॉल के बजाय, आप @protocol से परिभाषित एक औपचारिक प्रोटोकॉल का भी उपयोग कर सकते हैं। यदि आप ऐसा करते हैं, तो आप प्रतिनिधि सेटर के प्रकार को बदल देंगे, और चर को id <MyClassDelegate>केवल " id" के बजाय " " होने देंगे ।

इसके अलावा, आप देखेंगे कि प्रतिनिधि बरकरार नहीं है। यह आमतौर पर किया जाता है क्योंकि ऑब्जेक्ट जो "MyClass" के "मालिक" उदाहरण हैं, आमतौर पर भी प्रतिनिधि हैं। यदि MyClass ने अपने प्रतिनिधि को बनाए रखा, तो एक चक्र होगा। यह एक वर्ग के डीललोक पद्धति में एक अच्छा विचार है जिसमें एक MyClass उदाहरण है और इसके प्रतिनिधि को यह स्पष्ट करना है कि यह एक कमजोर बैक पॉइंटर होने के बाद से उस प्रतिनिधि को संदर्भित करता है। अन्यथा अगर कुछ MyClass उदाहरण को जीवित रख रहा है, तो आपके पास झूलने वाला सूचक होगा।


+1 अच्छा जवाब। केक पर आइसिंग प्रतिनिधियों पर अधिक गहराई से एप्पल प्रलेखन के लिए एक कड़ी होगी। :-)
क्विन टेलर

जॉन, आपकी मदद के लिए बहुत बहुत धन्यवाद। तुम्हारी मदद के लिए शुक्रिया। मुझे इस पर खेद है, लेकिन मैं उत्तर पर बहुत स्पष्ट नहीं हूं। संदेश .m एक ऐसा वर्ग है जो doSomething फ़ंक्शन कॉल के दौरान खुद को प्रतिनिधि के रूप में सेट करता है। क्या उपयोगकर्ता कॉल करता है कॉलबैक फ़ंक्शन को पूरा करना? चूँकि मैं इस धारणा के तहत हूं कि उपयोगकर्ता doSomething को कॉल करता है, और आपके कॉल बैक फ़ंक्शन myClassWillDoSomethingg और myClassDidDoSomething हैं। साथ ही, क्या आप मुझे दिखा सकते हैं कि एक उच्च श्रेणी कैसे बनाई जाए जो कॉल बैक फ़ंक्शन को कॉल करता है। मैं एक सी प्रोग्रामर हूं इसलिए मैं ओब्ज-सी के वातावरण से अभी तक परिचित नहीं हूं।
RucConnection

"संदेश .m" का अर्थ है, आप .m फ़ाइल में हैं। आपके पास एक अलग वर्ग होगा, चलो इसे "फू" कहते हैं। फू का "MyClass * myClass" वैरिएबल होगा, और कुछ बिंदु पर फू कहेंगे "[myClass setDelegate: self]"। उसके बाद किसी भी बिंदु पर, अगर कोई भी शामिल है, जिसमें foo सहित किसी ने MyClass के doSomethingMethod को आमंत्रित किया है, तो foo का myClassWillDoSomething, और myClassDidDoSomething रिकॉर्ड किया जाएगा। मैं वास्तव में सिर्फ एक दूसरा अलग उदाहरण पोस्ट करूँगा जो प्रतिनिधियों का उपयोग नहीं करता है।
जॉन हेस

मुझे नहीं लगता कि .m "संदेश" के लिए खड़ा है।
चक


140

पूर्णता के लिए, चूंकि StackOverflow RSS ने केवल मेरे लिए प्रश्न को यादृच्छिक रूप से पुनर्जीवित किया है, अन्य (नया) विकल्प ब्लॉक का उपयोग करना है:

@interface MyClass: NSObject
{
    void (^_completionHandler)(int someParameter);
}

- (void) doSomethingWithCompletionHandler:(void(^)(int))handler;
@end


@implementation MyClass

- (void) doSomethingWithCompletionHandler:(void(^)(int))handler
{
    // NOTE: copying is very important if you'll call the callback asynchronously,
    // even with garbage collection!
    _completionHandler = [handler copy];

    // Do stuff, possibly asynchronously...
    int result = 5 + 3;

    // Call completion handler.
    _completionHandler(result);

    // Clean up.
    [_completionHandler release];
    _completionHandler = nil;
}

@end

...

MyClass *foo = [[MyClass alloc] init];
int x = 2;
[foo doSomethingWithCompletionHandler:^(int result){
    // Prints 10
    NSLog(@"%i", x + result);
}];

2
@ अहरमन: "शून्य" का क्या अर्थ है "शून्य (^ _completionHandler) (int someParameter);" क्या मतलब है? क्या आप बता सकते हैं कि वह रेखा क्या करती है?
कोनराड हॉफनर

2
क्या आप कॉलबैक हैंडलर को कॉपी करने की आवश्यकता का स्पष्टीकरण प्रदान कर सकते हैं?
इलियट संभावना

52

यहाँ एक उदाहरण है जो प्रतिनिधियों की अवधारणाओं को बाहर रखता है, और बस एक कच्चा कॉल वापस करता है।

@interface Foo : NSObject {
}
- (void)doSomethingAndNotifyObject:(id)object withSelector:(SEL)selector;
@end

@interface Bar : NSObject {
}
@end

@implementation Foo
- (void)doSomethingAndNotifyObject:(id)object withSelector:(SEL)selector {
    /* do lots of stuff */
    [object performSelector:selector withObject:self];
}
@end

@implementation Bar
- (void)aMethod {
    Foo *foo = [[[Foo alloc] init] autorelease];
    [foo doSomethingAndNotifyObject:self withSelector:@selector(fooIsDone:)];
}

- (void)fooIsDone:(id)sender {
    NSLog(@"Foo Is Done!");
}
@end

आमतौर पर विधि - [फू doSomethingAndNotifyObject: withSelector:] अतुल्यकालिक होगी जो कॉलबैक को यहां से अधिक उपयोगी बनाती है।


1
बहुत बहुत धन्यवाद जॉन। मैं आपकी टिप्पणियों के बाद आपके पहले कॉलबैक कार्यान्वयन को समझता हूं। साथ ही, आपका दूसरा कॉलबैक कार्यान्वयन अधिक सरल है। दोनों बहुत अच्छे हैं।
पहुंचना

1
इस जॉन को पोस्ट करने के लिए धन्यवाद, यह बहुत मददगार था। मुझे बदलना पड़ा [ऑब्जेक्ट PerformelectorwithObject: self]; [ऑब्जेक्ट PerformSelector: चयनकर्ता withObject: self]; इसे सही ढंग से काम करने के लिए पाने के लिए।
बंजर

16

इस सवाल को अप-टू-डेट रखने के लिए, आईओएस 5.0 की एआरसी की शुरूआत का मतलब है कि इसे ब्लॉक का उपयोग करके और भी संक्षिप्त रूप से प्राप्त किया जा सकता है :

@interface Robot: NSObject
+ (void)sayHi:(void(^)(NSString *))callback;
@end

@implementation Robot
+ (void)sayHi:(void(^)(NSString *))callback {
    // Return a message to the callback
    callback(@"Hello to you too!");
}
@end

[Robot sayHi:^(NSString *reply){
  NSLog(@"%@", reply);
}];

यदि आप कभी ऑब्जेक्टिव-सी के ब्लॉक सिंटैक्स को भूल जाते हैं, तो हमेशा ब्लॉक सिंटैक्स पर F **** होता है ।


@ इनट्रेडफेस में + (void)sayHi:(void(^)(NSString *reply))callback;नहीं होना चाहिए+ (void)sayHi:(void(^)(NSString *))callback;
टिम 007

उपर्युक्त एफ **** एनजी सिंटैक्स के अनुसार नहीं : - (void)someMethodThatTakesABlock:(returnType (^nullability)(parameterTypes))blockName;(नोट parameterTypesनहीं parameters)
रयान ब्रॉडी

4

CallBack: Objective C में 4 प्रकार के कॉलबैक हैं

  1. चयनकर्ता प्रकार : आप NSTimer देख सकते हैं, UIPangesture चयनकर्ता कॉलबैक के उदाहरण हैं। कोड के बहुत सीमित निष्पादन के लिए उपयोग किया जाता है।

  2. डेलिगेट प्रकार : सामान्य और Apple ढांचे में सबसे अधिक उपयोग किया जाता है। UITableViewDelegate, NSNURLConnectionDelegate। वे आमतौर पर सर्वर से अतुल्यकालिक रूप से कई छवियों को डाउनलोड करने के लिए उपयोग किए जाते हैं।

  3. NSNotifications : NotificationCenter ऑब्जेक्टिव C की एक विशेषता है जो कि घटना होने पर कई रसीदों को सूचित करने के लिए उपयोग की जाती है।
  4. ब्लॉक : ऑब्जेक्टिव C प्रोग्रामिंग में ब्लॉक का इस्तेमाल आमतौर पर किया जाता है। यह बहुत अच्छी सुविधा है और कोड का हिस्सा निष्पादित करने के लिए उपयोग किया जाता है। आप ट्यूटोरियल को समझने के लिए भी संदर्भित कर सकते हैं: ब्लॉक ट्यूटोरियल

कृपया मुझे इसके लिए कोई अन्य उत्तर दें। मैं इसकी प्रशंसा करूंगा।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.