float variable1, variable2;
float *variable1Pointer, *variable2Pointer;
float *activeNumberPointer;
}
float variable1 = 0;
float variable2 = 0;
float* variable1Pointer = &variable1;
float* variable2Pointer = &variable2;
float* activeNumberPointer = &variable1;
You cannot initialize instance variables within the class @interface
. What you've actually done here is declared two variables with each of these names.
For each name, one variable is an instance variable, declared within the {…} immediately following the @interface
, and the other is a global variable, declared elsewhere in the header. Specifically, you declared the global variables within the @interface
, but that doesn't matter: Global variables have no relation to any class or object, and you can put them within or without an @interface
with no objection from the compiler.
You initialized the global pointer variables to point to the global float
variables, but within the method bodies in the @implementation
, instance variables outrank global variables (instance variables are a narrower scope). Moreover, properties are always based on instance variables, not global variables. Therefore, within the methods, you're referring (through the properties) to the instance variables, not the global variables that you initialized.
Instance variables are initialized to nil
at instance creation time, so the value of the activeNumberPointer
instance variable is NULL
. Thus, statements like this one:
*self.activeNumberPointer = *self.activeNumberPointer * 10 + buttonClicked;
read from and write to a null pointer. That's the crash you're seeing.
It's also worth pointing out that this:
*self.activeNumberPointer = …
is not a property assignment, which is to say that it does not send self
a setActiveNumberPointer:
message; it is a property retrieval (sending a getter message), which returns the pointer. It's worth cutting the property to avoid confusing the two here.
The solution to the crash is to delete the global variables and initialize your instance variables in code. This is what the init
method is for. Override init
in the typical fashion and set up your initial pointer values there. Access these instance variables directly (without going through a property) throughout the class.
Better yet, dispense with the pointer juggling altogether. Use a BOOL
variable to select between them:
BOOL editingVariable2;
Test the Boolean value whenever you need to work with the active variable. In order to not write bothersome if-else statements every time that need comes up, you might encapsulate it into a method, named setValueOfActiveVariable:switchActive:
, which does what the first part says and then, if the argument to the second part is YES
, switches the active variable.
The Boolean-variable solution will eliminate the risk of accessing an uninitialized or no-longer-valid float
pointer from this class entirely.