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


145

मैं Blocka Function/ कैसे पास कर सकता हूं Method?

मैंने - (void)someFunc:(__Block)someBlockकोई फायदा नहीं हुआ।

अर्थात। एक प्रकार के लिए क्या है Block?


7
एक संदर्भ जिसे मैं अपनी देखभाल से अधिक उपयोग करता हूं: goshdarnblocksyntax.com
oltman

जवाबों:


257

एक ब्लॉक का प्रकार उसके तर्कों और उसके रिटर्न प्रकार के आधार पर भिन्न होता है। सामान्य स्थिति में, ब्लॉक प्रकारों को उसी तरह से घोषित किया जाता है जैसे फ़ंक्शन पॉइंटर प्रकार होते हैं, लेकिन *ए के साथ प्रतिस्थापित करना ^। एक ब्लॉक को एक विधि में पारित करने का एक तरीका इस प्रकार है:

- (void)iterateWidgets:(void (^)(id, int))iteratorBlock;

लेकिन जैसा कि आप देख सकते हैं, यह गड़बड़ है। आप इसके बजाय typedefब्लॉक प्रकार को क्लीनर बनाने के लिए उपयोग कर सकते हैं :

typedef void (^ IteratorBlock)(id, int);

और फिर उस ब्लॉक को इस तरह से पास करें:

- (void)iterateWidgets:(IteratorBlock)iteratorBlock;

आप आईडी को एक तर्क के रूप में क्यों पारित कर रहे हैं? क्या उदाहरण के लिए NSNumber को आसानी से पास करना संभव नहीं है? कैसा लगेगा?
बस

7
आप निश्चित रूप से इस तरह के रूप में एक जोरदार टाइप तर्क पारित कर सकते हैं NSNumber *या std::string&या कुछ और आप एक समारोह तर्क के रूप में दे सकते हैं। यह सिर्फ एक उदाहरण है। (एक ब्लॉक है कि जगह के लिए छोड़कर बराबर है के लिए idके साथ NSNumber, typedefहो सकता है typedef void (^ IteratorWithNumberBlock)(NSNumber *, int);।)
जोनाथन Grynspan

यह विधि घोषणा को दर्शाता है। ब्लॉकों के साथ एक परेशानी यह है कि "गड़बड़" घोषणा शैली वास्तविक ब्लॉक कॉल के साथ वास्तविक विधि कॉल को लिखने के लिए स्पष्ट और आसान नहीं बनाती है।
uchuugaka

Typedefs न केवल लिखने के लिए कोड को आसान बनाते हैं, बल्कि ब्लॉक / फ़ंक्शन पॉइंटर सिंटैक्स को पढ़ने में काफी आसान होते हैं।
pyj

@JonathanGrynspan, स्विफ्ट दुनिया से आ रहा है, लेकिन कुछ पुराने उद्देश्य-सी कोड को छूने के लिए, मैं कैसे बता सकता हूं कि कोई ब्लॉक बच रहा है या नहीं? मैंने पढ़ा है कि डिफ़ॉल्ट रूप से, ब्लॉक से बच रहे हैं अगर के साथ सजाया गया है NS_NOESCAPE, लेकिन enumerateObjectsUsingBlockमुझे बताया गया है कि गैर-बच रहा है, फिर भी मैं NS_NOESCAPEसाइट में कहीं भी नहीं देखता हूं , और न ही एप्पल डॉक्स में उल्लेख किया गया है। क्या आप मदद कर सकते हैं?
मार्क ए। डोनोहे

62

इस प्रश्न का सबसे आसान स्पष्टीकरण इन टेम्पलेट्स का पालन करना है:

1. एक विधि पैरामीटर के रूप में ब्लॉक करें

खाका

- (void)aMethodWithBlock:(returnType (^)(parameters))blockName {
        // your code
}

उदाहरण

-(void) saveWithCompletionBlock: (void (^)(NSArray *elements, NSError *error))completionBlock{
        // your code
}

मामलों का अन्य उपयोग:

2. एक संपत्ति के रूप में ब्लॉक करें

खाका

@property (nonatomic, copy) returnType (^blockName)(parameters);

उदाहरण

@property (nonatomic,copy)void (^completionBlock)(NSArray *array, NSError *error);

3. विधि तर्क के रूप में ब्लॉक करें

खाका

[anObject aMethodWithBlock: ^returnType (parameters) {
    // your code
}];

उदाहरण

[self saveWithCompletionBlock:^(NSArray *array, NSError *error) {
    // your code
}];

4. एक स्थानीय चर के रूप में ब्लॉक करें

खाका

returnType (^blockName)(parameters) = ^returnType(parameters) {
    // your code
};

उदाहरण

