Saya memiliki banyak kode berulang di kelas saya yang terlihat seperti berikut:
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request
delegate:self];
Masalah dengan permintaan asinkron adalah ketika Anda memiliki berbagai permintaan yang keluar, dan Anda memiliki delegasi yang ditugaskan untuk memperlakukan mereka semua sebagai satu entitas, banyak kode bercabang dan jelek mulai merumuskan:
Jenis data apa yang kami dapatkan kembali? Jika berisi ini, lakukan itu, jika tidak, lakukan yang lain. Menurut saya, akan bermanfaat jika dapat menandai permintaan asinkron ini, seperti Anda dapat menandai tampilan dengan ID.
Saya ingin tahu strategi apa yang paling efisien untuk mengelola kelas yang menangani beberapa permintaan asinkron.
sumber
[NSMapTable weakToStrongObjectsMapTable]
alih - alih aCFMutableDictionaryRef
dan menghemat kerumitan. Bekerja dengan baik untuk saya.Saya memiliki proyek di mana saya memiliki dua NSURLConnections yang berbeda, dan ingin menggunakan delegasi yang sama. Apa yang saya lakukan adalah membuat dua properti di kelas saya, satu untuk setiap koneksi. Kemudian dalam metode delegasi, saya memeriksa untuk melihat apakah hubungannya
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { if (connection == self.savingConnection) { [self.savingReturnedData appendData:data]; } else { [self.sharingReturnedData appendData:data]; } }
Ini juga memungkinkan saya untuk membatalkan koneksi tertentu berdasarkan nama saat diperlukan.
sumber
Subclassing NSURLConnection untuk menyimpan data yang bersih, lebih sedikit kode daripada beberapa jawaban lainnya, lebih fleksibel, dan membutuhkan lebih sedikit pemikiran tentang manajemen referensi.
// 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
Gunakan seperti yang Anda lakukan NSURLConnection dan kumpulkan data dalam properti datanya:
- (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]; }
Itu dia.
Jika Anda ingin melangkah lebih jauh, Anda dapat menambahkan blok yang berfungsi sebagai panggilan balik hanya dengan beberapa baris kode lagi:
// Add to DataURLConnection.h/.m @property(nonatomic, copy) void (^onComplete)();
Atur seperti ini:
DataURLConnection *con = [[DataURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO]; con.onComplete = ^{ [self myMethod:con]; }; [con start];
dan panggil ketika pemuatan selesai seperti ini:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection { ((DataURLConnection *)connection).onComplete(); }
Anda dapat memperluas blok untuk menerima parameter atau hanya meneruskan DataURLConnection sebagai argumen ke metode yang membutuhkannya di dalam blok no-args seperti yang ditunjukkan
sumber
INI BUKAN JAWABAN BARU. TOLONG BIARKAN SAYA TUNJUKKAN CARA SAYA
Untuk membedakan NSURLConnection yang berbeda dalam metode delegasi kelas yang sama, saya menggunakan NSMutableDictionary, untuk mengatur dan menghapus NSURLConnection, menggunakan
(NSString *)description
sebagai kuncinya.Objek yang saya pilih
setObject:forKey
adalah URL unik yang digunakan untuk memulaiNSURLRequest
,NSURLConnection
penggunaan.Setelah disetel, NSURLConnection dievaluasi di
-(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]];
sumber
Salah satu pendekatan yang saya ambil adalah tidak menggunakan objek yang sama sebagai delegasi untuk setiap koneksi. Sebagai gantinya, saya membuat instance baru dari kelas parsing saya untuk setiap koneksi yang dijalankan dan mengatur delegasi ke instance itu.
sumber
Coba kelas khusus saya, MultipleDownload , yang menangani semua ini untuk Anda.
sumber
Saya biasanya membuat berbagai kamus. Setiap kamus memiliki sedikit informasi pengenal, objek NSMutableData untuk menyimpan respons, dan koneksi itu sendiri. Ketika metode delegasi koneksi diaktifkan, saya mencari kamus koneksi dan menanganinya sesuai.
sumber
Salah satu opsinya adalah subclass NSURLConnection sendiri dan tambahkan -tag atau metode serupa. Desain NSURLConnection sengaja dibuat tanpa tulang jadi ini bisa diterima.
Atau mungkin Anda bisa membuat kelas MyURLConnectionController yang bertanggung jawab untuk membuat dan mengumpulkan data koneksi. Kemudian hanya perlu memberi tahu objek pengontrol utama Anda setelah pemuatan selesai.
sumber
di iOS5 dan yang lebih baru, Anda cukup menggunakan metode kelas
sendAsynchronousRequest:queue:completionHandler:
Tidak perlu melacak koneksi karena respons kembali di penangan penyelesaian.
sumber
Saya suka ASIHTTPRequest .
sumber
Seperti yang ditunjukkan oleh jawaban lain, Anda harus menyimpan connectionInfo di suatu tempat dan mencarinya berdasarkan koneksi.
Jenis data yang paling alami untuk ini adalah
NSMutableDictionary
, tetapi tidak dapat menerimaNSURLConnection
sebagai kunci karena koneksi tidak dapat disalin.Opsi lain untuk digunakan
NSURLConnections
sebagai kunci dalamNSMutableDictionary
menggunakanNSValue valueWithNonretainedObject]
:NSMutableDictionary* dict = [NSMutableDictionary dictionary]; NSValue *key = [NSValue valueWithNonretainedObject:aConnection] /* store: */ [dict setObject:connInfo forKey:key]; /* lookup: */ [dict objectForKey:key];
sumber
Saya memutuskan untuk membuat subkelas NSURLConnection dan menambahkan tag, delegasi, dan NSMutabaleData. Saya memiliki kelas DataController yang menangani semua manajemen data, termasuk permintaan. Saya membuat protokol DataControllerDelegate, sehingga tampilan / objek individu dapat mendengarkan DataController untuk mengetahui kapan permintaan mereka selesai, dan jika perlu, berapa banyak yang telah diunduh atau kesalahan. Kelas DataController dapat menggunakan subkelas NSURLConnection untuk memulai permintaan baru, dan menyimpan delegasi yang ingin mendengarkan DataController untuk mengetahui kapan permintaan telah selesai. Ini adalah solusi kerja saya di XCode 4.5.2 dan ios 6.
File DataController.h yang mendeklarasikan protokol DataControllerDelegate). DataController juga berbentuk tunggal:
@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
Metode kunci dalam file 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]]; }
Dan untuk memulai permintaan:
[[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
Dan 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
sumber
Setiap NSURLConnection memiliki atribut hash, Anda dapat membedakan semuanya dengan atribut ini.
Misalnya saya perlu menjaga informasi tertentu sebelum dan sesudah koneksi, jadi RequestManager saya memiliki NSMutableDictionary untuk melakukan ini.
Sebuah contoh:
// 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];
Setelah permintaan:
- (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]; }
sumber