0

기내 API 호출 수를 2로 제한하고 싶습니다. NSOperationQueue을 생성하고 블록을 대기열에 추가 할 수 있지만 각 API 호출에는 완료 블록이 있으므로 초기 호출은 제한적이지만 완료 블록의 실행을 기반으로 큐의 처리를 제한하는 방법을 알지 못합니다.iOS에서 NSBlockOperation을 사용하여 비동기 API 호출을 조절 함

아래 코드에서 아무 때 나 2 회 이상 호출 API를 사용할 수 있습니다.

NSOperationQueue *requestQueue = [[NSOperationQueue alloc] init]; 
service.requestQueue.maxConcurrentOperationCount = 2; 

for (int i = 0; i < 100; i++) 
{ 
    NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{ 

     [self invokeAPI:kAPIName completion:^BOOL(APIResult *result) { 

      // Do stuff 
     } 

     [requestQueue addOperation:operation]; 
    } 
} 

정확한 패턴을 가리키는 포인터가 있으면 좋겠다.

편집 - 마크 - 알렉산더의 답변을 바탕으로

이 클래스는 dataAccessService에서 생성 및 주입됩니다 주어진보기의 메모리 관점에서 안전한 방법이며, 작업을 캡슐화하는이 클래스를 만들었습니다 완성 된 블록은 자체에 대한 참조를 가지고 있으며 완료 블록이 실행되는 보다 앞에이라는 마무리가 필요합니까?

@interface MAGApiOperation : NSOperation 

@property (nonatomic, strong) id<MAGDataAccessServiceProtocol> dataAccessService; 
@property (nonatomic, copy) NSString *apiName; 
@property (nonatomic, copy) BOOL (^onCompletion)(APIResult *); 

+ (instancetype)apiOperationWithName:(NSString *)apiName dataAccessService:(id<MAGDataAccessServiceProtocol>)dataAccessService completion:(BOOL (^)(APIResult *))onCompletion; 

@implementation MAGApiOperation 

@synthesize executing = _isExecuting; 
@synthesize finished = _isFinished; 

#pragma mark - Class methods 

/// Creates a new instance of MAGApiOperation 
+ (instancetype)apiOperationWithName:(NSString *)apiName dataAccessService:(id<MAGDataAccessServiceProtocol>)dataAccessService completion:(BOOL (^)(APIResult *))onCompletion { 

    MAGApiOperation *operation = [[self alloc] init]; 
    operation.apiName = apiName; 
    operation.dataAccessService = dataAccessService; 
    operation.onCompletion = onCompletion; 

    return operation; 
} 

#pragma mark - NSOperation method overrides 

- (void)start { 

    [self willChangeValueForKey:@"isExecuting"]; 
    _isExecuting = YES; 
    [self didChangeValueForKey:@"isExecuting"]; 

    if (!self.isCancelled) 
    { 
     [self invokeApiWithName:self.apiName completion:self.onCompletion]; 
    } 
} 

- (void)finish { 

    [self willChangeValueForKey:@"isExecuting"]; 
    [self willChangeValueForKey:@"isFinished"]; 

    _isExecuting = NO; 
    _isFinished = YES; 

    [self didChangeValueForKey:@"isExecuting"]; 
    [self didChangeValueForKey:@"isFinished"]; 
} 

#pragma mark - Private methods 

/// Invokes the api with the name then executes the completion block 
- (void)invokeApiWithName:(NSString *)apiName completion:(BOOL (^)(VAAInvokeAPIResult *))onCompletion { 

     [self.dataAccessService invokeAPI:kAPIName completion:^BOOL(APIResult *result) { { 

      [self finish]; 

      return onCompletion(result); 
     }]; 
} 
+0

을 (아래 참조 willChange 및 didChange 통화가 정말 중요주의) 자신의 작업을 표시, 그것은 필요가 없습니다 언제든지 2 개 이상의 API 호출을 병렬로 수행 할 수 있습니다. –

+0

NSOperation에는 이미 사용할 수있는 completionBlock이 있습니다. 당신은 당신 자신의 것을 구현할 필요가 없다. 대신 결과를'@ property'에 저장 한 다음 작업을 호출 할 때 myOperation.completionBlock =^{/ * myOperation.results * /}에 액세스 할 수 있습니다. 말이된다? –

답변

2

이렇게하려면 NSOperation을 하위 클래스화해야합니다. https://developer.apple.com/reference/foundation/operation

빠른 노트 :

  • 귀하의 "시작"작업이 invokeAPI 호출 될

    여기 모든 방법 NSOperation을 하위 클래스 설명 전체 설명서입니다. 마무리

  • 이 그런 다음 invokeAPI 완료 블록에, 당신은 당신의 코드에서

[self willChangeValueForKey:@"isExecuting"]; 
[self willChangeValueForKey:@"isFinished"]; 
self.isExecuting = NO; 
self.isFinished = YES; 
[self didChangeValueForKey:@"isExecuting"]; 
[self didChangeValueForKey:@"isFinished"]; 
+0

마크, 감사합니다. NSOperation의 하위 클래스를 포함하도록 질문을 수정했는지, 메모리 누수 가능성 또는 액세스 불량에 대한 의견을 보내 주시면 감사하겠습니다. –