문제

수업에는 다음과 같은 것처럼 보이는 반복 코드가 많이 있습니다.

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"]);

그리고 이제 연결에 대한 정보를 추적하는 데 사용할 수있는 각 연결에 대한 "정보"사전과 "Info"사전에는 이미 회신 데이터를 저장하는 데 사용할 수있는 변이 가능한 데이터 객체가 포함되어 있습니다.

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

다른 팁

두 개의 뚜렷한 nsurlconnections가있는 프로젝트가 있고 동일한 대의원을 사용하고 싶었습니다. 내가 한 일은 수업에서 각 연결 당 하나의 두 가지 속성을 만드는 것이 었습니다. 그런 다음 대표 방법에서 어떤 연결이든지 확인합니다.


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

블록을 확장하여 매개 변수를 받아들이거나 데이터 릴 연결을 표시하지 않는 방법으로 인수로 전달할 수 있습니다.

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

동일한 클래스의 대의원 메소드 내에서 다른 nsurlconnection을 구별하려면 nsmutabledictionary를 사용하여 NSURLConnection을 설정하고 제거합니다. (NSString *)description 열쇠로.

내가 선택한 대상 setObject:forKey 시작에 사용되는 고유 한 URL입니다 NSURLRequest,, NSURLConnection 용도.

일단 설정되면 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]];

내가 취한 방법 중 하나는 각 연결에 대해 대의원과 동일한 개체를 사용하지 않는 것입니다. 대신, 발사 된 각 연결에 대해 새 구문 분석 클래스의 새 인스턴스를 생성하고 대의원을 해당 인스턴스로 설정합니다.

내 커스텀 클래스를 시도하고 다중 공장,이 모든 것을 당신을 위해 처리합니다.

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

한 가지 옵션은 NsurlConnection을 서브 클래스하고 -TAG 또는 유사한 방법을 추가하는 것입니다. nsurlconnection의 디자인은 의도적으로 매우 뼈가 매우 뼈 가므로 완벽하게 허용됩니다.

또는 연결 데이터를 작성하고 수집하는 MyurlConnectionController 클래스를 만들 수도 있습니다. 그런 다음로드가 완료되면 주 컨트롤러 객체를 알리면됩니다.

iOS5 이상에서는 클래스 메소드 만 사용할 수 있습니다.sendAsynchronousRequest:queue:completionHandler:

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

좋아요 Asihttprequest.

다른 답변에서 지적했듯이 ConnectionInfo를 어딘가에 저장하고 연결로 찾아야합니다.

이것에 대한 가장 자연스러운 데이터 유형은입니다 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];

나는 nsurlconnection을 서브 클래스로 결정하고 태그, 대표 및 nsmutabaledata를 추가하기로 결정했습니다. 요청을 포함하여 모든 데이터 관리를 처리하는 데이터 컨트롤러 클래스가 있습니다. DatacontrollerDelegate 프로토콜을 만들어 개별보기/객체가 데이터 콘트롤러를 듣고 요청이 완료되었는지, 그리고 필요한 경우 다운로드 또는 오류가 필요한 경우를 찾을 수 있습니다. DataController 클래스는 NSURLConnection 서브 클래스를 사용하여 새 요청을 시작하고 요청이 완료된시기를 알기 위해 Datacontroller를 듣고 자하는 대의원을 저장할 수 있습니다. 이것은 Xcode 4.5.2 및 iOS 6의 내 작동 솔루션입니다.

Datacontroller.h 파일 DatacontrollerDelegate 프로토콜을 선언하는 파일). 데이터 컨트롤러는 또한 싱글 톤입니다.

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

nsurlconnectionwithdelegate.h : @protocol datacontrollerdelegate;

@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

그리고 nsurlconnectionwithdelegate.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

모든 nsurlconnection에는 해시 속성이 있으며이 속성으로 모든 것을 차별 할 수 있습니다.

예를 들어 연결 전후에 특정 정보를 맨 테이프해야하므로 요청 관리자에게는이 작업을 수행 할 NSMutabledictionary가 있습니다.

An Example:

// 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];
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top