Вандад Нахавандипур - iOS. Приемы программирования
• dateOfType: inURL: — поскольку мы собираемся просматривать у каждого URL, соответствующего NSDate, свойства трех типов, просто инкапсулируем в данный метод нужный для этого код. Метод будет принимать ключ и возвращать в URL дату, ассоциированную с конкретным ключом.
Ну вот и все. Вы научились перечислять каталоги и получать все элементы, расположенные в конкретном каталоге. Вы даже умеете получать различные атрибуты для разных элементов.
См. также
Разделы 12.1 и 12.2.
12.5. Удаление файлов и каталогов
Постановка задачи
Вы создали на диске ряд файлов и/или каталогов, и они вам больше не нужны. Вы хотите их удалить.
Решение
Используйте один из двух методов экземпляра, removeItemAtPath: error: или removeItemAtURL: error:, относящихся к классу NSFileManager. Первый метод принимает путь как строку, а второй — как URL.
Обсуждение
Пожалуй, удаление файлов и каталогов — одна из простейших операций, которые можно совершать в файловом менеджере. В iOS нужно обязательно помнить о том, где вы храните ваши файлы и каталоги, а когда хранить их больше не требуется — избавляться от файлов и каталогов. Например, создадим пять текстовых файлов в каталоге tmp/text, а когда закончим работу с ними — удалим эти файлы. Тем временем мы успеем перечислить содержимое каталога по состоянию до и после удаления. Будем делать перечень лишь для того, чтобы убедиться, что все работает правильно. Как вы помните, на момент установки приложения каталог tmp/ существует, а каталог tmp/text — нет. Поэтому для начала потребуется создать второй каталог. Как только закончим работу с файлами, удалим и сам каталог:
/* Создаем каталог по заданному пути */
— (void) createFolder:(NSString *)paramPath{
NSError *error = nil;
if ([self.fileManager createDirectoryAtPath: paramPath
withIntermediateDirectories: YES
attributes: nil
error:&error] == NO){
NSLog(@"Failed to create folder %@. Error = %@",
paramPath,
error);
}
}
/* Создаем пять файлов с расширением. txt в заданном каталоге, называем
их 1.txt, 2.txt и т. д. */
— (void) createFilesInFolder:(NSString *)paramPath{
/* Создаем 10 файлов */
for (NSUInteger counter = 0; counter < 5; counter++){
NSString *fileName = [NSString stringWithFormat:@"%lu.txt",
(unsigned long)counter+1];
NSString *path = [paramPath stringByAppendingPathComponent: fileName];
NSString *fileContents = [NSString stringWithFormat:@"Some text"];
NSError *error = nil;
if ([fileContents writeToFile: path
atomically: YES
encoding: NSUTF8StringEncoding
error:&error] == NO){
NSLog(@"Failed to save file to %@. Error = %@", path, error);
}
}
}
/* Перечисляем все файлы/каталоги, расположенные по заданному пути */
— (void) enumerateFilesInFolder:(NSString *)paramPath{
NSError *error = nil;
NSArray *contents = [self.fileManager contentsOfDirectoryAtPath: paramPath
error:&error];
if ([contents count] > 0 &&
error == nil){
NSLog(@"Contents of path %@ = n%@", paramPath, contents);
}
else if ([contents count] == 0 &&
error == nil){
NSLog(@"Contents of path %@ is empty!", paramPath);
}
else {
NSLog(@"Failed to enumerate path %@. Error = %@", paramPath, error);
}
}
/* Удаляем все файлы/каталоги по заданному пути */
— (void) deleteFilesInFolder:(NSString *)paramPath{
NSError *error = nil;
NSArray *contents = [self.fileManager contentsOfDirectoryAtPath: paramPath
error:&error];
if (error == nil){
error = nil;
for (NSString *fileName in contents){
/* У нас есть имя файла, но, чтобы удалить этот файл,
нужен полный путь к нему */
NSString *filePath = [paramPath
stringByAppendingPathComponent: fileName];
if ([self.fileManager removeItemAtPath: filePath
error:&error] == NO){
NSLog(@"Failed to remove item at path %@. Error = %@",
fileName,
error);
}
}
} else {
NSLog(@"Failed to enumerate path %@. Error = %@", paramPath, error);
}
}
/* Удаляем каталог, к которому ведет заданный путь*/
— (void) deleteFolder:(NSString *)paramPath{
NSError *error = nil;
if ([self.fileManager removeItemAtPath: paramPath error:&error] == NO){
NSLog(@"Failed to remove path %@. Error = %@", paramPath, error);
}
}
Не забывайте: свойство fileManager, которое мы используем в различных методах делегата нашего приложения, — это свойство самого делегата приложения, определяемое следующим образом:
#import «AppDelegate.h»
@interface AppDelegate ()
@property (nonatomic, strong) NSFileManager *fileManager;
@end
@implementation AppDelegate
<# Здесь находится остаток кода делегата приложения #>
В коде из этого примера объединено немало концепций, изученных в этой главе, — от перечисления до создания и удаления файлов. Все это вы здесь найдете. Как видите, с момента начала разработки приложения мы выполняем шесть основных задач, для каждой из которых существуют собственные методы.
1. Создание каталога tmp/txt. Мы знаем, что каталог tmp создается в iOS для каждого приложения, но подкаталог txt на момент установки приложения отсутствует.
2. Создание пяти файлов в каталоге tmp/txt.
3. Перечисление всех файлов в каталоге tmp/txt. Эту операцию нужно выполнить лишь для того, чтобы убедиться, что мы успешно создали в этом каталоге все пять файлов.
4. Удаление всех созданных файлов — собственно, именно эта операция интересовала нас в данном разделе.
5. Повторное перечисление файлов в каталоге tmp/txt. Эту операцию мы выполняем для того, чтобы убедиться, что механизм удаления сработал правильно.
6. Удаление каталога tmp/txt, ведь он нам больше не нужен. Повторюсь: обязательно учитывайте, какие файлы и каталоги вы создаете на диске. Дисковое пространство на дороге не валяется! Поэтому, если какие-то файлы или каталоги вам больше не нужны, обязательно их удаляйте.
См. также
Раздел 12.2.
12.6. Сохранение объектов в файлах
Постановка задачи
Вы добавили в ваш проект новый класс и теперь хотите сохранить этот объект на диск в виде файла, а потом в случае необходимости считать этот файл с диска.
Решение
Убедитесь, что ваш класс соответствует протоколу NSCoding, и реализуйте все необходимые методы данного протокола. Не волнуйтесь, я все подробно объясню в подразделе «Обсуждение» данного раздела.
Обсуждение
В iOS SDK есть два очень удобных класса, предназначенных именно для этой цели. Процесс, который будет описан в этом разделе, в программировании называется «маршалинг». Вот эти классы.
• NSKeyedArchiver — класс, позволяющий архивировать или сохранять содержимое объекта или дерева объектов по ключам. Каждое значение в классе, скажем каждое свойство, может быть сохранено в архиве с применением ключа, выбранного программистом. Вы получаете архивный файл (далее мы обсудим этот момент подробнее) и просто сохраняете ваши значения с ключами, которые выбраны вами же. Точно как в словаре!
• NSKeyedUnarchiver — этот класс работает совершенно противоположным образом. Он просто дает вам неархивированный словарь и предлагает считать значения в свойства вашего объекта.
Для обеспечения работы класса-архиватора и класса-деархиватора необходимо гарантировать, что те объекты, архивацию и деархивацию которых вы запрашиваете, соответствуют протоколу NSCoding. Начнем с простого класса Person. Вот заголовок этого класса:
#import <Foundation/Foundation.h>
@interface Person: NSObject <NSCoding>
@property (nonatomic, copy) NSString *firstName;
@property (nonatomic, copy) NSString *lastName;
@end
Теперь, если вы не напишете никакого кода реализации для этого класса и попытаетесь скомпилировать имеющийся код, то компилятор начнет забрасывать вас предупреждениями, сводящимися к следующему: класс не соответствует протоколу NSCoding и не реализует необходимые методы этого протокола. Вот какие методы нам потребуется реализовать:
• (void)encodeWithCoder:(NSCoder *)aCoder — от этого метода мы получаем сущность-кодировщик. Кодировщик используется точно так же, как словарь. Просто храните в нем значения с ключами на ваш выбор;
• (instancetype)initWithCoder:(NSCoder *)aDecoder; — этот метод вызывается в вашем классе всякий раз, когда вы пытаетесь разархивировать класс с помощью NSKeyedUnarchiver. Просто считывайте значения их экземпляра NSCoder, передаваемого этому методу.