目标C:有没有一种方法可以在另一个方法中调用一个方法的完成块?

时间:2018-11-27 18:26:54

标签: ios objective-c objective-c-blocks completionhandler

我有多个GET API请求方法,它们在完成时调用完成块。这是一个例子。

- (void)getUserInfo
    onSuccess:(void (^)(id))successBlock
    onFailure:(void (^)(NSError *))failureBlock {

    NSString *urlStr = [NSString stringWithFormat:@"%@/user/", baseUrl];

    [manager GET:urlStr parameters:nil progress:nil
          success:^(NSURLSessionTask *task, id responseObject) {
              successBlock(responseObject);
          }
          failure:^(NSURLSessionTask *operation, NSError *error) {
              failureBlock(error);
          }];
}

但是,我注意到我正在以其他方法重复管理器GET请求代码。我想创建另一个方法来处理所有请求并删除重复代码。 URL似乎是唯一更改的东西。但是,存在一个缺陷。我需要调用successBlock以使方法知道请求已完成。

也许我需要走另一条路,做些不同的事情。

2 个答案:

答案 0 :(得分:2)

您可以传递完成块,然后从处理所有get请求的final方法中调用它们。为了简化起见,我通常会编写将被重用的typedef的完成块。这是我的意思的示例(我添加了第二个示例方法,该方法也传递给中心BookcaseController方法):

LLFakeManager.h

getRequestWithURLString:onSuccess:onFailure:

LLFakeManager.m

#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

以及调用它的示例:

#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

将产生此日志:

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
}];

此站点:http://goshdarnblocksyntax.com是块语法的便捷列表,对您也可能会有所帮助。

答案 1 :(得分:0)

如果块具有相同的签名,则可以沿着方法链传递它们。您的GET块带有不必要的第一个参数。 NSURLSessionTask *(如果要完全返回)应该同步返回。将其移出块签名将使您可以标准化块。

用代码说起来更容易...

// changed this method name so it would compile

- (void)getUserInfoOnSuccess:(void (^)(id))successBlock
                   onFailure:(void (^)(NSError *))failureBlock {

    NSString *urlStr = [NSString stringWithFormat:@"%@/user/", baseUrl];

   // two things: get the task as a return value (if you need it)
   // pass the blocks directly, without nesting them in new blocks
    NSURLSessionTask *task = [manager GET: urlStr
                               parameters: nil
                                 progress: nil
                                  success: successBlock
                                  failure: failureBlock];
    // do something with the task
}

要执行此操作,请更改GET方法的返回类型和块签名...

- (NSURLSessionTask *)GET:(NSString *)url parameters:(id)params progress:(id)progress success:(void (^)(id))successBlock failure:(void (^)(NSError *))failureBlock {
    // return the session task created here
    return task
}