iOS 개발 - AFNetWorking 네트워크 연결 상세 설명

18364 단어 iOS 개발
AFHTTPSession Manager 는 AFURLSession Manager 에 계승 되 어 더욱 편리 한 HTTP 요청 방법 을 제공 합 니 다. GET, POST, PUT, PATCH, DELETE 등 다섯 가지 방식 을 포함 하고 AF 는 우리 가 AFHTTPSession Manager 에서 다시 한 번 포장 하여 우리 자신의 업무 수 요 를 만족 시 키 도록 격려 합 니 다.
처음에 AF 는 변수 baseURL 까지 알려 주 었 습 니 다. 이 변 수 는 더 봉인 할 때 baseURL 을 자신의 HTTP 요청 원본 주소 로 쓸 수 있 습 니 다. 예 를 들 어
+ (NSURL *)baseURL {
    return [NSURL URLWithString:kBaseURLString];
}

baseURL 을 연결 할 때 도 요청 한 URL 에 문제 가 발생 하지 않도록 몇 가지 주의해 야 합 니 다.
    NSURL *baseURL = [NSURL URLWithString:@"http://example.com/v1/"];
    [NSURL URLWithString:@"foo" relativeToURL:baseURL];                  // http://example.com/v1/foo
    [NSURL URLWithString:@"foo?bar=baz" relativeToURL:baseURL];          // http://example.com/v1/foo?bar=baz
    [NSURL URLWithString:@"/foo" relativeToURL:baseURL];                 // http://example.com/foo
    [NSURL URLWithString:@"foo/" relativeToURL:baseURL];                 // http://example.com/v1/foo
    [NSURL URLWithString:@"/foo/" relativeToURL:baseURL];                // http://example.com/foo/
    [NSURL URLWithString:@"http://example2.com/" relativeToURL:baseURL]; // http://example2.com/

초기 화 하 는 방법 에서 우 리 는 이 방법 을 보 았 다.
- (instancetype)initWithBaseURL:(nullable NSURL *)url
           sessionConfiguration:(nullable NSURLSessionConfiguration *)configuration NS_DESIGNATED_INITIALIZER;

NS_DESIGNATED_인 니 티 알 리 제 르. 이게 무슨 뜻 이 죠?이것 은 이러한 종류의 초기 화 방법 이 여러 가지 가 있 음 을 나타 내 는 것 입 니 다. 이 표 시 를 추가 한 후에 시스템 의 init 방법 에서 반드시 이 방법 을 사용 해 야 합 니 다.
- (nullable NSURLSessionDataTask *)POST:(NSString *)URLString
                    parameters:(nullable id)parameters
                       success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
                       failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure DEPRECATED_ATTRIBUTE;

DEPRECATED_ATTRIBUTE 는 여러분 이 많이 보 셨 을 거 라 고 믿 습 니 다. 즉, 이 API 는 개발 자 에 게 다시 사용 하 라 고 건의 하지 않 고 다시 사용 할 때 컴 파일 경고 가 나타 납 니 다.
아래 POST, GET, PUT, PATCH, DELETE 방법 전 삼 은 기본적으로 대동소이 하 다.
URLString 은 요청 한 URL 을 표시 합 니 다. parameters 는 클 라 이언 트 가 요청 한 내용 을 표시 하 는 메모리 입 니 다. progress 는 요청 의 진 도 를 표시 합 니 다. constructing Body With Block 에는 HTTP 요청 체 를 연결 하 는 formData 만 있 습 니 다. success 는 요청 이 성공 한 후의 block 리 셋 을 표시 합 니 다. failure 표 는 요청 이 실패 한 block 리 셋 을 표시 합 니 다.
그렇다면 이 몇 가지 요 구 는 어떤 차이 가 있 습 니까?1. POST 요청 은 서버 에 데 이 터 를 보 내 는 것 으로 자원 정 보 를 업데이트 하 는 데 사 용 됩 니 다. 데이터 의 종류 등 자원 을 변경 할 수 있 습 니 다. 2. GET 요청 은 서버 에 데 이 터 를 요청 하 는 것 으로 자원 정 보 를 얻 거나 조회 하 는 데 사 용 됩 니 다. 3. PUT 요청 과 POST 요청 은 모두 데 이 터 를 보 내 는 것 과 비슷 하지만 PUT 요청 은 데이터 의 종류 등 자원 을 변경 할 수 없습니다. 내용 만 수정 할 수 있 습 니 다. 4.DELETE 요청 은 어떤 자원 을 삭제 하 는 데 사용 되 는 5, PATCH 요청 은 PUT 요청 과 마찬가지 로 데이터 업데이트 에 도 사 용 됩 니 다. 이것 은 HTTP verb 가 업데이트 에 추천 하 는 것 입 니 다.
실제 개발 과정 에서 우 리 는 POST 와 GET 요청 을 가장 많이 사용 했다.
실현 을 요청 하 는 부분 에 서 는 모두 자신의 방법 을 호출 하 였 다.
- (NSURLSessionDataTask *)dataTaskWithHTTPMethod:(NSString *)method
                                       URLString:(NSString *)URLString
                                      parameters:(id)parameters
                                  uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgress
                                downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgress
                                         success:(void (^)(NSURLSessionDataTask *, id))success
                                         failure:(void (^)(NSURLSessionDataTask *, NSError *))failure;

