Хранение необъектных данных

Поговорим о взаимодействии Objective-C и C. В Objective-C есть простые и удобные классы для хранения данных (NSDictionary, NSArray и другие). Единственное ограничение – хранить в них можно только объекты Objective-C. Для типов C нужны “обертки”. Вот про них мы и поговорим.

Числовые типы данных и enum мы можем “оборачивать” в NSNumber. Последние обновления Xcode позволяют использовать @-синтаксис:

NSNumber *intObj = @(10);
NSNumber *floatObj = @(1.5f);
NSNumber *boolObj = @YES; // or @(YES)
NSNumber *enumObj = @(UIImageOrientationUp);

Для хранения пустого объекта существует специальный класс NSNull.

NSDictionary *dict = @{ @"nullObj" : [NSNull null] };

Как же быть с C-структурами и другими необъектными типами данных?
Для решения этой задачи существует класс NSValue. С помощью этого класса можно хранить любой набор байт с сохранением информации о типе.
Объект класса NSValue – является обычным объектом Objective-C, он поддерживает протоколы NSCoding и NSCopying, что означает, что он поддерживает создание копий и сохранение объектов в виде ключ-значение. Работа с NSValue делится на две задачи – сохранение и извлечение данных.

Сохранение данных

typedef struct {
    float r;
    float i;
} ComplexNumber;

ComplexNumber complexNumber;
complexNumber.r = 1.0f;
complexNumber.i = 2.0f;

NSValue *value = [NSValue valueWithBytes:&complexNumber objCType:@encode(ComplexNumber)];
NSDictionary *dict = @{ @"complexNumber" : value };

Метод +valueWithBytes:objCType: принимает указатель на область памяти, где хранятся данные, а также описание типа данных.
Директива @encode создает представление типа данных, которое можно сохранить вместе со значением. Параметром директивы нужно писать сам тип данных. Сравнивать представления типа можно с помощью strcmp – хранится он как обычная C-строка.

Извлечение данных

NSValue *extractedValue = dict[@"complexNumber];

if (!strcmp(extractedValue objCType], @encode(ComplexNumber))
{
    ComplexNumber extractedComplexNumber;
    [extractedValue getValue:&extractedComplexNumber];
    // ...
}

Вспомогательные методы, реализованные в UIKit
Для некоторых часто используемых структур в UIKit определены вспомогательные методы для NSValue.

+ (NSValue *)valueWithCGPoint:(CGPoint)point;
+ (NSValue *)valueWithCGSize:(CGSize)size;
+ (NSValue *)valueWithCGRect:(CGRect)rect;
+ (NSValue *)valueWithCGAffineTransform:(CGAffineTransform)transform;
+ (NSValue *)valueWithUIEdgeInsets:(UIEdgeInsets)insets;
+ (NSValue *)valueWithUIOffset:(UIOffset)insets;

- (CGPoint)CGPointValue;
- (CGSize)CGSizeValue;
- (CGRect)CGRectValue;
- (CGAffineTransform)CGAffineTransformValue;
- (UIEdgeInsets)UIEdgeInsetsValue;
- (UIOffset)UIOffsetValue;

Дополнительно стоит почитать документацию по NSValue, заметку о правильном использовании NSValue, статью о кодировании типов данных.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s