Помогите с указателями в какао - PullRequest
0 голосов
/ 11 июня 2010

Я пытаюсь сделать простое приложение калькулятора в какао. Программа зависает, когда я нажимаю на одну из моих кнопок. Я думаю, что отследил проблему до той части моего контроллера, которая добавляет цифру к концу числа, отображаемого в данный момент на дисплее:

- (void)updateNumber:(int)buttonClicked{
 *self.activeNumberPointer = *self.activeNumberPointer * 10 + buttonClicked;
 [outputField setFloatValue:*self.activeNumberPointer];
}

Я использовал указатель на «activeNumber», чтобы моя программа могла сказать, какой из двух операндов я редактирую.

Любая помощь приветствуется, спасибо.

(редактировать): Моя декларация и @property:

//CalculatorController.h
@interface CalculatorController : NSObject {
    IBOutlet NSTextField *outputField;
    float variable1, variable2;
    float *variable1Pointer, *variable2Pointer;
    float *activeNumberPointer;
}

float variable1 = 0;
float variable2 = 0;
float* variable1Pointer = &variable1;
float* variable2Pointer = &variable2;
float* activeNumberPointer = &variable1;

@property (readwrite) float variable1, variable2;
@property (readwrite) float *vairable1Pointer, *variable2Pointer;
@property (readwrite) float *activeNumberPointer;

...

Полный файл XCode доступен здесь: http://rapidshare.com/files/397664243/Calculator_2.zip (К сведению: я фактически использовал leftNumberValue и rightNumberValue вместо variable1 и variable2 в проекте) Поскольку я новичок в Objective-C и XCode, приветствуется любая общая критика.

Ответы [ 3 ]

0 голосов
/ 11 июня 2010

Непонятно, как указатели в target-C с простыми типами переменных, и не совсем понятно, зачем вы вообще используете указатели.

*self.activeNumberPointer = *self.activeNumberPointer * 10 + buttonClicked;

Вы используете неправильный оператор * (разыменование) в левой части этого выражения. Выполняя задание, вы не хотите разыменовывать так.

http://www.cplusplus.com/doc/tutorial/pointers/

Это ссылка на C ++, но хорошее начало для логики указателей.

Я бы, вероятно, использовал NSMutableArray или какую-либо подобную конструкцию (вы хотите сохранить больше, чем просто два числа, верно?), И использовал бы целочисленный индекс, чтобы указать на "текущее" число, которое вы отображаете на экране. 1011 *

Кроме того, я не знаю, опечатка ли это, или какой-то недостающий код и т. Д., Но ...

@interface CalculatorController : NSObject {
    IBOutlet NSTextField *outputField;
    float variable1, variable2;
    float *variable1Pointer, *variable2Pointer;
    float *activeNumberPointer;
}

float variable1 = 0;
float variable2 = 0;
float* variable1Pointer = &variable1;
float* variable2Pointer = &variable2;
float* activeNumberPointer = &variable1;

... вы, кажется, объявляете все указанные выше переменные в определении интерфейса как ivars - или переменные экземпляра, которые непосредственно связаны с вашим CalculatorController, а затем вне определения интерфейса вы переделываете их как переменные GLOBAL. Нет необходимости использовать второй набор определений в вашей реализации

Если вы хотите инициализировать эти переменные экземпляра, обычно есть функция с именем -init, которую вы можете переопределить (так как вы создаете подкласс NSObject), и она похожа на конструктор в других языках. Это будет жить в вашем файле реализации (.m или .mm). Это может выглядеть примерно так:

-(CalculatorController *)init{
   if( self = [super init] ){
       // Do your initialization here etc
   }
   return self;
}

Существует также другая функция -awakeFromNib, которую вы можете переопределить, если она создается в файле XIB / NIB как часть определения вашего пользовательского интерфейса. Функция -awakeFromNib вызывается после загрузки класса и пользовательского интерфейса.

Редактировать: чтобы быть ясным о бизнесе указателя .... self.activeNumberPointer = * self.activeNumberPointer * 10 + buttonClicked;

Это верно. Вы НЕ используете оператор разыменования слева, но вы действительно используете оператор разыменования справа, так как вы ищете значение self.activeNumberPointer.

Josh

0 голосов
/ 11 июня 2010
    float variable1, variable2;
    float *variable1Pointer, *variable2Pointer;
    float *activeNumberPointer;
}

float variable1 = 0;
float variable2 = 0;
float* variable1Pointer = &variable1;
float* variable2Pointer = &variable2;
float* activeNumberPointer = &variable1;

Вы не можете инициализировать переменные экземпляра в классе @interface. То, что вы на самом деле здесь сделали, объявили две переменные с каждым из этих имен.

Для каждого имени одна переменная является переменной экземпляра, объявленной в {…} сразу после @interface, а другая - глобальной переменной, объявленной в другом месте заголовка. В частности, вы объявили глобальные переменные в @interface, но это не имеет значения: глобальные переменные не имеют никакого отношения к какому-либо классу или объекту, и вы можете поместить их в @interface или без него без возражений компилятора.

Вы инициализировали переменные глобального указателя так, чтобы они указывали на глобальные переменные float, но внутри тела метода в @implementation переменные экземпляра опережают глобальные переменные (переменные экземпляра имеют более узкую область действия). Более того, свойства всегда основаны на переменных экземпляра, а не на глобальных переменных. Поэтому в методах вы ссылаетесь (через свойства) на переменные экземпляра, а не на глобальные переменные, которые вы инициализировали.

Переменные экземпляра инициализируются в nil во время создания экземпляра, поэтому значение переменной экземпляра activeNumberPointer равно NULL. Таким образом, утверждения, подобные этому:

*self.activeNumberPointer = *self.activeNumberPointer * 10 + buttonClicked;

чтение и запись в нулевой указатель. Это авария, которую вы видите.

Также стоит отметить, что это:

*self.activeNumberPointer = …

не является присваиванием свойства, то есть оно не отправляет self a setActiveNumberPointer: сообщение; это свойство retrieval (отправка получающего сообщения), которое возвращает указатель. Стоит сократить собственность, чтобы не перепутать их здесь.

Решение проблемы заключается в удалении глобальных переменных и инициализации переменных вашего экземпляра в коде. Для этого и используется метод init. Переопределите init в обычным способом и установите там свои начальные значения указателя. Доступ к этим переменным экземпляра напрямую (без прохождения через свойство) по всему классу.

Еще лучше, вообще не обходиться с манипулированием указателем. Используйте переменную BOOL для выбора между ними:

BOOL editingVariable2;

Проверяйте логическое значение всякий раз, когда вам нужно работать с активной переменной. Чтобы не писать надоедливые операторы if-else каждый раз, когда возникает необходимость, вы можете инкапсулировать их в метод с именем setValueOfActiveVariable:switchActive:, который выполняет то, что говорит первая часть, и затем, если аргумент второй части равен * 1044. *, переключает активную переменную.

Решение с булевыми переменными исключит риск полного доступа к неинициализированному или недействительному указателю float из этого класса.

0 голосов
/ 11 июня 2010

Вам не нужен * перед self.activeNumberPointer или activeNumberPointer, когда вы их используете, только когда вы их определяете.Попробуйте:

- (void)updateNumber:(int)buttonClicked{
 self.activeNumberPointer = self.activeNumberPointer * 10 + buttonClicked;
 [outputField setFloatValue:activeNumberPointer];
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...