Ответ 1
- Прекратить использование ASIHTTPRequest.
NSURLConnection
не является трудным в использовании и приведет к лучшему, более совершенному коду. - Ваш ответ JSON должен быть подан в структуру данных, а не в пользовательский интерфейс. Я рекомендую Core Data.
- Структура данных должна подавать ваш
UITableView
. Опять же, я рекомендую Core Data.
Я бы предложил просмотреть, как работает MVC, вы коротко замыкаете дизайн, и это основная проблема.
Спойлер
Вот более подробная информация. Сначала вы хотите, чтобы поиск данных был асинхронным. Самый простой и многоразовый способ сделать это - создать простой подкласс NSOperation.
@class CIMGFSimpleDownloadOperation;
@protocol CIMGFSimpleDownloadDelegate <NSObject>
- (void)operation:(CIMGFSimpleDownloadOperation*)operation didCompleteWithData:(NSData*)data;
- (void)operation:(CIMGFSimpleDownloadOperation*)operation didFailWithError:(NSError*)error;
@end
@interface CIMGFSimpleDownloadOperation : NSOperation
@property (nonatomic, assign) NSInteger statusCode;
- (id)initWithURLRequest:(NSURLRequest*)request andDelegate:(id<CIMGFSimpleDownloadDelegate>)delegate;
@end
Этот подкласс - самый простой способ загрузить что-то из URL-адреса. Постройте его с помощью NSURLRequest
и делегата. Он вернет успех или неудачу. Реализация только немного длиннее.
#import "CIMGFSimpleDownloadOperation.h"
@interface CIMGFSimpleDownloadOperation()
@property (nonatomic, retain) NSURLRequest *request;
@property (nonatomic, retain) NSMutableData *data;
@property (nonatomic, assign) id<CIMGFSimpleDownloadDelegate> delegate;
@end
@implementation CIMGFSimpleDownloadOperation
- (id)initWithURLRequest:(NSURLRequest*)request andDelegate:(id<CIMGFSimpleDownloadDelegate>)delegate
{
if (!(self = [super init])) return nil;
[self setDelegate:delegate];
[self setRequest:request];
return self;
}
- (void)dealloc
{
[self setDelegate:nil];
[self setRequest:nil];
[self setData:nil];
[super dealloc];
}
- (void)main
{
[NSURLConnection connectionWithRequest:[self request] delegate:self];
CFRunLoopRun();
}
- (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSHTTPURLResponse*)resp
{
[self setStatusCode:[resp statusCode]];
[self setData:[NSMutableData data]];
}
- (void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)newData
{
[[self data] appendData:newData];
}
- (void)connectionDidFinishLoading:(NSURLConnection*)connection
{
[[self delegate] operation:self didCompleteWithData:[self data]];
CFRunLoopStop(CFRunLoopGetCurrent());
}
- (void)connection:(NSURLConnection*)connection didFailWithError:(NSError*)error
{
[[self delegate] operation:self didFailWithError:error];
CFRunLoopStop(CFRunLoopGetCurrent());
}
@synthesize delegate;
@synthesize request;
@synthesize data;
@synthesize statusCode;
@end
Теперь этот класс ОЧЕНЬ многоразовый. Существуют другие методы делегатов для NSURLConnection, которые вы можете добавить в зависимости от ваших потребностей. NSURLConnection
может обрабатывать перенаправления, аутентификацию и т.д. Я сильно предлагаю вам ознакомиться с его документацией.
Здесь вы можете либо открутить CIMGFSimpleDownloadOperation
от вашего UITableViewController
, либо от другой части вашего приложения. Для этой демонстрации мы сделаем это в UITableViewController
. В зависимости от потребностей вашего приложения вы можете начать загрузку данных там, где это имеет смысл. В этом примере мы будем запускать его, когда появится представление.
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
NSURLRequest *request = ...;
CIMGFSimpleDownloadOperation *op = [[CIMGFSimpleDownloadOperation alloc] initWithURLRequest:request andDelegate:self];
[[NSOperationQueue mainQueue] addOperation:op];
[self setDownloadOperation:op]; //Hold onto a reference in case we want to cancel it
[op release], op = nil;
}
Теперь, когда появится представление, асинхронный вызов перейдет и загрузит содержимое URL-адреса. В этом коде, который либо пройдет, либо провалится. Первый сбой:
- (void)operation:(CIMGFSimpleDownloadOperation*)operation didFailWithError:(NSError*)error;
{
[self setDownloadOperation:nil];
NSLog(@"Failure to download: %@\n%@", [error localizedDescription], [error userInfo]);
}
При успехе нам нужно проанализировать данные, которые вернулись.
- (void)operation:(CIMGFSimpleDownloadOperation*)operation didCompleteWithData:(NSData*)data;
{
[self setDownloadOperation:nil];
NSLog(@"Download complete");
//1. Massage the data into whatever we want, Core Data, an array, whatever
//2. Update the UITableViewDataSource with the new data
//Note: We MIGHT be on a background thread here.
if ([NSThread isMainThread]) {
[[self tableView] reloadData];
} else {
dispatch_sync(dispatch_get_main_queue(), ^{
[[self tableView] reloadData];
});
}
}
И сделано. Еще несколько строк кода для написания, но он заменяет 13K + строк кода, который импортируется с ASI, что приводит к меньшему, более компактному и более быстрому приложению. И что еще более важно, это приложение, которое вы понимаете каждую строку кода.