전 삼 의 내용 은 기본적으로 이전 방법 과 같 습 니 다. method 는 요청 하 는 유형 을 말 합 니 다.
NSError *serializationError = nil;
    NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:&serializationError];
    if (serializationError) {
        if (failure) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu"
            dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
                failure(nil, serializationError);
            });
#pragma clang diagnostic pop
        }

        return nil;
    }

    __block NSURLSessionDataTask *dataTask = nil;
    dataTask = [self dataTaskWithRequest:request
                          uploadProgress:uploadProgress
                        downloadProgress:downloadProgress
                       completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {
        if (error) {
            if (failure) {
                failure(dataTask, error);
            }
        } else {
            if (success) {
                success(dataTask, responseObject);
            }
        }
    }];

    return dataTask;

내부 구현 은 들 어 오 는 URLString 에 따라 request 대상 을 만 든 다음 부모 클래스 의 dataTask With Request 방법 으로 dataTask 작업 을 생 성 하 는 것 입 니 다. 주 는 이렇게 간단 합 니 다.
AFNetworkReachability Manager 는 네트워크 상 태 를 모니터링 하 는 클래스 로 상태 값 은 다음 과 같은 네 가지 가 있 습 니 다.
typedef NS_ENUM(NSInteger, AFNetworkReachabilityStatus) {
    AFNetworkReachabilityStatusUnknown          = -1,//  
    AFNetworkReachabilityStatusNotReachable     = 0,//   
    AFNetworkReachabilityStatusReachableViaWWAN = 1,//       
    AFNetworkReachabilityStatusReachableViaWiFi = 2,//WiFi  
};

도 메 인 이름 이나 socket 주 소 를 통 해 대상 을 예화 할 수도 있 고, SCNetwork Reachability Ref 대상 을 만들어 대상 을 초기 화 할 수도 있 습 니 다.
+ (instancetype)managerForDomain:(NSString *)domain;
+ (instancetype)managerForAddress:(const void *)address;
- (instancetype)initWithReachability:(SCNetworkReachabilityRef)reachability NS_DESIGNATED_INITIALIZER;

그 다음 에 startMonitoring 과 stopMonitoring 을 호출 하여 모니터링 을 시작 하고 끝 냅 니 다. 중간 네트워크 상태 가 변화 하 는 과정 에서 setReachability Status Change Block 을 통 해 네트워크 상 태 를 얻 을 수 있 고 등록 알림 형식 으로 네트워크 상 태 를 받 을 수 있 습 니 다.
- (void)startMonitoring {
    [self stopMonitoring];

    if (!self.networkReachability) {
        return;
    }

    __weak __typeof(self)weakSelf = self;
    AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) {
        __strong __typeof(weakSelf)strongSelf = weakSelf;

        strongSelf.networkReachabilityStatus = status;
        if (strongSelf.networkReachabilityStatusBlock) {
            strongSelf.networkReachabilityStatusBlock(status);
        }

    };

    SCNetworkReachabilityContext context = {0, (__bridge void *)callback, AFNetworkReachabilityRetainCallback, AFNetworkReachabilityReleaseCallback, NULL};
    SCNetworkReachabilitySetCallback(self.networkReachability, AFNetworkReachabilityCallback, &context);
    SCNetworkReachabilityScheduleWithRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes);

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0),^{
        SCNetworkReachabilityFlags flags;
        if (SCNetworkReachabilityGetFlags(self.networkReachability, &flags)) {
            AFPostReachabilityStatusChange(flags, callback);
        }
    });
}

