antonio's blog

antonio's blog


Блог о всяком разном, связанном с разработкой ПО. Пишу редко, когда есть время и желание.

antonio
Author

Share


Tags


Класс NSValue

antonioantonio

Класс NSValue представляет собой простой контейнер для C данных и Objective-C и применяется для создания объектов из скалярных данных, для последующего их использования в коллекциях NSArray, NSDictonary, NSSet и др., которые работают только с объектами. Объекты класса NSValue способны сохранить любые скаларные данные, такие как, int, float, char, указатели, структуры, id. Созданный объект являются не изменяемыми (immutable) и может разместить только один элемент данных.

Класс принимает следующие протоколы:

Пример использования

Допустим у нас есть структура вида:

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(@"Объекты не равны");
}
antonio
Author

antonio

Comments