programing

여러 비동기 NSURL 연결 관리

megabox 2023. 8. 27. 09:03
반응형

여러 비동기 NSURL 연결 관리

우리 반에는 다음과 같은 반복 코드가 많이 있습니다.

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

비동기식 요청의 문제는 다양한 요청이 발생하고 모든 요청을 하나의 엔티티로 처리하도록 위임받은 경우, 많은 분기 및 추악한 코드가 다음과 같이 공식화되기 시작한다는 것입니다.

어떤 종류의 데이터를 얻고 있습니까?이것이 포함되어 있으면 그렇게 하고, 그렇지 않으면 다른 것을 합니다.이러한 비동기 요청에 태그를 지정할 수 있다면 유용할 것입니다. 마치 ID로 보기에 태그를 지정할 수 있는 것처럼 말입니다.

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

나는 관련된 NSURL 연결에 의해 키가 지정된 CFMutableDictionaryRef에서 응답을 추적합니다. 예:

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

NSMutableDictionary 대신 이 기능을 사용하는 것이 이상하게 보일 수 있지만, 이 CFDictionary는 키(NSULC 연결)만 유지하는 반면 NSDictionary는 키를 복사(및 NSULC 연결은 복사를 지원하지 않음)하기 때문에 이 기능을 사용합니다.

작업이 완료되면 다음을 수행합니다.

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

이제 각 연결에 대한 데이터의 "info" 사전을 사용하여 연결에 대한 정보를 추적할 수 있으며 "info" 사전에는 이미 응답 데이터를 저장하는 데 사용할 수 있는 가변 데이터 개체가 있습니다.

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

두 개의 서로 다른 NSURL 연결이 있는 프로젝트가 있는데, 동일한 대리자를 사용하려고 합니다.제가 한 일은 우리 반에 각 연결마다 하나씩 두 개의 속성을 만드는 것이었습니다.그런 다음 위임 방법에서 어떤 연결인지 확인합니다.


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

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

데이터를 유지하기 위한 NSURL 연결 하위 분류는 다른 답변보다 코드가 적고, 유연성이 뛰어나며, 참조 관리에 대한 고려가 덜합니다.

// 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

NSURL 연결과 마찬가지로 사용하고 데이터 속성에 데이터를 축적합니다.

- (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();
}

표시된 것처럼 매개 변수를 허용하도록 블록을 확장하거나 no-args 블록 내에서 필요한 메서드에 인수로 DataURLConnection을 전달할 수 있습니다.

이것은 새로운 대답이 아닙니다.제가 어떻게 했는지 보여드리겠습니다.

메서드 에서 서로 하기 위해 하여 NSURL합니다. NSURL을 사용하여 NSMutableDictionary를 합니다.(NSString *)descriptionkey. 쇠로열

는 가선택객체입니다.setObject:forKey는 시에사입고유 URL을 하는 데 입니다.NSURLRequest,NSURLConnection사용하다.

설정된 NSURL 연결이 다음에서 평가됩니다.

-(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]];

제가 취한 한 가지 접근 방식은 각 연결에 대해 대리자와 동일한 개체를 사용하지 않는 것입니다.대신, 각 연결이 해제될 때마다 구문 분석 클래스의 새 인스턴스를 만들고 대리자를 해당 인스턴스로 설정합니다.

이 모든 것을 처리하는 사용자 지정 클래스인 다중 다운로드를 사용해 보십시오.

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

한 가지 옵션은 직접 NSURL 연결을 하위 분류하고 -tag 또는 유사한 방법을 추가하는 것입니다.NSURL Connection의 설계는 의도적으로 매우 베어본이므로 이는 완벽하게 수용 가능합니다.

또는 연결의 데이터를 만들고 수집하는 MyURLConnectionController 클래스를 만들 수도 있습니다.그런 다음 로드가 완료된 후에만 주 컨트롤러 개체에 알려주면 됩니다.

메소드 iOS5를 .sendAsynchronousRequest:queue:completionHandler:

응답이 완료 핸들러에 반환되므로 연결을 추적할 필요가 없습니다.

ASIHTTPRequest를 좋아합니다.

다른 답변에서 지적했듯이 연결을 저장해야 합니다.어딘가에 정보를 제공하고 연결을 통해 검색합니다.

이에 대한 가장 자연스러운 데이터 유형은 다음과 같습니다.NSMutableDictionary하지만 그것은 받아들일 수 없습니다.NSURLConnection키를 복사할 수 없습니다.

사을위다옵션을 사용하기 위한 입니다.NSURLConnections…의 NSMutableDictionary 중입니다.NSValue valueWithNonretainedObject]:

NSMutableDictionary* dict = [NSMutableDictionary dictionary];
NSValue *key = [NSValue valueWithNonretainedObject:aConnection]
/* store: */
[dict setObject:connInfo forKey:key];
/* lookup: */
[dict objectForKey:key];

