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?

Author: Jay Bhalani, 2009-12-24

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,

 22
Author: Matt Long,
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.

 1
Author: Kendall Helmstetter Gelner,
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