void (^completionBlock) (NSArray *array, NSError *error) = ^void(NSArray *array, NSError *error){
    // your code
};

5. एक टंकण के रूप में ब्लॉक करें

खाका

typedef returnType (^typeName)(parameters);

typeName blockName = ^(parameters) {
    // your code
}

उदाहरण

typedef void(^completionBlock)(NSArray *array, NSError *error);

completionBlock didComplete = ^(NSArray *array, NSError *error){
    // your code
};

1
[self saveWithCompletionBlock: ^ (NSArray * एरे, NSError * एरर) {// आपके कंप्यूटर}]; इस उदाहरण में रिटर्न प्रकार को अनदेखा किया जाता है क्योंकि यह शून्य है?
एलेक्स

51

यह सहायक हो सकता है:

- (void)someFunc:(void(^)(void))someBlock;

आप
newacct

यह एक मेरे लिए काम करता है जबकि पिछले एक नहीं था। Btw धन्यवाद दोस्त, कि वास्तव में उपयोगी था!
tanou

23

आप इस तरह से कर सकते हैं, एक ब्लॉक पैरामीटर के रूप में पासिंग ब्लॉक:

//creating a block named "completion" that will take no arguments and will return void
void(^completion)() = ^() {
    NSLog(@"bbb");
};

//creating a block namd "block" that will take a block as argument and will return void
void(^block)(void(^completion)()) = ^(void(^completion)()) {
    NSLog(@"aaa");
    completion();
};

//invoking block "block" with block "completion" as argument
block(completion);

8

नीचे उदाहरण में с फ़ंक्शन का उपयोग करके ब्लॉक पास करने का एक और तरीका। I`ve ने पृष्ठभूमि में और मुख्य कतार में कुछ भी प्रदर्शन करने के लिए फ़ंक्शंस बनाए।

blocks.h फ़ाइल

void performInBackground(void(^block)(void));
void performOnMainQueue(void(^block)(void));

blocks.m फ़ाइल

#import "blocks.h"

void performInBackground(void(^block)(void)) {
    if (nil == block) {
        return;
    }

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), block);
}

void performOnMainQueue(void(^block)(void)) {
    if (nil == block) {
        return;
    }

    dispatch_async(dispatch_get_main_queue(), block);
}

आवश्यक होने पर ब्लॉक इंसेक्ट करें और इसे लागू करें:

- (void)loadInBackground {

    performInBackground(^{

        NSLog(@"Loading something in background");
        //loading code

        performOnMainQueue(^{
            //completion hadler code on main queue
        });
    });
}

6

यदि यह आपके लिए लागू है, तो आप ब्लॉक को एक साधारण संपत्ति के रूप में भी सेट कर सकते हैं:

@property (nonatomic, copy) void (^didFinishEditingHandler)(float rating, NSString *reviewString);

सुनिश्चित करें कि ब्लॉक संपत्ति "कॉपी" है!

और निश्चित रूप से आप typedef का उपयोग कर सकते हैं:

typedef void (^SimpleBlock)(id);

@property (nonatomic, copy) SimpleBlock someActionHandler;

5

इसके अलावा आप सामान्य सी फ़ंक्शन सिंटैक्स का उपयोग करके किसी ब्लॉक को आमंत्रित या कॉल करते हैं

-(void)iterateWidgets:(IteratorBlock)iteratorBlock{

    iteratorBlock(someId, someInt);
}

यहाँ ब्लॉकों पर अधिक जानकारी

http://developer.apple.com/library/ios/#documentation/cocoa/Conceptual/Blocks/Articles/bxGettingStarted.html#//apple_ref/doc/uid/TP40007502-CH7-SW1


4

मैं हमेशा ब्लॉक सिंटैक्स के बारे में भूल जाता हूं। यह हमेशा मेरे दिमाग में आता है जब मुझे ब्लॉक घोषित करने की आवश्यकता होती है। मुझे आशा है कि यह किसी की मदद करता है :)

http://fuckingblocksyntax.com


इसने मेरा समय बचाया
ले डिंग

3

मैंने एक वर्ग के लिए एक पूरा लेखन लिखा है जो पासा के मूल्यों को वापस कर देगा, जिसके बाद वे हिल गए हैं:

  1. वापसी के साथ टाइपराइफ को परिभाषित करें ( घोषणा के .hऊपर @interface)

    typedef void (^CompleteDiceRolling)(NSInteger diceValue);
  2. @propertyब्लॉक के लिए परिभाषित करें ( .h)

    @property (copy, nonatomic) CompleteDiceRolling completeDiceRolling;
  3. finishBlock( .h) के साथ एक विधि परिभाषित करें

    - (void)getDiceValueAfterSpin:(void (^)(NSInteger diceValue))finishBlock;
  4. में पहले से निर्धारित विधि सम्मिलित .mफ़ाइल और प्रतिबद्ध finishBlockकरने @propertyसे पहले परिभाषित

    - (void)getDiceValueAfterSpin:(void (^)(NSInteger diceValue))finishBlock{
        self.completeDiceRolling = finishBlock;
    }
  5. completionBlockपास पूर्वनिर्धारित चर टाइप करने के लिए इसे ट्रिगर करें (यह जाँचना न भूलें कि क्या completionBlockमौजूद है)

    if( self.completeDiceRolling ){
        self.completeDiceRolling(self.dieValue);
    }

2

इस सूत्र पर दिए गए उत्तर के बावजूद, मैं वास्तव में एक फ़ंक्शन लिखने के लिए संघर्ष कर रहा था, जो एक फ़ंक्शन के रूप में ब्लॉक ले जाएगा - और एक पैरामीटर के साथ। आखिरकार, यहाँ मैं समाधान के साथ आया हूँ।

मैं एक सामान्य फ़ंक्शन लिखना चाहता था loadJSONthread, जो JSON वेब सेवा का URL लेगा, इस JSON डेटा को बैकग्राउंड थ्रेड पर कुछ JSON डेटा लोड करेगा, फिर परिणाम के NSArray * को कॉलिंग फ़ंक्शन पर वापस लौटाएगा।

मूल रूप से, मैं एक सामान्य पुन: प्रयोज्य समारोह में सभी पृष्ठभूमि-धागा जटिलता को दूर रखना चाहता था।

यहां बताया गया है कि मैं इस फ़ंक्शन को कैसे कॉल करूंगा:

NSString* WebServiceURL = @"http://www.inorthwind.com/Service1.svc/getAllCustomers";

[JSONHelper loadJSONthread:WebServiceURL onLoadedData:^(NSArray *results) {

    //  Finished loading the JSON data
    NSLog(@"Loaded %lu rows.", (unsigned long)results.count);

    //  Iterate through our array of Company records, and create/update the records in our SQLite database
    for (NSDictionary *oneCompany in results)
    {
        //  Do something with this Company record (eg store it in our SQLite database)
    }

} ];

... और यह थोड़ा सा मैंने संघर्ष किया है: इसे कैसे घोषित किया जाए, और डेटा लोड होने पर इसे ब्लॉक फ़ंक्शन को कॉल करने के लिए कैसे प्राप्त किया जाए, और Blockलोड किए गए रिकॉर्ड का एक NSArray * पास करें :

+(void)loadJSONthread:(NSString*)urlString onLoadedData:(void (^)(NSArray*))onLoadedData
{
    __block NSArray* results = nil;

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^{

        // Call an external function to load the JSON data 
        NSDictionary * dictionary = [JSONHelper loadJSONDataFromURL:urlString];
        results = [dictionary objectForKey:@"Results"];

        dispatch_async(dispatch_get_main_queue(), ^{

            // This code gets run on the main thread when the JSON has loaded
            onLoadedData(results);

        });
    });
}

यह स्टैकऑवरफ़्लो प्रश्न यह कहता है कि फ़ंक्शंस को कैसे कॉल किया जाए, एक ब्लॉक को एक पैरामीटर के रूप में पारित किया जाए, इसलिए मैंने ऊपर दिए गए कोड को सरल किया है, और loadJSONDataFromURLफ़ंक्शन को शामिल नहीं किया है ।

लेकिन, यदि आप रुचि रखते हैं, तो आप इस ब्लॉग पर JSON लोडिंग फ़ंक्शन की एक प्रति पा सकते हैं: http://mikesknowledgebase.azurewebooks.net/pages/Services/WebServices-Page6.htm

उम्मीद है कि यह कुछ अन्य XCode डेवलपर्स में मदद करता है! (इस सवाल और मेरे जवाब को मत भूलना, अगर यह करता है!)


1
यह गंभीरता से ios और ब्लॉक के लिए देखी गई सबसे अच्छी चालों में से एक है। प्यार करो यार !!!!
portforwardpodcast

1

पूरा खाका जैसा दिखता है

- (void) main {
    //Call
    [self someMethodWithSuccessBlock:^{[self successMethod];}
                    withFailureBlock:^(NSError * error) {[self failureMethod:error];}];
}

//Definition
- (void) someMethodWithSuccessBlock:(void (^) (void))successBlock
                   withFailureBlock:(void (^) (NSError*))failureBlock {

    //Execute a block
    successBlock();

//    failureBlock([[NSError alloc]init]);

}

- (void) successMethod {

}

- (void) failureMethod:(NSError*) error {

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