У меня есть несколько представлений, которые делают то же NSURLRequest/NSURLConnection request
. Идеально, для получения некоторого повторного использования кода, я хотел бы иметь своего рода "прокси", который делает всю базовую работу создания/выполнения (асинхронного) запроса/соединения, установки все методы делегата, и т.д., таким образом, я не должен копировать все они NSURLConnection
обработчики методов делегата в каждом представлении. В первую очередь, действительно ли этот подход дизайна разумен? Во-вторых, как я пошел бы о выполнении чего-то как этот?
Для небольшой вводной информации я делал попытку этого и заставил ее "работать", однако, это, кажется, не выполняется асинхронно. Я создал файл Proxy.h/m, который имеет методы экземпляра для различных вызовов веб-сервиса (и также содержит 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 определяется как таковой:
@protocol WSResponseProtocol <NSObject>
@optional
- (void)responseData:(NSData *)data;
- (void)didFailWithError:(NSError *)error;
@end
Для использования этого контроллер представления просто должен соответствовать WSResponseProtocol
протокол, для ловли ответа (ответов). Совершение звонка веб-сервиса сделано как так:
Proxy *p = [[Proxy alloc] init];
[p searchForSomethingAsync:searchText delegate:self];
[p release];
Я могу предоставить больше кода, но остающееся может быть принято. Перед вызовом, я "startAnimating" a UIActivityIndicatorView
счетчик. Но счетчик никогда не вращается. Если я просто поместил методы делегата NSURLConnection непосредственно в контроллер представления, то счетчик вращается. Так, это заставляет меня думать, что моя реализация не выполняется асинхронно. Какие-либо мысли/идеи здесь?
Ваш подход разумен, однако, я не уверен, зачем вы создаете свой собственный протокол. В этом нет необходимости. Всё, что вам нужно, чтобы это реализовалось, находится в документации Apple по NSURLConnection. Если взять код с той страницы, где инстанцируется NSURLConnection, и сделать соединение ivar вместо того, чтобы просто создавать его в качестве локальной переменной, вы можете затем сравнить объекты соединения в каждом из методов обратного вызова и ответить соответствующим образом. Например, возьмите этот код из документации и измените объект соединения на 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
}
Переменная theConnection - это наш ivar. Тогда вы можете проверить ее следующим образом:
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
if (connection == theConnection)
{
// do something with the data object.
[connectionSpecificDataObject appendData:data];
}
}
Вы, конечно, можете реализовать ее, создав свой собственный протокол, как вы предлагаете, а затем перезвонить делегату, который соответствует вашему протоколу, но, возможно, вам лучше просто инстанцировать ваш объект, используя селектор успеха и неудачи, который вы можете проверить. Что-то вроде этого:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
if (connection == theConnection)
{
if (delegate && [delegate respondsToSelector:successSelector])
[delegate performSelector:successSelector
withObject:connectionSpecificDataObject];
}
[connection release];
}
Где dataDidDownloadSelector - это переменная SEL instance, которую вы устанавливаете, когда создаете делегата загрузки, где весь этот код содержится - ваш объект Proxy. Что-то вроде этого:
Proxy *p = [[Proxy alloc] init];
[p searchForSomethingAsync:searchText
delegate:self
successSelector:@selector(didFinishWithData:)
failSelector:@selector(didFailWithError:)];
Реализуйте свои селекторы следующим образом:
- (void)didFinishWithData:(NSData*)data;
{
// Do something with data
}
- (void)didFailWithError:(NSError*)error
{
// Do something with error
}
Это стало более длинным ответом, чем я предполагал. Дайте мне знать, если это не имеет смысла, и я попробую прояснить.
С наилучшими пожеланиями,
.Ваш код как есть, я думаю, ничего не сделает - вы освобождаете прокси сразу после инициализации, поэтому он даже не запускается.
Мне нравится использовать синхронные вызовы NSURLConnection, внутри NSOperation, которая, в свою очередь, управляется NSOperationQueue. Я делаю объект очереди в синглтоне, поэтому я просто получаю доступ к экземпляру из любого места и сообщаю ему, когда мне нужно начать новое соединение.