#iphone #objective-c #ios #cocoa-touch #nsdocumentdirectory
#iPhone #objective-c #iOS #cocoa-touch #nsdocumentdirectory
Вопрос:
У меня есть класс с именем XYZ, наследуемый от NSObject, и массив, который содержит объекты XYZ. Мне нужно записать этот массив в файл plist в каталоге documents. После попытки [array writeToFile ….] я обнаружил, что writeToFile завершается с ошибкой, поскольку массив содержит пользовательские объекты класса XYZ.
Возможное решение этой проблемы — преобразовать объекты в NSData. Каковы различные способы достижения этого?? Я обнаружил, что NSCoding подходит, но не могу понять, как его использовать. Любая помощь будет высоко оценена.
Ответ №1:
В блоге Рэя Вендерлиха есть очень хороший учебник, в котором объясняется, как работать с NSCoding.
Просто вам просто нужно реализовать методы *-(void)encodeWithCoder: (NSCoder )encode и *-(id)initWithCoder:(NSCoder )decoder в вашем объекте, который уважает протокол NSCoding подобным образом:
// Header
@interface AnObject: NSObject <NSCoding>
// Implementation
- (void) encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:ivar1 forKey:@"ivar1"];
[encoder encodeFloat:ivar2 forKey:@"ivar2"];
}
- (id)initWithCoder:(NSCoder *)decoder {
self = [super initWithCoder:coder];
ivar1 = [[coder decodeObjectForKey:@"ivar1"] retain];
ivar2 = [[coder decodeObjectForKey:@"ivar2"] retain];
return self;
}
Вы также можете ознакомиться с официальной документацией здесь.
Комментарии:
1. Я получаю утечку памяти в декодере — (id)initWithCoder: (NSCoder *) в каждой строке. Знаете ли вы, что может быть возможной причиной? (Мои iVar1 и ivar2 являются строками)
2. Вы освободили их с помощью метода dealloc?
3. @YannickL.hello, я хочу спросить,
NSCoding
стоит ли это того или лучше остановиться наNSDictionary
коде, который вы написали выше, например? Есть ли какие-либо критерии для выбора или это просто дело вкуса? Если да, то как насчет затрат на ресурсы, что дешевле? Возможно, это тема для целого вопроса, но в теоретическом плане это тихо, поэтому я буду очень благодарен, если вы ответите здесь или отредактируете свой вопрос. Спасибо.4. @flinth Я думаю, что лучше использовать
NSCoding
протокол, чемNSDictionary
с точки зрения шаблона проектирования. Использование aNSDictionary
подразумевает создание нового объекта, и у вас нет полномочий по сериализации. Для проверки производительности вы можете проверить эту ссылку: developer.apple.com/library/mac/documentation/Cocoa/Conceptual /… .
Ответ №2:
После реализации encodeWithCoder:
и initWithCoder:
для пользовательского класса вот как записать и прочитать:
Записать:
NSError *error;
NSData* archiveData = [NSKeyedArchiver archivedDataWithRootObject:yourClassInstance];
[archiveData writeToFile:filePath options:NSDataWritingAtomic error:amp;error];
Читать:
NSData *archiveData = [NSData dataWithContentsOfFile:filePath];
YourClass *yourClassInstance = (NSArray*)[NSKeyedUnarchiver unarchiveObjectWithData:archiveData];
Комментарии:
1. Как это сделать для удаления определенного объекта?
Ответ №3:
Соответствие вашего класса XYZ протоколу NSCoding действительно очень подходит для того, что вы пытаетесь сделать. Для этого добавьте протокол NSCoding в объявление интерфейса вашего класса:
@interface XYZ <NSCoding>
Затем вам необходимо реализовать encodeWithCoder: и initWithCoder: в вашей реализации. «Кодировать с помощью coder» означает «взять текущее состояние вашего объекта и упаковать его в универсальный объект, называемый «encoder»». «Инициализация с помощью coder» означает «учитывая уже упакованный объект encoder, настройте себя с использованием данных, упакованных в encoder». В обоих этих методах ‘encoder’ будет экземпляром NSCoder, который имеет довольно простой интерфейс для кодирования («упаковки») и декодирования («распаковки») базовых типов.
Вот пример реализации:
@implementation XYZ
- (id)initWithCoder:(NSCoder*)encoder
{
self = [self init];
if (self)
{
self.myIntProperty = [encoder decodeIntForKey:@"myInt"];
}
return self;
}
– (void)encodeWithCoder:(NSCoder*)decoder
{
[decoder encodeInt:self.myIntProperty forKey:@"myInt"];
}
@end
Ответ №4:
Вам нужно реализовать два метода: -initWithCoder:
и -encodeWithCoder:
. Прочитайте NSCoding
документы; это довольно простые методы. По сути, вы хотите закодировать / декодировать переменные вашего экземпляра с помощью ключа, соответствующего его имени.
Ответ №5:
Это довольно просто. Для данного класса Foo
:
#import <Foundation/Foundation.h>
@interface Foo : NSObject <NSCoding> {
NSArray* bar_;
NSUInteger baz_;
}
@property (nonatomic, retain) NSArray *bar;
@property (nonatomic, assign) NSUInteger baz;
@end
Все, что вам нужно сделать, чтобы соответствовать NSCoding
протоколу, — это реализовать сообщения initWithCoder:
и decodeWithCoder
:
#import "Foo.h"
@implementation Foo
@synthesize bar = bar_;
@synthesize baz = baz_;
#pragma mark - NSCoding
- (void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:self.bar forKey:@"bar"];
[encoder encodeInteger:self.baz forKey:@"baz"];
}
- (id)initWithCoder:(NSCoder *)decoder {
if ((self = [super init])) {
self.bar = [decoder decodeObjectForKey:@"bar"];
self.baz = [decoder decodeIntegerForKey:@"baz"];
}
return self;
}
- (void) dealloc {
[bar_ release];
[super dealloc];
}
@end