NSURL Connection을 하위 분류하고 태그, 위임 및 NSMutabaleData를 추가하기로 결정했습니다.요청을 포함한 모든 데이터 관리를 처리하는 DataController 클래스가 있습니다.개별 보기/객체가 DataController를 청취하여 요청이 완료된 시점과 필요한 경우 다운로드 또는 오류의 양을 확인할 수 있도록 DataControllerDelegate 프로토콜을 만들었습니다.DataController 클래스는 NSURLConnection 하위 클래스를 사용하여 새 요청을 시작하고 DataController를 청취하려는 대리자를 저장하여 요청이 완료된 시간을 알 수 있습니다.이것은 XCode 4.5.2 및 ios 6에서 사용하는 솔루션입니다.

DataControllerDelegate protocol)을 선언하는 DataController.h 파일입니다.데이터 컨트롤러도 싱글톤입니다.

@interface DataController : NSObject

@property (strong, nonatomic)NSManagedObjectContext *context;
@property (strong, nonatomic)NSString *accessToken;

+(DataController *)sharedDataController;

-(void)generateAccessTokenWith:(NSString *)email password:(NSString *)password delegate:(id)delegate;

@end

@protocol DataControllerDelegate <NSObject>

-(void)dataFailedtoLoadWithMessage:(NSString *)message;
-(void)dataFinishedLoading;

@end

DataController.m 파일의 주요 메서드는 다음과 같습니다.

-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
    NSURLConnectionWithDelegate *customConnection = (NSURLConnectionWithDelegate *)connection;
    NSLog(@"DidReceiveResponse from %@", customConnection.tag);
    [[customConnection receivedData] setLength:0];
}

-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    NSURLConnectionWithDelegate *customConnection = (NSURLConnectionWithDelegate *)connection;
    NSLog(@"DidReceiveData from %@", customConnection.tag);
    [customConnection.receivedData appendData:data];

}

-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
    NSURLConnectionWithDelegate *customConnection = (NSURLConnectionWithDelegate *)connection;
    NSLog(@"connectionDidFinishLoading from %@", customConnection.tag);
    NSLog(@"Data: %@", customConnection.receivedData);
    [customConnection.dataDelegate dataFinishedLoading];
}

-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    NSURLConnectionWithDelegate *customConnection = (NSURLConnectionWithDelegate *)connection;
    NSLog(@"DidFailWithError with %@", customConnection.tag);
    NSLog(@"Error: %@", [error localizedDescription]);
    [customConnection.dataDelegate dataFailedtoLoadWithMessage:[error localizedDescription]];
}

요청을 시작하려면 다음과 같이 하십시오.[[NSURLConnectionWithDelegate alloc] initWithRequest:request delegate:self startImmediately:YES tag:@"Login" dataDelegate:delegate];

NSURL 연결딜러와 함께.h: @protocol Data Controller 대표단;

@interface NSURLConnectionWithDelegate : NSURLConnection

@property (strong, nonatomic) NSString *tag;
@property id <DataControllerDelegate> dataDelegate;
@property (strong, nonatomic) NSMutableData *receivedData;

-(id)initWithRequest:(NSURLRequest *)request delegate:(id)delegate startImmediately:(BOOL)startImmediately tag:(NSString *)tag dataDelegate:(id)dataDelegate;

@end

그리고 NSURL 연결은딜러와 함께.m:

#import "NSURLConnectionWithDelegate.h"

@implementation NSURLConnectionWithDelegate

-(id)initWithRequest:(NSURLRequest *)request delegate:(id)delegate startImmediately:(BOOL)startImmediately tag:(NSString *)tag dataDelegate:(id)dataDelegate {
    self = [super initWithRequest:request delegate:delegate startImmediately:startImmediately];
    if (self) {
        self.tag = tag;
        self.dataDelegate = dataDelegate;
        self.receivedData = [[NSMutableData alloc] init];
    }
    return self;
}

@end

모든 NSURL 연결에는 해시 특성이 있으므로 이 특성으로 모두 구별할 수 있습니다.

예를 들어 연결 전후에 특정 정보를 유지 관리해야 하므로 RequestManager에 NSMutableDictionary가 있습니다.

예:

// Make Request
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLConnection *c = [[NSURLConnection alloc] initWithRequest:request delegate:self];

// Append Stuffs 
NSMutableDictionary *myStuff = [[NSMutableDictionary alloc] init];
[myStuff setObject:@"obj" forKey:@"key"];
NSNumber *connectionKey = [NSNumber numberWithInt:c.hash];

[connectionDatas setObject:myStuff forKey:connectionKey];

[c start];

요청 후:

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    NSLog(@"Received %d bytes of data",[responseData length]);

    NSNumber *connectionKey = [NSNumber numberWithInt:connection.hash];

    NSMutableDictionary *myStuff = [[connectionDatas objectForKey:connectionKey]mutableCopy];
    [connectionDatas removeObjectForKey:connectionKey];
}

언급URL : https://stackoverflow.com/questions/332276/managing-multiple-asynchronous-nsurlconnection-connections

반응형