Класс NSValue
представляет собой простой контейнер для C данных и Objective-C и применяется для создания объектов из скалярных данных, для последующего их использования в коллекциях NSArray
, NSDictonary
, NSSet
и др., которые работают только с объектами. Объекты класса NSValue
способны сохранить любые скаларные данные, такие как, int
, float
, char
, указатели, структуры, id
. Созданный объект являются не изменяемыми (immutable) и может разместить только один элемент данных.
Класс принимает следующие протоколы:
- NSCoding
- NSCopying
Пример использования
Допустим у нас есть структура вида:
struct __coordinates {
float x;
float y;
};
typedef struct __coordinates coordinates;
и нам необходимо ее сохранить как элемент набора NSSet
.
Так как NSSet
может размещать только объекты, то создадим объект класса NSValue
в котором сохраним нашу структуру:
coordinates pointCoordinates = {20.0, 11.1};
NSValue *value = [[NSValue alloc ] initWithBytes: &pointCoordinates objCType:@encode(coordinates)];
NSSet *set = [NSSet setWithObject: value];
[value release];
NSLog(@"%@", set);
В примере мы создали объект класса NSValue
и инициализировали его с помощью метода initWithBytes:objCType:
. Метод принимает два аргумента, первый - указатель на размещаемые данные, второй - тип данных, в кодировке Objective-C, которую мы получили с помощью директивы @encode
. После того как объект был создан и инициализирован мы его разместили в наборе NSSet
Объекты класса NSValue
могу размещать данные с постоянной длинной, вы не можете сохранить в объекте C-строки, массивы переменной длины, структуры или другие данные неопределенной длинны. Следующий код не верен:
char *cstring = "This is a string.";
NSValue *value = [NSValue value:cstring withObjCType:@encode(char *)];
В этом фрагменте кода содержимое переменной cstring
интерпретируется как указатель на char, размер которого 4 байта (может меняться в зависимости от аппаратной архитектуры). В объекте будет сохранены только первые четыре байта строки, т.е. "This", что является не корректным. Правильный способ размещения таких данных - это передавать адрес указателя:
char *cstring = "This is a string.";
NSValue *value = [NSValue value:&cstring withObjCType:@encode(char**)];
Обратите внимание на то, что при создании объекта NSValue
данные не копируются, в объекте сохраняется только указатель на данные . Если вы создаете объект из данных, под которые память была выделена вручную, то вы не должны ее освобождать до тех пор пока существует объект NSValue
.
Создание и инициализация объектов
Методы создания объектов NSValue
:
+valueWithBytes:objCType:
- создает и возвращает объект NSValue
, который содержит указанные данные. Метод принимает два аргумента, первый - указатель на данные, второй - тип данных, в кодировке Objective-C, который возвращает директива @encode
int ivalue = 35;
NSValue *value = [NSValue valueWithBytes: &ivalue objCType:@encode(int)];
+value:withObjCType:
- метод делает то же, что и метод +valueWithBytes:objCType:
. Метод может быть удален в будущих версиях. Используйте вместо него +valueWithBytes:objCType:
+valueWithNonretainedObject:
- создает и возвращает объект NSValue
, который содержит указаный объект. Метод принимает один аргумент - сохраняемый объект. Этот метод полезен, если вы хотите добавить объект в коллекцию, но не хотите чтобы была создана сильная ссылка на него.
NSString *string = @"This is string";
NSValue *value = [NSValue valueWithNonretainedObject:string];
Использование данного метода эквивалентно:
NSValue *theValue = [NSValue value:&anObject withObjCType:@encode(void *)];
+valueWithPointer:
- создает и возвращает объект NSValue
, который содержит переданный указатель. Метод принимает один аргумент - указатель. Использование данного метода эквивалентно:
NSValue *theValue = [NSValue value:&aPointer withObjCType:@encode(void *)];
+valueWithRange:
- создает и возвращает объект NSValue
, который содержит переданную структур NSRange. Метод принимает один аргумент - структуру NSRange.
Следующий метод добавлен в класс категорией NSValueRangeExtensions
, описанной в заголовочном файле NSRange.h
:
NSRange range = {35, 8};
NSValue *value = [NSValue valueWithRange:range];
-initWithBytes:objCType:
- инициализирует созданный объект переданными данными. Метод принимает два аргумента, первый - указатель на данные, второй - тип данных в кодировке Objective-C, который возвращает директива @encode. Метод возвращает инициализированный объект NSValue
Следующие методы добавлены в класс категорией NSValueGeometryExtensions
, описанной в заголовочном файле NSGeometry.h
:
+valueWithRect:
- создает и возвращает объект NSValue
, который содержит переданную структур NSRect
. Метод принимает один аргумент - структуру NSRect.
NSRect rect =CGRectMake(10.0f, 10.0f, 100.0f, 25.0f);
NSValue *value = [NSValue valueWithRect:rect];
+valueWithSize:
- создает и возвращает объект NSValue
, который содержит переданную структур NSSize
. Метод принимает один аргумент - структуру NSSize
.
NSSize size =CGSizeMake(200.0f, 25.0f);
NSValue *value = [NSValue valueWithSize:size];
+valueWithPoint:
- создает и возвращает объект NSValue
, который содержит переданную структур NSPoint
. Метод принимает один аргумент - структуру NSPoint.
NSPoint point =CGPointMake(20.0f, 25.0f);
NSValue *value = [NSValue valueWithPoint:point];
Доступ к данным
Методы получения данных, хранимых в объекте класса NSValue
:
-getValue:
- копирует данные из объекта класса NSValue
в указанный буфер. Метод принимает один аргумент - указатель на буфер. Буфер должен иметь размер достаточный для размещения данных.
int ivalue = 35;
NSValue *value = [NSValue valueWithBytes: &ivalue objCType:@encode(int)];
int ivalue2;
[value getValue:(void *)&ivalue2];
NSLog(@"%d", ivalue2); // Выводит 35
-nonretainedObjectValue
- возвращает объект сохраненый в экземпляре NSValue
NSNumber *number = [NSNumber numberWithInt:35];
NSValue *value = [NSValue valueWithNonretainedObject:number];
NSNumber *number2 = [value nonretainedObjectValue];
-objCType
- возвращает C-строку с описанием типа данных хранимых в объекте класса NSValue
.
NSNumber *number = [NSNumber numberWithInt:35];
NSValue *value = [NSValue valueWithNonretainedObject:number];
const char *objCType = [value objCType];
NSLog(@"%s", objCType); // Выведет: ^v
-pointerValue
- возвращает указатель сохраненный в экземпляре NSValue
. Возвращаемый указатель приведен к void
void myCallback(void) {
NSLog(@"ok");
}
typedef void (*callbackPtr)(void);
NSValue *value = [NSValue valueWithPointer:myCallback];
callbackPtr callbackFunc = (callbackPtr)[value pointerValue];
callbackFunc();
Следующий метод добавлен в класс категорией NSValueRangeExtensions
, описанной в заголовочном файле NSRange.h
:
-rangeValue
- возвращает структуру NSRange сохраненную в объекте класса NSValue
Следующие методы добавлены в класс категорией NSValueGeometryExtensions
, описанной в заголовочном файле NSGeometry.h
:
-pointValue
- возвращает структуру NSPoint сохраненную в объекте класса NSValue
-rectValue
- возвращает структуру NSPoint сохраненную в объекте класса NSValue
-sizeValue
- возвращает структуру NSSize сохраненную в объекте класса NSValue
Сравнение объектов
Для сравнения объектов класса NSValue
используется метод isEqualToValue:
. Метод сравнивает текущий объект NSValue
с переданным. Метод возвращает YES
, если объекты равны, иначе NO
. Метод сранивает классы объектов, данные сохраненные в объектах и их типы
NSNumber *number = [NSNumber numberWithInt:35];
NSValue *value = [NSValue valueWithNonretainedObject:number];
NSNumber *number2 = [NSNumber numberWithInt:46];
NSValue *value2 = [NSValue valueWithNonretainedObject:number2];
if([value isEqualToValue:value2]) {
NSLog(@"Объекты равны");
} else {
NSLog(@"Объекты не равны");
}