How to Write an Objective-C Completion Block

How to write an Objective-C Completion Block

I always use this when I want to write a block:

http://fuckingblocksyntax.com

EDIT

If you are writing Swift then use this:

http://fuckingswiftblocksyntax.com

If the above links are not opening because of the obscene language, use this one.

http://goshdarnblocksyntax.com/

Custom completion block for my own method

1) Define your own completion block,

typedef void(^myCompletion)(BOOL);

2) Create a method which takes your completion block as a parameter,

-(void) myMethod:(myCompletion) compblock{
//do stuff
compblock(YES);
}

3)This is how you use it,

[self myMethod:^(BOOL finished) {
if(finished){
NSLog(@"success");
}
}];

Sample Image

How to write a completion block in objective-C?

check out http://fuckingblocksyntax.com for syntax.
For personal choice I like to return value and error in the completion block (similar to iOS framework pattern)
As an example;

declaration

- (void)fetchStuff:(void (^)(id value,NSError *error))completion;

calling the function

// async fetch
[object fetchStuff:^(id value, NSError *error) {
// do stuff with value
}];

Objective-C: How to give a completion block to a method that uses a result from the method execution

Yes, what you've shown is the typical way of doing this. Look at Apple's own APIs to see that they do it the same way. For example, -[NSURLSession dataTaskWithURL:completionHandler:], whose declaration is:

- (NSURLSessionDataTask *)dataTaskWithURL:(NSURL *)url 
completionHandler:(void (^)(NSData *data, NSURLResponse *response, NSError *error))completionHandler;

Using Obj-C completion block in Swift

Given that your closure doesn't specify nullability qualifiers (where they almost certainly are optional), one can safely assume that your Objective-C API has not been audited for nullability. Thus, Swift will treat pointers as implicitly unwrapped optionals. Furthermore, nowadays the NSDictionary is mapped to a [NSObject : AnyObject] Swift dictionary.

Thus, it would be:

obj.objcMethod(param) { (success: Bool, result: [NSObject : AnyObject]!, error: NSError!) in
if success {
// do something
}
}

Or, as Kobi points out, you can let the compiler infer the types:

obj.objcMethod(param) { success, result, error in
if success {
// do something
}
}

Note, you don't have to remember this yourself. You can leverage Xcode's code completion as you enter the code. So, type enough to match the method name and when it matches objcMethod, then hit enter:

Sample Image

When you get to MYCompletionBlock, hit enter again, and it will show you the correct signature:

Sample Image


If this Objective-C method was my own class, I would audit it for nullability. So, for example, let's assume the param is optional, the closure is required, and the result and error were optional, you might define it like so:

NS_ASSUME_NONNULL_BEGIN

typedef void (^MYCompletionBlock)(BOOL success, NSDictionary * _Nullable result, NSError * _Nullable error);

@interface MyObject : NSObject

- (void)objcMethod:(NSDictionary * _Nullable)param1 withCompletionHandler:(MYCompletionBlock)completionHandler;

@end

NS_ASSUME_NONNULL_END

And, if that was the case, your Swift code would call it like so:

obj.objcMethod(param) { (success: Bool, result: [NSObject : AnyObject]?, error: NSError?) in
if success {
// do something
}
}

