2010-10-15 2 views
2

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

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

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]; 

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

Любые предложения будут очень полезными!

ответ

4

Вы не можете достоверно определить, где объект будет создан в памяти. 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; 

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

+0

Я действительно разместил этот вопрос и не получил много информации: http://stackoverflow.com/questions/3919127/how-should-nsdecimalnumbers-be-stored-in-the-database. Мне нужно сохранить nsdecimalnumber, потому что я работаю с валютами и не могу позволить себе потерять точность с двойными типами при записи в базу данных. Я сохраняю их как строки, а затем читаю их как nsdecimal число для суммирования в агрегатной функции. Следовательно, необходимо сохранить временную сумму переменных до сих пор. Думаю, с этим подходом мне придется выпустить и создать новую переменную для каждой строки ... – Ying

+0

... но я не уверен, как это сделать в противном случае. Я попробую этот подход и посмотрю, работает ли он. – Ying

1

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

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

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

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

Подробнее о том, зачем использовать NSDecimalNumber вообще, в отличие от целого числа C или двойного или любого другого?

+0

mark, аргументы sqlite3_aggregate_context в основном представляют собой размер памяти, который вы хотели бы выделить. Существует обратный вызов для очистки, поэтому я могу надежно очистить nsdecimalnumber. Я использую NSDecimalNumber, потому что я делаю расчеты на долю пенни и нуждаюсь в сохранении точности. – Ying