programing

NSBlockOperation 및 큐가있는 NSURLSession

shortcode 2021. 1. 19. 07:34
반응형

NSBlockOperation 및 큐가있는 NSURLSession


현재 NSURLConnection대부분의 네트워킹에 사용되는 앱이 있습니다 . 나는 NSURLSession애플이 그것이 갈 길이라고 말했기 때문에 이사 하고 싶다.

내 앱 NSURLConnection+ (NSData *)sendSynchronousRequest:(NSURLRequest *)request returningResponse:(NSURLResponse **)response error:(NSError **)error클래스 메서드를 통해 동기 버전을 사용합니다 . 나는 NSBlockOperation실행 중에 이것을 수행 NSOperationQueue하므로 불필요하게 메인 대기열을 차단하지 않습니다. 이런 방식으로 작업을 수행 할 때의 가장 큰 장점은 작업을 서로 종속시킬 수 있다는 것입니다. 예를 들어 데이터를 요청하는 작업이 로그인 작업 완료에 따라 달라 지도록 할 수 있습니다.

내에서 동기 작업에 대한 지원을 보지 못했습니다 NSURLSession. 내가 찾을 수있는 것은 동기식으로 사용한다고 생각하고 스레드를 차단하는 끔찍한 사람이라는 것을 유도하는 기사뿐입니다. 좋아. 그러나 나는 NSURLSessionTasks를 서로 의존 하게 만들 방법이 없다고 생각합니다 . 그렇게하는 방법이 있습니까?

아니면 다른 방식으로 그런 일을 어떻게 할 것인지에 대한 설명이 있습니까?


동기식 네트워크 요청에 대한 가장 가혹한 비판은 주 대기열에서 수행하는 사람들을 위해 예약되어 있습니다 (기본 대기열을 절대로 차단해서는 안된다는 것을 알고 있기 때문). 그러나 동기 요청의 가장 심각한 문제를 해결하는 자체 백그라운드 큐에서이를 수행하고 있습니다. 그러나 비동기 기술이 제공하는 멋진 기능 (예 : 필요한 경우 요청 취소)이 손실됩니다.

NSURLSessionDataTask아래에서 귀하의 질문 ( 동 기적으로 작동 하도록 만드는 방법)에 답할 것이지만, 비동기 패턴과 싸우기보다는 포용하는 것이 좋습니다. 비동기 패턴을 사용하도록 코드를 리팩토링하는 것이 좋습니다. 특히, 한 작업이 다른 작업에 종속 된 경우 이전 작업의 완료 처리기에 종속 작업의 시작을 입력하면됩니다.

해당 변환에 문제가있는 경우 다른 Stack Overflow 질문을 게시하여 시도한 내용을 보여 주시면 도움을 드릴 수 있습니다.


비동기 작업을 동기식으로 만들려는 경우 일반적인 패턴은 디스패치 세마포어를 사용하여 비동기 프로세스를 시작한 스레드가 계속하기 전에 비동기 작업의 완료 블록에서 신호를 기다릴 수 있도록하는 것입니다. 기본 대기열에서이 작업을 수행하지 마십시오. 그러나 일부 백그라운드 대기열에서이 작업을 수행하는 경우 유용한 패턴이 될 수 있습니다.

다음을 사용하여 세마포어를 만들 수 있습니다.

dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

그런 다음 비동기 프로세스의 완료 블록이 다음과 같이 세마포어에 신호를 보내도록 할 수 있습니다.

dispatch_semaphore_signal(semaphore);

그런 다음 완료 블록 외부에있는 코드가 해당 신호를 기다리도록 할 수 있습니다 (하지만 여전히 기본 큐가 아닌 백그라운드 큐에 있음).

dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

그래서,와 NSURLSessionDataTask, 모두 함께, 즉처럼 보일 수도 퍼팅 :

[queue addOperationWithBlock:^{

    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

    NSURLSession *session = [NSURLSession sharedSession]; // or create your own session with your own NSURLSessionConfiguration
    NSURLSessionTask *task = [session dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        if (data) {
            // do whatever you want with the data here
        } else {
            NSLog(@"error = %@", error);
        }

        dispatch_semaphore_signal(semaphore);
    }];
    [task resume];

    // but have the thread wait until the task is done

    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

    // now carry on with other stuff contingent upon what you did above
]);

으로 NSURLConnection(현재 사용되지 않음), 당신은 배경 큐의 요청을 시작하는 몇 가지 농구를 통해 이동해야하지만, NSURLSession정상적으로 핸들을.


즉, 이와 같은 블록 작업을 사용하면 작업이 취소 이벤트에 응답하지 않습니다 (적어도 실행중인 동안). 그래서 저는 일반적으로이 세마포어 기술을 블록 작업으로 피하고 데이터 작업을 비동기 NSOperation하위 클래스로 래핑합니다 . 그런 다음 작업의 이점을 누리지 만 취소 가능하게 만들 수도 있습니다. 더 많은 작업이지만 훨씬 더 나은 패턴입니다.

예를 들면 :

//
//  DataTaskOperation.h
//
//  Created by Robert Ryan on 12/12/15.
//  Copyright © 2015 Robert Ryan. All rights reserved.
//

