88

私のクラスには、次のような繰り返しコードがたくさんあります。

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

非同期リクエストの問題は、さまざまなリクエストが発生し、それらすべてを 1 つのエンティティとして扱うデリゲートが割り当てられている場合、多くの分岐と醜いコードが次のように定式化し始めることです。

どのような種類のデータが返されますか? これが含まれている場合はそれを行い、そうでない場合はその他を行います。ビューにIDでタグ付けできるように、これらの非同期リクエストにタグ付けできると便利だと思います。

複数の非同期リクエストを処理するクラスを管理するには、どの戦略が最も効率的かということに興味がありました。

4

13 に答える 13

77

それに関連付けられた NSURLConnection をキーとする CFMutableDictionaryRef で応答を追跡します。すなわち:

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

NSMutableDictionary の代わりにこれを使用するのは奇妙に思えるかもしれませんが、この CFDictionary はそのキー (NSURLConnection) のみを保持するのに対し、NSDictionary はそのキーをコピーします (そして NSURLConnection はコピーをサポートしていません)。

それが完了したら:

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];
}
于 2008-12-01T22:37:37.457 に答える
19

2 つの異なる NSURLConnections があるプロジェクトがあり、同じデリゲートを使用したいと考えていました。私が行ったことは、クラスに 2 つのプロパティを作成し、接続ごとに 1 つずつ作成することでした。次に、デリゲート メソッドで、どの接続かを確認します。


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

これにより、必要に応じて特定の接続を名前でキャンセルすることもできます。

于 2011-01-24T20:18:22.950 に答える
16

データを保持するために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を引数としてno-argsブロック内でそれを必要とするメソッドに渡すことができます(図を参照)。

于 2012-12-17T19:25:07.627 に答える
8

これは新しい答えではありません。私がどのようにやったか見せてください

同じクラスのデリゲート メソッド内で異なる NSURLConnection を区別するために、NSMutableDictionary を使用して、その(NSString *)descriptionキーとして 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]];
于 2010-07-06T22:44:52.693 に答える
5

私が採用したアプローチの1つは、接続ごとにデリゲートと同じオブジェクトを使用しないことです。代わりに、起動される接続ごとに解析クラスの新しいインスタンスを作成し、デリゲートをそのインスタンスに設定します。

于 2008-12-02T05:35:18.567 に答える
4

これらすべてを処理するカスタム クラスMultipleDownloadを試してください。

于 2008-12-02T08:51:47.467 に答える
2

私は通常、辞書の配列を作成します。各ディクショナリには、少しの識別情報、応答を格納するための NSMutableData オブジェクト、および接続自体があります。接続デリゲート メソッドが起動すると、接続の辞書を検索し、それに応じて処理します。

于 2008-12-01T21:38:23.847 に答える
2

1 つのオプションは、自分で NSURLConnection をサブクラス化し、-tag または同様のメソッドを追加することです。NSURLConnection の設計は意図的に非常に骨の折れるものであるため、これは完全に受け入れられます。

あるいは、接続データの作成と収集を担当する MyURLConnectionController クラスを作成することもできます。ロードが完了したら、メインコントローラーオブジェクトに通知するだけで済みます。

于 2008-12-02T00:20:52.850 に答える
2

iOS5以降では、クラスメソッドを使用できます sendAsynchronousRequest:queue:completionHandler:

完了ハンドラーで応答が返されるため、接続を追跡する必要はありません。

于 2012-12-13T00:06:56.783 に答える
1

私はASIHTTPRequestが好きです。

于 2010-05-26T11:24:46.930 に答える
1

他の回答で指摘されているように、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];
于 2009-02-07T15:15:13.300 に答える
0

すべての NSURLConnection にはハッシュ属性があり、この属性によってすべてを区別できます。

たとえば、接続の前後に特定の情報を維持する必要があるため、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];
}
于 2013-12-23T10:27:47.487 に答える
0

NSURLConnection をサブクラス化し、タグ、デリゲート、および NSMutabaleData を追加することにしました。リクエストを含むすべてのデータ管理を処理する DataController クラスがあります。DataControllerDelegate プロトコルを作成して、個々のビュー/オブジェクトが DataController をリッスンして、要求がいつ終了したか、必要に応じてダウンロードされた量やエラーを確認できるようにしました。DataController クラスは、NSURLConnection サブクラスを使用して新しいリクエストを開始し、リクエストがいつ終了したかを知るために DataController をリッスンするデリゲートを保存できます。これは、XCode 4.5.2 および ios 6 での私の実用的なソリューションです。

DataControllerDelegate プロトコルを宣言する DataController.h ファイル)。DataController もシングルトンです。

@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
于 2012-11-14T00:44:54.880 に答える