네트워크 상 태 를 모니터링 할 때 먼저 자신의 네트워크 상태의 block 리 셋 을 설정 한 다음 에 SCNetworkReachability Context 구조 체 를 만 듭 니 다. 첫 번 째 매개 변 수 는 버 전 번호 이 고 값 은 0 이 며 두 번 째 매개 변 수 는 info 는 데이터 block 리 셋 을 가리 키 는 c 지침 입 니 다. 세 번 째 매개 변 수 는 retain 을 통 해 데 이 터 를 한 번 더 보존 합 니 다.이 값 은 null 일 수 있 습 니 다. 네 번 째 매개 변수 release 는 리 셋 을 통 해 제거 되 고 다섯 번 째 매개 변수 description 은 데 이 터 를 제공 하 는 설명 입 니 다.그 다음 에 리 셋 을 설정 하여 runloop 에 추가 하여 이 를 감 측 하고 배경 스 레 드 에서 변 화 를 발견 할 때 네트워크 상태 변 화 를 보 냅 니 다.
AFSecurity Policy 는 보안 정책 류 로 세 가지 SSL Pinning 모드 가 있 습 니 다.
typedef NS_ENUM(NSUInteger, AFSSLPinningMode) {
    AFSSLPinningModeNone,//      
    AFSSLPinningModePublicKey,//  
    AFSSLPinningModeCertificate,//  
};
@property (nonatomic, strong, nullable) NSSet  *pinnedCertificates;

이것 은 인증서 집합 입 니 다. 범 형 에 서 는 집합 이 NSData 형식 임 을 표시 합 니 다. 이것 은 인증서 데 이 터 를 저장 하 는 집합 임 을 나타 냅 니 다. 이 인증 서 는 SSL Pinning 모드 에 따라 서버 와 검 사 를 합 니 다. 기본적으로 인증서 가 없습니다. certificates InBundle 을 호출 해 야 합 니 다. 방법 은 bundle 에 있 는 인증서 파일 을 data 형식의 집합 으로 변환 합 니 다.
+ (instancetype)defaultPolicy;
+ (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode;
+ (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode withPinnedCertificates:(NSSet  *)pinnedCertificates;

세 가지 실례 화 방법 이 있 습 니 다. 하 나 는 기본 정책 입 니 다. AFSSLPinning ModeNone 입 니 다. 두 번 째 는 보안 정책 을 사용자 정의 한 다음 에 현재 종류의 bundle 을 가 져 와 cer 파일 생 성 집합 을 읽 고 세 번 째 는 인증서 집합 이 필요 합 니 다.
AFURLRequestSerialization 은 URL 요청 을 처리 하 는 데 사 용 됩 니 다.
URL 안의 특수 문 자 를 백분율 로 바 꿉 니 다:
FOUNDATION_EXPORT NSString * AFPercentEscapedStringFromString(NSString *string);

사전 의 key / value 값 을% @ =% @ 로 조립 하고 & 로 구분 하 는 형식:
FOUNDATION_EXPORT NSString * AFQueryStringFromParameters(NSDictionary *parameters);

AFHTTPRequestSerializer 에 헤더 정 보 를 설정 하 는 방법 이 있 습 니 다.
- (void)setValue:(nullable NSString *)value
forHTTPHeaderField:(NSString *)field;

이 value 가 비어 있 을 때 삭제 처리 로 사 용 됩 니 다. 존재 하 는 요청 헤 더 를 삭제 합 니 다. 비어 있 지 않 을 때 새로운 요청 헤 더 를 추가 하거나 존재 하 는 요청 헤 더 를 설정 합 니 다.
- (void)setAuthorizationHeaderFieldWithUsername:(NSString *)username
                                       password:(NSString *)password;

사용자 이름, 비밀 번 호 를 정보 로 요청 헤더 로 설정 합 니 다. 그 안에 사용자 이름 비밀 번 호 를 data 로 맞 춘 다음 base 64 인 코딩 형식 으로 문자열 로 바 꾼 다음 요청 헤더 의 내용 으로 설정 합 니 다.
요청 을 만 드 는 방법 은 세 가지 가 있 습 니 다.
- (NSMutableURLRequest *)requestWithMethod:(NSString *)method
                                 URLString:(NSString *)URLString
                                parameters:(nullable id)parameters
                                     error:(NSError * _Nullable __autoreleasing *)error;
- (NSMutableURLRequest *)multipartFormRequestWithMethod:(NSString *)method
                                              URLString:(NSString *)URLString
                                             parameters:(nullable NSDictionary  *)parameters
                              constructingBodyWithBlock:(nullable void (^)(id  formData))block
                                                  error:(NSError * _Nullable __autoreleasing *)error;
- (NSMutableURLRequest *)requestWithMultipartFormRequest:(NSURLRequest *)request
                             writingStreamContentsToFile:(NSURL *)fileURL
                                       completionHandler:(nullable void (^)(NSError * _Nullable error))handler;

method 는 GET, POST 등 요청 하 는 방법 을 말 합 니 다. URLString 은 요청 URL 을 만 드 는 문자열 입 니 다. parameters 는 GET 가 요청 한 조회 필드 나 요청 한 HTTP 체 입 니 다. request 는 HTTP Body Stream 의 인 스 턴 스 변수 request 이 고 fileURL 은 파일 URL 입 니 다.
- (BOOL)appendPartWithFileURL:(NSURL *)fileURL
                         name:(NSString *)name
                        error:(NSError * _Nullable __autoreleasing *)error;
- (BOOL)appendPartWithFileURL:(NSURL *)fileURL
                         name:(NSString *)name
                     fileName:(NSString *)fileName
                     mimeType:(NSString *)mimeType
                        error:(NSError * _Nullable __autoreleasing *)error;

파일 데이터 에 따라 HTTP 헤드 를 연결 합 니 다. fileURL 은 파일 의 URL 입 니 다. name 은 데이터 의 이름 을 말 합 니 다. fileName 은 파일 의 이름 입 니 다. fileURL 에 따라 마지막 부분의 파일 이름 을 얻 을 수 있 습 니 다. mimeType 은 파일 데이터 의 mime 형식 입 니 다. 파일 의 접두사 에 따라 AFContentType ForPathExtension 방법 을 사용 하여 얻 을 수 있 습 니 다.
static inline NSString * AFContentTypeForPathExtension(NSString *extension) {
    NSString *UTI = (__bridge_transfer NSString *)UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)extension, NULL);
    NSString *contentType = (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)UTI, kUTTagClassMIMEType);
    if (!contentType) {
        return @"application/octet-stream";
    } else {
        return contentType;
    }
}