@import Foundation;
#import "AsynchronousOperation.h"

NS_ASSUME_NONNULL_BEGIN

@interface DataTaskOperation : AsynchronousOperation

/// Creates a operation that retrieves the contents of a URL based on the specified URL request object, and calls a handler upon completion.
///
/// @param  request                    A NSURLRequest object that provides the URL, cache policy, request type, body data or body stream, and so on.
/// @param  dataTaskCompletionHandler  The completion handler to call when the load request is complete. This handler is executed on the delegate queue. This completion handler takes the following parameters:
///
/// @returns                           The new session data operation.

- (instancetype)initWithRequest:(NSURLRequest *)request dataTaskCompletionHandler:(void (^)(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error))dataTaskCompletionHandler;

/// Creates a operation that retrieves the contents of a URL based on the specified URL request object, and calls a handler upon completion.
///
/// @param  url                        A NSURL object that provides the URL, cache policy, request type, body data or body stream, and so on.
/// @param  dataTaskCompletionHandler  The completion handler to call when the load request is complete. This handler is executed on the delegate queue. This completion handler takes the following parameters:
///
/// @returns                           The new session data operation.

- (instancetype)initWithURL:(NSURL *)url dataTaskCompletionHandler:(void (^)(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error))dataTaskCompletionHandler;

@end

NS_ASSUME_NONNULL_END

//
//  DataTaskOperation.m
//
//  Created by Robert Ryan on 12/12/15.
//  Copyright © 2015 Robert Ryan. All rights reserved.
//

#import "DataTaskOperation.h"

@interface DataTaskOperation ()

@property (nonatomic, strong) NSURLRequest *request;
@property (nonatomic, weak) NSURLSessionTask *task;
@property (nonatomic, copy) void (^dataTaskCompletionHandler)(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error);

@end

@implementation DataTaskOperation

- (instancetype)initWithRequest:(NSURLRequest *)request dataTaskCompletionHandler:(void (^)(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error))dataTaskCompletionHandler {
    self = [super init];
    if (self) {
        self.request = request;
        self.dataTaskCompletionHandler = dataTaskCompletionHandler;
    }
    return self;
}

- (instancetype)initWithURL:(NSURL *)url dataTaskCompletionHandler:(void (^)(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error))dataTaskCompletionHandler {
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    return [self initWithRequest:request dataTaskCompletionHandler:dataTaskCompletionHandler];
}

- (void)main {
    NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:self.request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        self.dataTaskCompletionHandler(data, response, error);
        [self completeOperation];
    }];

    [task resume];
    self.task = task;
}

- (void)completeOperation {
    self.dataTaskCompletionHandler = nil;
    [super completeOperation];
}

- (void)cancel {
    [self.task cancel];
    [super cancel];
}

@end

어디:

//
//  AsynchronousOperation.h
//

@import Foundation;

@interface AsynchronousOperation : NSOperation

/// Complete the asynchronous operation.
///
/// This also triggers the necessary KVO to support asynchronous operations.

- (void)completeOperation;

@end

//
//  AsynchronousOperation.m
//

#import "AsynchronousOperation.h"

@interface AsynchronousOperation ()

@property (nonatomic, getter = isFinished, readwrite)  BOOL finished;
@property (nonatomic, getter = isExecuting, readwrite) BOOL executing;

@end

@implementation AsynchronousOperation

@synthesize finished  = _finished;
@synthesize executing = _executing;

- (instancetype)init {
    self = [super init];
    if (self) {
        _finished  = NO;
        _executing = NO;
    }
    return self;
}

- (void)start {
    if ([self isCancelled]) {
        self.finished = YES;
        return;
    }

    self.executing = YES;

    [self main];
}

- (void)completeOperation {
    self.executing = NO;
    self.finished  = YES;
}

#pragma mark - NSOperation methods

- (BOOL)isAsynchronous {
    return YES;
}

- (BOOL)isExecuting {
    @synchronized(self) {
        return _executing;
    }
}

- (BOOL)isFinished {
    @synchronized(self) {
        return _finished;
    }
}

- (void)setExecuting:(BOOL)executing {
    @synchronized(self) {
        if (_executing != executing) {
            [self willChangeValueForKey:@"isExecuting"];
            _executing = executing;
            [self didChangeValueForKey:@"isExecuting"];
        }
    }
}

- (void)setFinished:(BOOL)finished {
    @synchronized(self) {
        if (_finished != finished) {
            [self willChangeValueForKey:@"isFinished"];
            _finished = finished;
            [self didChangeValueForKey:@"isFinished"];
        }
    }
}

@end

@Rob의 다음 문서 참고 사항을 고려하여 답변을 솔루션으로 게시하는 것이 좋습니다 NSURLSession.dataTaskWithURL(_:completionHandler:).

This method is intended as an alternative to the sendAsynchronousRequest:queue:completionHandler: method of NSURLConnection, with the added ability to support custom authentication and cancellation.

ReferenceURL : https://stackoverflow.com/questions/21198404/nsurlsession-with-nsblockoperation-and-queues

반응형