Разъяснение NSData и встроенных указателей

В документации Apple относительно NSData говорится

NSData и его изменяемый подкласс NSMutableData предоставляют объекты данных, объектно-ориентированные оболочки для байтовых буферов. Объекты данных позволяют простым выделенным буферам (то есть данным без встроенных указателей) вести себя как объекты Foundation.

Что они подразумевают под «встроенными указателями»? Насколько я понимаю, как только вы помещаете в него байты, он понятия не имеет, что это такое, если вы не декодируете его на уровне приложения. Кто-нибудь знает, о чем они говорят?


person mskw    schedule 09.09.2012    source источник


Ответы (2)


Целью NSData является предоставление средств для очистки выделенного буфера данных, когда он больше не нужен, т. е. когда счетчик ссылок NSData становится равным 0. В общем случае данные выделяются с помощью malloc, а NSData использует соответствующий вызов чтобы бесплатно освободить данные. Это накладывает ограничение на характер байтовых данных. Это должны быть обычные старые данные. Если данные представляют собой структуру, содержащую поле, указывающее на другую область памяти, выделенную с помощью malloc (встроенный указатель), встроенный указатель никогда не будет освобожден объектом NSData, что приведет к утечке памяти. Например:

typedef struct Point {
    CGFloat x,
    CGFloat y
} Point;

typedef struct LineSegment {
    Point* start;
    Point* end;
} LineSegment;

// point does not contain any embedded pointers (i.e., it is Plain Old Data)
Point* point = malloc(sizeof(Point));
// pointData will call free on point to deallocate the memory allocated by malloc
NSData* pointData = [NSData dataWithBytesNoCopy:point length:sizeof(Point)];

Point* start = malloc(sizeof(Point));
Point* end = malloc(sizeof(Point));

// line contains two embedded pointers to start and end. Calling free on line
// without calling free on start and end will leak start and end 
LineSegment* line = malloc(sizeof(LineSegment));
line->start = start;
line->end = end;

// start and end will be leaked!
NSData* lineData = [NSData dataWithBytesNoCopy:&line length:sizeof(LineSegment)];

// Try this instead. Line is now Plain Old Data
typedef struct Line {
    Point start;
    Point end;
} Line;

// anotherLine does not contain any embedded pointers and can safely be used with
// NSData. A single call to free will deallocate all memory allocated for anotherLine
// with malloc
Line* anotherLine = malloc(sizeof(Line));

NSData* anotherLineData = [NSData dataWithBytesNoCopy:&anotherLine
                                               length:sizeof(Line)];
person Brian Coleman    schedule 09.09.2012
comment
Очень полезный ответ. Теперь я понимаю, плюс на другом уровне, чем у Тило! Я также хочу поблагодарить Тило за быстрый и хороший ответ. - person mskw; 10.09.2012

Да, это то, о чем они говорят. NSData — это чистые сериализованные данные, массив байтов. Любая структура должна быть добавлена ​​в код приложения, и ссылки на внешнюю память не имеют особого смысла (объекты данных, такие как NSData, должны быть автономными или, по крайней мере, ссылаться на вещи таким образом, который не зависит от конкретных мест памяти, поэтому что он транспортабельный). Они просто хотят, чтобы это было ясно.

person Thilo    schedule 09.09.2012