AFNetworking 소스 읽기

5374 단어
1. AFNetworking의 간단한 사용
 , 


// 
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
// 
manager.requestSerializer.timeoutInterval = 10;
// ( Json)
manager.responseSerializer = [AFJSONResponseSerializer serializer];
// GET 
[manager GET:urlString
  parameters:nil
     success:^(AFHTTPRequestOperation * _Nonnull operation, id  _Nonnull responseObject) {
         NSLog(@" ");
     }
     failure:^(AFHTTPRequestOperation * _Nullable operation, NSError * _Nonnull error) {
         NSLog(@" ");
     }];

2. 대체적인 프레임워크 이 소스 오픈 프레임워크는 NSURLconnection과 NSURLSession을 바탕으로 개발된 것이다.그중에는 두 가지 관리 클래스가 있는데 그것이 바로 AFHTTPRequest Operation Manager와 AFHTTPSession Manager이다.또 다른 주요 클래스는 AFURLconnection Operation이다. 이것은 사용자 정의 NSOperation으로 네트워크 요청 작업, 리셋, 메인 라인으로 전송하는 데 사용된다.3. AFURLconnection Operation은 먼저 라인을 논의한다.우리가 네트워크 요청을 하는 것은 다음과 같은 몇 가지가 있다. 1) 메인 스레드 동기화 요청: 이것은 메인 스레드를 막아서 일반적으로 아무도 사용하지 않는다.2) 메인 스레드 호출 비동기 요청: NSURLconnection은 메인 스레드 Runloop에서 리셋 이벤트를 터치합니다. 메인 스레드의 모드(㎡는 상태로 이해할 수 있죠)는 두 가지 기본값이 있습니다. NSDefaultRunLoopMode입니다. 평소의 상태와 UITrackingRunLoopMode를 기록하고 ScrollView가 미끄러질 때의 상태를 추적합니다.NSURLconnection의 리셋을 언제든지 받아들이려면 NSRunLoopCommonModes 상태로 설정해야 합니다. 계속 미끄러지는 상태에서는 리셋을 처리할 수 없기 때문입니다.그러나 이렇게 하면 애니메이션 효과에도 영향을 줄 수 있다.3) 서브스레드 호출 동기화 요청: 이때 요청을 진행하면 주 스레드의 상태에 영향을 주지 않지만 하나의 네트워크 요청을 처리하려면 하나의 스레드를 차지해야 한다. 이 스레드는 리셋을 진행할 때까지 막힌다. 요청이 비교적 많으면 여러 스레드를 차지하고 자원 낭비를 초래한다.4) 서브루틴 호출 비동기 요청: 이런 상황에서 상주 서브루틴을 설정하여 네트워크 요청의 리셋을 할 수 있다. 이렇게 여러 개의 네트워크 요청이 요청될 때 리셋은 모두 통일된 서브루틴에 있고 이후에 메인 루틴으로 전달될 때 메인 루틴에 영향을 주지 않는다.위 방식3)에 비해 적지 않은 우세가 있다.이 틀은 방식 4)을 채택한다.소스:
+ (void)networkRequestThreadEntryPoint:(id)__unused object {
    @autoreleasepool {
        [[NSThread currentThread] setName:@"AFNetworking"];

        NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
        [runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
        [runLoop run];
    }
}

//   
+ (NSThread *)networkRequestThread {
    
    static NSThread *_networkRequestThread = nil;
    static dispatch_once_t oncePredicate;
    
    dispatch_once(&oncePredicate, ^{
        _networkRequestThread = [[NSThread alloc] initWithTarget:self selector:@selector(networkRequestThreadEntryPoint:) object:nil];
        [_networkRequestThread start];
    });

    return _networkRequestThread;
}

operation이queue에 입력되면 operation 방법이 자동으로 호출됩니다.
- (void)start;

이 프레임워크의 이 방법은 위에서 만든 라인에connection 요청 네트워크 데이터를 만들고 이 라인에서 리셋합니다.또한 받은 데이터를 메모리에 쓰기 위해 outputStream을 만들었습니다.
- (NSOutputStream *)outputStream {
    if (!_outputStream) {
        self.outputStream = [NSOutputStream outputStreamToMemory];
    }

    return _outputStream;
}

보충:operation에는 하나의 상태기가 포함되어 있으며 현재operation의 상태를 설명하고 KVO로 관리합니다.상태는
isReady → isExecuting → isFinished

사용자 정의operation은 상태기를 추가해야 합니다.queue에 가입하면 실행할 수 없습니다.queue의 의존과 같이 A는 B에 의존한다. B의 상태기 상태가 isFinished일 때만 A를 실행할 수 있다.이 프레임의 원본 코드는 다음과 같습니다.
typedef NS_ENUM(NSInteger, AFOperationState) {
    AFOperationPausedState      = -1,
    AFOperationReadyState       = 1,
    AFOperationExecutingState   = 2,
    AFOperationFinishedState    = 3,
};
- (void)setState:(AFOperationState)state {
    if (!AFStateTransitionIsValid(self.state, state, [self isCancelled])) {
        return;
    }

    [self.lock lock];
    
    NSString *oldStateKey = AFKeyPathFromOperationState(self.state);
    NSString *newStateKey = AFKeyPathFromOperationState(state);

    [self willChangeValueForKey:newStateKey];
    [self willChangeValueForKey:oldStateKey];
    _state = state;
    [self didChangeValueForKey:oldStateKey];
    [self didChangeValueForKey:newStateKey];
    [self.lock unlock];
}


서버에서 데이터를 받으면 connection의 프록시 방법이 호출됩니다.
- (void)connection:(NSURLConnection __unused *)connection
    didReceiveData:(NSData *)data;


받은 데이터를 메모리에 쓰고 받은 후에 호출합니다
- (void)connectionDidFinishLoading:(NSURLConnection __unused *)connection;

메모리에 있는 데이터를 꺼내서connection을 닫습니다. 이operation상태기는 isFinished에 있고 이operation의completionBlock를 호출하여 받은 데이터를 조작합니다.


이 프레임워크는 Block 작업에 대해 다음과 같은 유형을 자주 볼 수 있습니다.
 __weak __typeof(self)weakSelf = self;
        [super setCompletionBlock:^ {
            
            __strong __typeof(weakSelf)strongSelf = weakSelf;

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu"
            dispatch_group_t group = strongSelf.completionGroup ?: url_request_operation_completion_group();
            dispatch_queue_t queue = strongSelf.completionQueue ?: dispatch_get_main_queue();
#pragma clang diagnostic pop

            dispatch_group_async(group, queue, ^{
                block();
            });

            dispatch_group_notify(group, url_request_operation_completion_queue(), ^{
                [strongSelf setCompletionBlock:nil];
            });
        }];
    }


Block과self 사이의 순환 인용을 방지하기 위해 weakself를 만듭니다.그러나 그 다음에 strongself를 만들어서 self가 가리키는 대상을 미리 방출하는 것을 방지합니다. (Block의 실행은 비동기적입니다. Block이 실행되지 않았을 수도 있습니다. Operation은 dealloc이고 Block에서 다시 사용되었습니다. 저자는 순환 인용을 무시했습니다. 마지막으로 이 Block을 nil로 설정했기 때문에 순환 인용이 되지 않습니다.)또strongSelf 이후에 자동으로 방출되어 순환 인용을 일으키지 않기 때문이다.

좋은 웹페이지 즐겨찾기