ПРОГРАММИРОВАНИЕ ПОД IPHONE, IPAD OBJECTIVE-C часть 2

Закачка больших файлов

Совсем недавно мы рассматривали пример того как получать данные с интернета (Закачка данных). Это хороший пример и он стабильно работает до тех пор, пока объем этих данных не будет превышать размер свободной оперативной памяти устройтсва. Если присмотреться — то полученные данные мы храним в переменной, которая в свою очередь, не записывается на флеш-память. Проще говоря, у нас не получится скачать полноценный фильм для дальнейшего его открытия в приложении. Наше приложение просто «упадет». Для выхода с этой ситуации нам следует хранить полученные данные не в переменной, а в файле. Для этого исправим код вышеупомянутого примера.

 

В первую очередь исправим интерфейс класса ViewController:

 

<code data-result="[object Object]">#import &lt;UIKit/UIKit.h&gt;

#define DOCUMENTS [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]

@interface ViewController : UIViewController

@property (nonatomic, retain) IBOutlet UIImageView *imageView;
@property (nonatomic, retain) NSFileHandle *file;
@property (nonatomic, retain) NSString *filePath;

- (IBAction)complexDownload;

@end</code>

 

Поскольку хранить данные мы будем в файле — я воспользовался дефайном DOCUMENTS с урока Сохранение данных в файлы. Переменная file класса NSFileHandle нам нужна будет чтобы обращаться к файлу и дописывать в него данные, а в filePath будем хранить к нему путь. Метод easyDownload я убрал, поскольку мы его не рассматриваем (не забудьте убрать соответствующую кнопку с интерфейса).

 

Теперь посмотрим как изменилась реализация класса ViewController. Для начала нам нужно синтезировать методы для новых переменных. Затем в методе viewDidLoad установим путь где будет храниться наш файл.

 

<code data-result="[object Object]">- (void)viewDidLoad
{
    [super viewDidLoad];

    self.filePath = [DOCUMENTS stringByAppendingPathComponent:@"logo.png"];
}</code>

 

Затем следует complexDownload:

 

<code data-result="[object Object]">- (IBAction)complexDownload {
    [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
    NSURL *url = [NSURL URLWithString:@"http://www.imaladec.net/img/logo.png"];
    NSURLRequest *theRequest=[NSURLRequest requestWithURL:url
                                              cachePolicy:NSURLRequestUseProtocolCachePolicy
                                          timeoutInterval:60.0];

    NSURLConnection *theConnection = [NSURLConnection connectionWithRequest:theRequest delegate:self];
    if (theConnection) {
        [[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil];
        self.file = [NSFileHandle fileHandleForUpdatingAtPath:filePath];
    } else {
        [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
        NSLog(@"Connection failed");
    }
}</code>

 

В этом случае мы вместо инициализации переменной для харнения данных — создаем файл и подготавливаем file для добавления в нее порций данных.

 

В методе didReceiveData мы добавляем к нашему файлу полученые данные:

 

<code data-result="[object Object]">- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data 
{
    [file seekToEndOfFile]; 

    NSMutableData *receivedData = [NSMutableData data];
    [receivedData setLength:0];
    [receivedData appendData:data];

    [file writeData:receivedData];
}</code>

 

Важным моменто в работе с файлами является их закрытие. Делать это нужно после получения всех данных, в нашем случае, это в методе connectionDidFinishLoading:

 

<code data-result="[object Object]">- (void)connectionDidFinishLoading:(NSURLConnection *)connection 
{
    [file closeFile];
    UIImage *image = [UIImage imageWithContentsOfFile:filePath];
    imageView.image = image;
    [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
}</code>

 

После закрытия мы читаем файл и передаем изображение нашему UIImageView.

 

В случае возникновения какой либо ошибки файл следует так же закрыть:

 

<code data-result="[object Object]">- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error 
{
    [file closeFile];
    NSLog(@"%@", error);
    [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
}</code>

 

Как видите, работа с большими файлами отличается лишь работой с классом NSFileHandle и начальными знаниями файловой системы iOS.

 

Исходный код проекта можно скачать здесь.