먼저 접미사 에 따라 유형 표 지 를 만 든 다음 에 유형 표 지 를 mime 형식 으로 바 꾸 고 해당 하 는 유형 이 있 으 면 application / ocket - stream 으로 돌아 갑 니 다. 그렇지 않 으 면 contentType 으로 돌아 갑 니 다.
- (void)throttleBandwidthWithPacketSize:(NSUInteger)numberOfBytes
                                  delay:(NSTimeInterval)delay;

3G 또는 E 네트워크 환경 에서 스 트림 요청 시 업로드 에 실패 할 수 있 습 니 다. 따라서 저 희 는 요청 의 대역 폭 과 지연 시간 을 설정 하여 문 제 를 해결 할 수 있 습 니 다. numberOfBytes 는 바이트 크기 이 고 기본 값 은 16kb 이 며 delay 는 지연 시간 이 없습니다. 기본 값 은 지연 시간 이 없습니다.
실행 파일 에 여러 부분 으로 구 성 된 경계 부 호 를 만 드 는 방법 이 있 습 니 다.
static NSString * AFCreateMultipartFormBoundary() {
    return [NSString stringWithFormat:@"Boundary+%08X%08X", arc4random(), arc4random()];
}

여기에 랜 덤 수 를 만 드 는 방법 인 arc4random () 을 사용 합 니 다. oc 에는 랜 덤 수 를 만 드 는 방법 인 random () 이 있 습 니 다. 이 두 가지 방법 은 어떤 차이 가 있 습 니까?우선 arc4random () 의 수치 범 위 는 0x 10000000 (4294967296) 이 고 random () 은 0x7ffffff f (2147483647) 이 며 전 자 는 후자 의 두 배 이 며 정밀도 에서 후자 보다 우수 하 며 random () 을 사용 할 때 자신의 선생 이 무 작위 피 드 가 되 어야 하지만 arc4random () 은 첫 번 째 호출 할 때 자동 으로 생 성 되 어 사용 하기에 도 비교적 편리 하 다.
AFURL Response Serialization 에서 프로 토 콜 을 정의 합 니 다.
- (nullable id)responseObjectForResponse:(nullable NSURLResponse *)response
                           data:(nullable NSData *)data
                          error:(NSError * _Nullable __autoreleasing *)error NS_SWIFT_NOTHROW;

서로 다른 유형의 응답 분석 을 처리 하 는 데 사 용 됩 니 다. 그 중에서 각 유형 이 이 협 의 를 실 현 했 습 니 다.
AFJSON Response Serializer 는 기본적으로 이 세 개의 MIME 형식 을 받 아들 입 니 다.
 - `application/json`
 - `text/json`
 - `text/javascript`

AFXMLparser Response Serializer 는 기본적으로 이 두 개의 MIME 형식 을 받 아들 입 니 다.
 - `application/xml`
 - `text/xml`

AFProperty ListResponsesSerializer 는 기본적으로 이 MIME 형식 을 받 아들 입 니 다.
 - `application/x-plist`