Or, again, just let the compiler infer the types for you (but this time they'd be inferred as optionals that are not implicitly unwrapped):

obj.objcMethod(param) { success, result, error in
if success {
// do something
}
}

Objective C: Is there a way to call a completion block for a method in another method?

You can pass completion blocks around and then call them from your final method which handles all the get requests. I usually make completion blocks that are going to be reused typedefs for brevity. Here's an example of what I mean (I added a second example method that also passes through to the center getRequestWithURLString:onSuccess:onFailure: method):

LLFakeManager.h

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

typedef void (^_Nullable SuccessCompletionBlock)(id responseObject);
typedef void (^_Nullable FailureCompletionBlock)(NSError *error);

@interface LLFakeManager : NSObject
- (void)getUserInfoOnSuccess:(SuccessCompletionBlock)successBlock onFailure:(FailureCompletionBlock)failureBlock;
- (void)getBooksCheckedOutOnSuccess:(SuccessCompletionBlock)successBlock onFailure:(FailureCompletionBlock)failureBlock;
@end

NS_ASSUME_NONNULL_END

LLFakeManager.m

#import "LLFakeManager.h"

@interface LLFakeManager()
- (void)getRequestWithURLString:(NSString *)urlString
onSuccess:(SuccessCompletionBlock)successBlock
onFailure:(FailureCompletionBlock)failureBlock;
@end

@implementation LLFakeManager

- (void)getUserInfoOnSuccess:(SuccessCompletionBlock)successBlock onFailure:(FailureCompletionBlock)failureBlock {
NSString *urlStr = @"FakeUserUrlPath";
[self getRequestWithURLString:urlStr onSuccess:successBlock onFailure:failureBlock];
}

- (void)getBooksCheckedOutOnSuccess:(SuccessCompletionBlock)successBlock onFailure:(FailureCompletionBlock)failureBlock {
NSString *urlString = @"FakeBooksUrlPath";
[self getRequestWithURLString:urlString onSuccess:successBlock onFailure:failureBlock];
}

// central method that will handle all the get requests
- (void)getRequestWithURLString:(NSString *)urlString
onSuccess:(SuccessCompletionBlock)successBlock
onFailure:(FailureCompletionBlock)failureBlock {
// some fake implementation here to do your request, then use the completion block passed in from whatever other method
if (successBlock) {
successBlock(@"responseObjectPassedBackHere");
}
}

@end

And an example of calling it:

LLFakeManager *manager = [[LLFakeManager alloc] init];
[manager getUserInfoOnSuccess:^(id _Nonnull responseObject) {
NSLog(@"Here's my response object = %@", responseObject);
} onFailure:^(NSError * _Nonnull error) {
// no implementation but same idea
}];

Would produce this log:

Here's my response object = responseObjectPassedBackHere

This site: http://goshdarnblocksyntax.com is a handy list of block syntax which may also be helpful for you.

completion block with parameters

If you want to pass a NSString* to the method:

-(void)testingFunction:(void(^)(NSMutableArray* result))handler andString:(NSString*) yourString;

Or if you want to pass a NSString* to the completion block:

-(void)testingFunction:(void(^)(NSMutableArray* result, NSString* yourString))handler;

Edit:

You can call the method like this:

NSString* yourString = @"Some Text";
testingFunction:^(NSMutableArray* result) {
//Do whatever you want here
} andString:yourString;

Go read this: http://www.tutorialspoint.com/objective_c/objective_c_functions.htm

EDIT2:

As trojanfoe said, if your string is supposed to be an url you should use NSURL instead of NSString

How to create c++ equivalent of Objective-C completion block as param

In C++ you would usually use std::function for this, which is a class template that can hold any kind of callable function/object including a lambda (caveat: as long as it's copyable):

void mySetter(Thing thing, std::function<void(bool)> completion) {
// ...
completion(true);
}

mySetter(thing, [](bool success) {
// ...
});

Note that in Objective-C++ (.mm files) you can generally mix C++ and Obj-C types freely, so you could for example pass a block as a parameter to a C++ function — you just need to be aware of the proper block pointer syntax.

void mySetter(Thing thing, void (^completion)(BOOL)) {
// ...
completion(YES);
}

mySetter(thing, ^(BOOL success) {
// ...
});

objective c completion handler

RequestManager.h

@interface RequestManager : NSObject
//Create a block property
typedef void(^postRequestBlock)(BOOL status);

-(void) getContentInBackgroundWithMemberId: (int) memberId completed:(postRequestBlock)completed;
@end

RequestManager.m

-(void) getContentInBackgroundWithMemberId: (int) memberId completed:(postRequestBlock)completed{
NSDictionary * params = [NSDictionary dictionary];
params = @ {
@ "member_id": [NSNumber numberWithInt: memberId]
};
[self postRequestWithParams: params completed:^(BOOL status){
completed(status);
}];
}

//Add completion block.
-(void) postRequestWithParams: (NSDictionary * ) params completed:(postRequestBlock)completed{
[NSURLConnection sendAsynchronousRequest: request queue: [NSOperationQueue mainQueue] completionHandler: ^ (NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
if (!connectionError) {
NSDictionary * serverData = [NSJSONSerialization JSONObjectWithData: data options: 0 error: nil];
NSArray * result = [NSArray array];
result = [serverData objectForKey: @ "result"];
completed(YES);
} else {
completed(NO);
}

}];
}

There are already tons of Q&A's for blocks. Here's one that might help further explain
How to write an Objective-C Completion Block



Related Topics



Leave a reply



Submit