Nsurlconnection nsurlrequest proxy dla asynchronicznych wywołań usług sieciowych
Mam wiele widoków, które tworzą to samo NSURLRequest/NSURLConnection request
. Najlepiej, aby uzyskać ponowne użycie kodu, chciałbym mieć jakiś "proxy", który wykonuje całą podstawową pracę, tworząc/wykonując (asynchroniczne) żądanie/połączenie, konfigurując wszystkie metody delegatów, itp., więc nie muszę kopiować tych wszystkich NSURLConnection
delegatów do obsługi metod w każdym widoku. Po pierwsze, czy takie podejście projektowe jest rozsądne? Po drugie, jak mógłbym zrobić coś takiego?
Dla trochę informacji w tle, próbowałem tego i dostałem go do "pracy", jednak nie wydaje się być wykonywany asynchronicznie. Stworzyłem Proxy.plik h / m, który zawiera metody instancji dla różnych wywołań usługi sieciowej (a także zawiera metody delegata NSURLConnection
):
@interface Proxy : NSObject {
NSMutableData *responseData;
id<WSResponseProtocol> delegate;
}
- (void)searchForSomethingAsync:(NSString *)searchString delegate:(id<WSResponseProtocol>)delegateObj;
@property (nonatomic, retain) NSMutableData *responseData;
@property (assign) id<WSResponseProtocol> delegate;
@end
WSResponseProtocol jest zdefiniowany jako taki:
@protocol WSResponseProtocol <NSObject>
@optional
- (void)responseData:(NSData *)data;
- (void)didFailWithError:(NSError *)error;
@end
Aby tego użyć, kontroler widoku musi po prostu dostosować się do protokołu WSResponseProtocol
, aby wychwycić odpowiedzi. Wywołanie usługi internetowej odbywa się jak więc:
Proxy *p = [[Proxy alloc] init];
[p searchForSomethingAsync:searchText delegate:self];
[p release];
Mogę podać więcej kodu, ale pozostałe można założyć. Przed wywołaniem "zaczynam" spinner. Ale spinner nigdy się nie kręci. Jeśli po prostu umieszczę metody delegowania NSURLConnection bezpośrednio w kontrolerze widoku, to wirnik obraca się. To sprawia, że myślę, że moja implementacja nie jest wykonywana asynchronicznie. Jakieś pomysły/pomysły?
2 answers
Twoje podejście jest rozsądne, jednak nie jestem pewien, dlaczego tworzysz swój własny protokół. To nie jest konieczne. Wszystko, czego potrzebujesz, aby to zaimplementować, znajduje się w dokumentacji Apple na NSURLConnection . Jeśli weźmiesz Kod ze strony, na której utworzono instancję NSURLConnection, i sprawisz, że połączenie stanie się ivar, zamiast tworzyć je jako zmienną lokalną, możesz porównać obiekty połączenia w każdej z metod wywołania zwrotnego i odpowiednio odpowiedzieć. Na przykład, weźmy ten kod z docs i zmień obiekt connection na ivar:
// create the request
NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.apple.com/"]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
// create the connection with the request
// and start loading the data
theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if (theConnection) {
// Create the NSMutableData that will hold
// the received data
// receivedData is declared as a method instance elsewhere
receivedData=[[NSMutableData data] retain];
} else {
// inform the user that the download could not be made
}
Zmienna theConnection jest naszym Ivarem. Następnie możesz to sprawdzić w następujący sposób:
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
if (connection == theConnection)
{
// do something with the data object.
[connectionSpecificDataObject appendData:data];
}
}
Z pewnością możesz zaimplementować go tworząc własny protokół, jak sugerujesz, a następnie oddzwonić do delegata, który jest zgodny z Twoim protokołem, ale może lepiej będzie po prostu utworzyć instancję obiektu za pomocą selektora sukcesu i porażki, który możesz sprawdzić. Coś takiego:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
if (connection == theConnection)
{
if (delegate && [delegate respondsToSelector:successSelector])
[delegate performSelector:successSelector
withObject:connectionSpecificDataObject];
}
[connection release];
}
Gdzie dataDidDownloadSelector jest zmienną instancji Sel, którą ustawiasz podczas tworzenia delegata pobierania, gdzie cały ten kod jest zawarty-Twój obiekt Proxy. Coś takiego:
Proxy *p = [[Proxy alloc] init];
[p searchForSomethingAsync:searchText
delegate:self
successSelector:@selector(didFinishWithData:)
failSelector:@selector(didFailWithError:)];
Zaimplementuj swoje selektory w następujący sposób:
- (void)didFinishWithData:(NSData*)data;
{
// Do something with data
}
- (void)didFailWithError:(NSError*)error
{
// Do something with error
}
To stała się dłuższa odpowiedź niż zamierzałem. Daj mi znać, jeśli to nie ma sensu i mogę spróbować wyjaśnić.
Pozdrawiam,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-24 18:36:20
Twój kod jak jest, myślę, że nic by nie zrobił - zwalniasz Proxy zaraz po zainicjowaniu, więc nigdy nie działa.
Podejście, którego lubię używać, to synchroniczne wywołania NSURLConnection, wewnątrz NSOperation, które z kolei jest zarządzane przez NSOperationQueue. Robię obiekt Kolejka żyje w Singleton, więc po prostu dostęp do instancji z dowolnego miejsca i powiedzieć, kiedy trzeba nowe połączenie uruchomione.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-24 21:38:06