পরামিতি হিসাবে অবজেক্টিভ-সি পাস ব্লক


144

আমি কীভাবে Blockএকটি Function/ এ পাস করতে পারি Method?

আমি চেষ্টা - (void)someFunc:(__Block)someBlockকরেও কোন লাভ হয়নি।

অর্থাত। কি ধরনের একটি জন্য Block?


7
আমি উল্লেখ করার চেয়ে যত্নের চেয়ে বেশি ব্যবহার করি এমন একটি রেফারেন্স: goshdarnblocksyntax.com
অল্টম্যান

উত্তর:


256

তার যুক্তি এবং তার ফেরতের ধরণের উপর নির্ভর করে একটি ব্লকের ধরণ পরিবর্তিত হয়। সাধারণ ক্ষেত্রে, ব্লক প্রকারগুলি একইভাবে ঘোষিত হয় ফাংশন পয়েন্টার প্রকারগুলি, তবে এটিকে *একটি দ্বারা প্রতিস্থাপন করা হয় ^। কোনও পদ্ধতিতে ব্লক পাস করার একটি উপায় নিম্নরূপ:

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

তবে আপনি দেখতে পাচ্ছেন যে এটি অগোছালো। পরিবর্তে typedefব্লক ধরণের ক্লিনার তৈরি করতে আপনি একটি ব্যবহার করতে পারেন :

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

এবং তারপরে সেই ব্লকটি কোনও পদ্ধতিতে পাস করুন:

- (void)iterateWidgets:(IteratorBlock)iteratorBlock;

আপনি যুক্তি হিসাবে আইডি পাস করছেন কেন? উদাহরণস্বরূপ কোনও এনএসএনবার সহজে পাস করা কি সম্ভব নয়? কেমন লাগবে?
বাস

7
আপনি অবশ্যই একটি দৃ strongly়ভাবে টাইপ করা যুক্তি যেমন NSNumber *বা std::string&বা কোনও কিছু যা আপনি কোনও ফাংশন আর্গুমেন্ট হিসাবে পাস করতে পারেন তা পাস করতে পারেন। এইটা শুধুমাত্র একটা উদাহরণ. (একটি ব্লকের idসাথে প্রতিস্থাপন ব্যতীত সমতুল্য ব্লকের জন্য NSNumberএটি typedefহবে typedef void (^ IteratorWithNumberBlock)(NSNumber *, int);))
জোনাথন গ্রিনস্পান

এটি পদ্ধতির ঘোষণা দেখায়। ব্লকগুলির সাথে একটি সমস্যা হ'ল "অগোছালো" ঘোষণার স্টাইলটি বাস্তব ব্লকের যুক্তি দিয়ে প্রকৃত পদ্ধতি কলটি পরিষ্কার করা এবং সহজ করে না।
uchuugaka

টাইপডেফগুলি কোডটি কেবল লেখার পক্ষে সহজ করে না, তবে ব্লক / ফাংশন পয়েন্টার সিনট্যাক্সটি সবচেয়ে পরিষ্কার নয় বলে পড়তে উল্লেখযোগ্যভাবে সহজ।
pyj

@ জোনাথান গ্রিনস্পান, সুইফট ওয়ার্ল্ড থেকে আগত কিন্তু কিছু পুরানো অবজেক্টিভ-সি কোডটি স্পর্শ করার পরে, আমি কীভাবে বলব যে কোনও ব্লক পালাচ্ছে কিনা? আমি পড়েছি যে ডিফল্টরূপে, ব্লকগুলি অলঙ্কৃত সজ্জিত ব্যতীত পালাচ্ছে 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
}];

৪. স্থানীয় ভেরিয়েবল হিসাবে ব্লক করুন

টেমপ্লেট

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

উদাহরণ

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

৫. টাইপডেফ হিসাবে ব্লক করুন

টেমপ্লেট

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
[স্ব রক্ষা উইথ কমপ্লিটব্লক: ^ (এনএসআর * * অ্যারে, এনএসইরর * ত্রুটি) {// আপনার কোড;]; এই উদাহরণে রিটার্নের ধরণটি বাতিল হয়ে যায় কারণ এটি বাতিল?
অ্যালেক্স

51

এটি সহায়ক হতে পারে:

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

আপনি একটি প্রথম বন্ধনী মিস করছেন
21

এইটি আমার পক্ষে কাজ করেছিল যখন আগেরটি তা করেনি। বিটিডব্লিউ ধন্যবাদ সঙ্গী, এটি ছিল সত্যই সহায়ক!
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

নীচের উদাহরণে с ফাংশনগুলি ব্যবহার করে ব্লকটি পাস করার আরও একটি উপায়। আমি ব্যাকগ্রাউন্ডে এবং মূল কাতারে কিছু করার জন্য ফাংশন তৈরি করেছি।

block.h ফাইল

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

block.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);
}

যখন প্রয়োজন হয় আমদানি করে block.h এর চেয়ে বেশি:

- (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 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 নেবে, এই ইউআরএল থেকে কিছু জেএসএন ডেটা একটি পটভূমির থ্রেডে লোড করবে, তারপরে কলিং ফাংশনে কোনও ফলাফলের এনএসআর্রে * ফিরিয়ে দেবে।

মূলত, আমি সমস্ত ব্যাকগ্রাউন্ড-থ্রেড জটিলতা জেনেরিক পুনঃব্যবহারযোগ্য ফাংশনে লুকিয়ে রাখতে চেয়েছিলাম।

এখানে আমি এই ফাংশনটি কীভাবে বলব:

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লোড হওয়া রেকর্ডগুলির একটি এনএসআরএ * পাস করতে হয় :

+(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.azurewebsites.net/pages/Services/WebServices-Page6.htm

আশা করি এটি আরও কিছু এক্সকোড বিকাশকারীকে সহায়তা করবে! (এই প্রশ্নটি এবং আমার উত্তরটি যদি ভোগ না করে তবে ভুলে যাবেন না!)


1
আইওএস এবং ব্লকগুলির জন্য আমি দেখেছি এটি সেরা কৌশলগুলির মধ্যে একটি seriously ভালোবাসি মানুষ !!!!
পোর্টফোরওয়ার্ডপোডকাস্ট

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 {

}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.