[objective-c] 여러 비동기 NSURLConnection 연결 관리

내 수업에는 다음과 같은 반복되는 코드가 많이 있습니다.

NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request
                                                              delegate:self];

비동기 요청의 문제는 다양한 요청이 발생하고 모든 요청을 하나의 엔터티로 처리하도록 할당 된 대리자가있을 때 많은 분기 및 추악한 코드가 공식화되기 시작한다는 것입니다.

우리는 어떤 종류의 데이터를 받고 있습니까? 이것이 포함되어 있으면 그렇게하고 그렇지 않으면 다른 작업을 수행하십시오. ID로 뷰에 태그를 지정할 수있는 것처럼 이러한 비동기 요청에 태그를 지정할 수 있으면 유용 할 것입니다.

여러 비동기 요청을 처리하는 클래스를 관리하는 데 가장 효율적인 전략이 무엇인지 궁금했습니다.



답변

나는 그것과 관련된 NSURLConnection에 의해 입력 된 CFMutableDictionaryRef에서 응답을 추적한다. 즉 :

connectionToInfoMapping =
    CFDictionaryCreateMutable(
        kCFAllocatorDefault,
        0,
        &kCFTypeDictionaryKeyCallBacks,
        &kCFTypeDictionaryValueCallBacks);

NSMutableDictionary 대신 이것을 사용하는 것이 이상하게 보일 수 있지만이 CFDictionary는 키 (NSURLConnection) 만 유지하는 반면 NSDictionary는 키를 복사합니다 (NSURLConnection은 복사를 지원하지 않음).

완료되면 :

CFDictionaryAddValue(
    connectionToInfoMapping,
    connection,
    [NSMutableDictionary
        dictionaryWithObject:[NSMutableData data]
        forKey:@"receivedData"]);

이제 연결에 대한 정보를 추적하는 데 사용할 수있는 각 연결에 대한 “정보”데이터 사전이 있으며 “정보”사전에는 응답 데이터가 들어올 때 저장하는 데 사용할 수있는 변경 가능한 데이터 개체가 이미 포함되어 있습니다.

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    NSMutableDictionary *connectionInfo =
        CFDictionaryGetValue(connectionToInfoMapping, connection);
    [[connectionInfo objectForKey:@"receivedData"] appendData:data];
}


답변

두 개의 서로 다른 NSURLConnection이 있고 동일한 대리자를 사용하려는 프로젝트가 있습니다. 내가 한 것은 각 연결에 대해 하나씩 클래스에 두 개의 속성을 만드는 것입니다. 그런 다음 위임 메서드에서 어떤 연결인지 확인합니다.


- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    if (connection == self.savingConnection) {
        [self.savingReturnedData appendData:data];
    }
    else {
        [self.sharingReturnedData appendData:data];
    }
}

또한 필요할 때 이름으로 특정 연결을 취소 할 수 있습니다.


답변

데이터를 보관하기 위해 NSURLConnection을 서브 클래 싱하는 것은 다른 답변보다 코드가 적고 더 유연하며 참조 관리에 대한 생각이 덜 필요합니다.

// DataURLConnection.h
#import <Foundation/Foundation.h>
@interface DataURLConnection : NSURLConnection
@property(nonatomic, strong) NSMutableData *data;
@end

// DataURLConnection.m
#import "DataURLConnection.h"
@implementation DataURLConnection
@synthesize data;
@end

NSURLConnection처럼 사용하고 데이터 속성에 데이터를 누적합니다.

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
    ((DataURLConnection *)connection).data = [[NSMutableData alloc] init];
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    [((DataURLConnection *)connection).data appendData:data];
}

그게 다야.

더 나아가고 싶다면 몇 줄의 코드로 콜백 역할을하는 블록을 추가 할 수 있습니다.

// Add to DataURLConnection.h/.m
@property(nonatomic, copy) void (^onComplete)();

다음과 같이 설정하십시오.

DataURLConnection *con = [[DataURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
con.onComplete = ^{
    [self myMethod:con];
};
[con start];

로드가 완료되면 다음과 같이 호출하십시오.

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    ((DataURLConnection *)connection).onComplete();
}

매개 변수를 허용하도록 블록을 확장하거나 표시된대로 인수가없는 블록 내에서이를 필요로하는 메소드에 DataURLConnection을 인수로 전달할 수 있습니다.


답변

이것은 새로운 답이 아닙니다. 내가 어떻게했는지 보여 줄게

동일한 클래스의 대리자 메서드 내에서 다른 NSURLConnection을 구별하기 위해 NSMutableDictionary를 사용하여 해당 (NSString *)descriptionas 키를 사용하여 NSURLConnection을 설정하고 제거합니다 .

내가 위해 선택한 객체는 setObject:forKey시작에 사용되는 고유 한 URL 인 NSURLRequestNSURLConnection용도.

일단 설정된 NSURLConnection은

-(void)connectionDidFinishLoading:(NSURLConnection *)connection, it can be removed from the dictionary.

// This variable must be able to be referenced from - (void)connectionDidFinishLoading:(NSURLConnection *)connection
NSMutableDictionary *connDictGET = [[NSMutableDictionary alloc] init];
//...//

// You can use any object that can be referenced from - (void)connectionDidFinishLoading:(NSURLConnection *)connection
[connDictGET setObject:anyObjectThatCanBeReferencedFrom forKey:[aConnectionInstanceJustInitiated description]];
//...//

// At the delegate method, evaluate if the passed connection is the specific one which needs to be handled differently
if ([[connDictGET objectForKey:[connection description]] isEqual:anyObjectThatCanBeReferencedFrom]) {
// Do specific work for connection //

}
//...//

// When the connection is no longer needed, use (NSString *)description as key to remove object
[connDictGET removeObjectForKey:[connection description]];


답변

내가 취한 한 가지 접근 방식은 각 연결에 대해 델리게이트와 동일한 객체를 사용하지 않는 것입니다. 대신 시작된 각 연결에 대해 파싱 클래스의 새 인스턴스를 만들고 해당 인스턴스에 대리자를 설정합니다.


답변

이 모든 것을 처리하는 내 사용자 정의 클래스 MultipleDownload를 사용해보십시오 .


답변

저는 보통 사전 배열을 만듭니다. 각 사전에는 약간의 식별 정보, 응답을 저장할 NSMutableData 객체 및 연결 자체가 있습니다. 연결 대리자 메서드가 실행되면 연결 사전을 찾아 그에 따라 처리합니다.