AFImageResponse Serializer 는 기본적으로 이 10 개의 MIME 형식 을 받 아들 입 니 다.
 - `image/tiff`
 - `image/jpeg`
 - `image/gif`
 - `image/png`
 - `image/ico`
 - `image/x-icon`
 - `image/bmp`
 - `image/x-bmp`
 - `image/x-xbitmap`
 - `image/x-win-bitmap`

AFHTTP Response Serializer 구현 파일 에서
- (BOOL)validateResponse:(NSHTTPURLResponse *)response
                    data:(NSData *)data
                   error:(NSError * __autoreleasing *)error
{
    BOOL responseIsValid = YES;
    NSError *validationError = nil;

    if (response && [response isKindOfClass:[NSHTTPURLResponse class]]) {
        if (self.acceptableContentTypes && ![self.acceptableContentTypes containsObject:[response MIMEType]]) {
            if ([data length] > 0 && [response URL]) {
                NSMutableDictionary *mutableUserInfo = [@{
                                                          NSLocalizedDescriptionKey: [NSString stringWithFormat:NSLocalizedStringFromTable(@"Request failed: unacceptable content-type: %@", @"AFNetworking", nil), [response MIMEType]],
                                                          NSURLErrorFailingURLErrorKey:[response URL],
                                                          AFNetworkingOperationFailingURLResponseErrorKey: response,
                                                        } mutableCopy];
                if (data) {
                    mutableUserInfo[AFNetworkingOperationFailingURLResponseDataErrorKey] = data;
                }

                validationError = AFErrorWithUnderlyingError([NSError errorWithDomain:AFURLResponseSerializationErrorDomain code:NSURLErrorCannotDecodeContentData userInfo:mutableUserInfo], validationError);
            }

            responseIsValid = NO;
        }

        if (self.acceptableStatusCodes && ![self.acceptableStatusCodes containsIndex:(NSUInteger)response.statusCode] && [response URL]) {
            NSMutableDictionary *mutableUserInfo = [@{
                                               NSLocalizedDescriptionKey: [NSString stringWithFormat:NSLocalizedStringFromTable(@"Request failed: %@ (%ld)", @"AFNetworking", nil), [NSHTTPURLResponse localizedStringForStatusCode:response.statusCode], (long)response.statusCode],
                                               NSURLErrorFailingURLErrorKey:[response URL],
                                               AFNetworkingOperationFailingURLResponseErrorKey: response,
                                       } mutableCopy];

            if (data) {
                mutableUserInfo[AFNetworkingOperationFailingURLResponseDataErrorKey] = data;
            }

            validationError = AFErrorWithUnderlyingError([NSError errorWithDomain:AFURLResponseSerializationErrorDomain code:NSURLErrorBadServerResponse userInfo:mutableUserInfo], validationError);

            responseIsValid = NO;
        }
    }

    if (error && !responseIsValid) {
        *error = validationError;
    }

    return responseIsValid;
}

response 를 검증 하 는 세 가지 절차 가 있 습 니 다. 첫 번 째 단 계 는 response 가 비어 있 는 지 확인 하고 response 가 NSHTTPURL Response 류 인지 판단 하 는 것 입 니 다. 상기 조건 에 부합 되 지 않 으 면 YES 가 유효 합 니 다. 이것 은 이해 가 되 지 않 습 니 다. 나중에 해답 을 찾 으 면 response MIME 형식 이 받 아들 이 는 유형 인지 확인 하 는 두 번 째 단 계 를 업데이트 하 겠 습 니 다.없 으 면 error 세 번 째 단계 에서 받 은 상태 코드 가 존재 하 는 지 확인 합 니 다. 없 으 면 잠재 적 인 error 가 발생 하여 error 의 userInfo 에 넣 습 니 다. key 는 NSUnderlying ErrorKey 입 니 다.
- (id)responseObjectForResponse:(NSURLResponse *)response
                           data:(NSData *)data
                          error:(NSError *__autoreleasing *)error
{
    [self validateResponse:(NSHTTPURLResponse *)response data:data error:error];

    return data;
}

여 기 는 vaidate Response: data: error: 방법 만 호출 되 었 습 니 다. 실제로 들 어 온 data 를 되 돌려 주 는 것 은 하위 클래스 가 response Object ForResponse: data: error: 하위 클래스 의 response Object ForResponse: data: error: 모두 response 의 유효성 을 먼저 검증 한 다음 에 data 를 해당 유형 으로 바 꾼 다음 에 되 돌려 주 는 것 입 니 다.

좋은 웹페이지 즐겨찾기