как инициализировать объект (подкласс NSObject) по определенному адресу - PullRequest
2 голосов
/ 16 октября 2010

Привет! Мне нужно инициализировать NSObject в определенном месте, которое я укажу (например, через указатель void *).Для небольшого контекста я пишу агрегатную функцию sqlite3.Чтобы сохранить временные результаты от этой функции, я должен вызвать функцию sqlite3_aggregate_context, которая выделяет мне блок памяти.Я хочу сохранить NSDecimalNumber в этом месте.

До сих пор я пробовал два подхода:

1) allocWithZone, выполнив:

void *location = sqlite3_aggregate_context(...); //returns a block of allocated memory of a certain size

NSDecimalNumber *num = [[NSDecimalNumber allocWithZone:NSZoneFromPointer(location)] initWithInt:0];

Это не работаетпотому что NSZoneFromPointer возвращает ноль.Документы говорят, что аргументами этой функции должен быть ранее выделенный указатель, которым он и является.Я не знаю, означает ли это выделение с помощью NSZoneMalloc / Calloc.

2)

id location = sqlite3_aggregate_function(...);

location = [[NSDecimalNumber alloc] init];

, но это вызывает некоторую бесконечную рекурсию при освобождении памяти ... не уверен, в чем дело,Снимок экрана здесь: http://dl.dropbox.com/u/3002073/Public%20Sync/sqlitefunctionissue.png

Любые предложения будут с благодарностью!

Ответы [ 2 ]

4 голосов
/ 16 октября 2010

Вы не можете реально определить, где объект будет создан в памяти.NSZoneFromPointer не работает для вас, потому что API sqlite3 не использует зоны для выделения своих ресурсов.

Если вы хотите иметь возможность передавать определенное местоположение, вы должны сделать это с помощью указателя на объект (так что выхранение указателя на указатель в принципе).Затем вы можете прочитать эту информацию из вашей агрегатной функции и соответственно обновить ее.Просто убедитесь, что вы не просто освободите свой объект в конце вызова, не позаботившись об его освобождении (или у вас будет утечка).

Так, например, вы можете сделатьчто-то вроде:

NSDecimalNumber** numberLocation = sqlite3_aggregate_context(...);
*numberLocation = [[NSDecimalNumber alloc] initWithDouble:25.0];

Теперь у вас есть ссылка на ваш объект, хранящийся в вашей специальной области памяти, и вы можете получить к ней доступ в любое время:

NSDecimalNumber* storedNumber = *numberLocation;
NSDecimalNumber* computedNumber = [[NSDecimalNumber alloc] initWithDouble:[storedNumber doubleValue] * someComputation];
[storedNumber autorelease];
*numberLocation = computedNumber;

С другой стороны, я согласенОтметка;может быть, этот неизменный класс не лучшее решение вашей проблемы?

1 голос
/ 16 октября 2010

Ваша первая версия просто не будет работать.NSZoneFromPointer работает только при передаче указателя, выделенного из зоны.Он используется для того, чтобы вы могли выделить объект из той же зоны, что и какой-либо другой объект.

Вторая версия должна работать, хотя трудно сказать без дополнительного контекста.Что вы передаете sqlite3_aggregate_context в качестве размера памяти для выделения?И как вы освобождаете эту память, когда закончите?

Вторая версия не работает, потому что тип "id" на самом деле является указателем, поэтому вы указываете на возвращаемую памятьс помощью sqlite3_aggregate_context (), затем указывая его на память, возвращаемую alloc / init.Вам действительно нужно хранить указатель на указатель, чтобы заставить его работать так, как вы хотите.

NSDecimalNumber является неизменяемым классом, поэтому вызов -init для него (в отличие от -initWithDecimal :) просто выполняетсячтобы получить значение по умолчанию.Какой тип кода вы используете для замены NSNumber новыми значениями по мере выполнения функции?

Более конкретно, зачем вообще использовать NSDecimalNumber, а не целое число C, или double, или что-то еще?

...