Objective C - Vector of Objects not holding value between methods - objective-c

I am new to Objective-C, but I have a background in C++. I am working on the front end of a project and I am using apple's interface builder and xcode.
I have a vector that holds objects of a class, vector<myClass> myVector, in another class bigClass. myClass holds 15 NSMutableString* variables. I have another vector that is local the method I declare it in vector<myClass> vector2 that performs SQL queries to fetch the data I want. I then assign the values from vector2 to myVector.
I set each variable of like this:[myVector[i].a setString: vector2[i].a]; and myVector is declared in my head like this: #property vector<myClass> myVector
I am able to read the values that I put in myVector in the method, however when a different method of bigClass gets class I am only to get the first 3 variable's value and the fifth variable's value for each object of the class that is in myVector every other attempt to get the value of a variable that is not one of those four results in a seg fault. What am I doing wrong?

I set each variable of like this:[myVector[i].a setString: vector2[i].a];
vector is a C++ container and doesn't know anything about Objective-C memory management. Objective-C uses a reference counted memory model which you can read about in About Memory Management. Since vector doesn't follow the memory management rules, the objects you store in a vector will be deallocated as soon as no other objects are retaining them, i.e. at the end of the method in which you deallocate them.
Rather than trying to use vector to store your objects, use NSArray or NSMutableArray, both of which work perfectly with Objective-C objects.

Related

Objective-C setValue:forKey on c primitive types

I'm trying to teach myself objective-c using the big nerd ranch book, it is a really great book but certain aspects confuse me.
The current chapter is talking about using setValue:forKey function which I understand is a method defined in NSObject. The book says that you can use this on a c primitive like int or float and gives this example
I have a custom class called Appliance and in it is an integer instance variable called voltage that stores the voltage of the current appliance
I initialize a new appliance called a
appliance *a = [[appliance alloc]init];
[a setValue:[NSNumber numberWithInt:240] forKey:#"voltage"];
he then sets up a custom setter for voltage and logs the voltage when its called to prove it works
-(void)setVoltage:int(x) {
NSLog(#"setting voltage to %d",x);
voltage =x;
}
whats confusing me is that NSNumber numberWithInt returns a pointer to an NSNumber object thats stored on the heap correct? so then how does he log the integer stored in NSNumber using the %d token. I understand that would log an integer but isn't an object being passed in? furthermore I thought that since voltage was defined as an integer and not a pointer to something it couldn't hold the address to an object in its memory? or is NSNumber kind of forcing it to hold its memory address without actually having voltage being declared as a pointer?
sorry for the confusion this chapter basically kicked my butt.
The conversion between objects and scalar types is handled automatically by the Key-Value Coding methods. From the documentation:
The default implementations of valueForKey: and setValue:forKey:
provide support for automatic object wrapping of the non-object data
types, both scalars and structs.
Once valueForKey: has determined the specific accessor method or
instance variable that is used to supply the value for the specified
key, it examines the return type or the data type. If the value to be
returned is not an object, an NSNumber or NSValue object is created
for that value and returned in its place.
Similarly, setValue:forKey: determines the data type required by the
appropriate accessor or instance variable for the specified key. If
the data type is not an object, then the value is extracted from the
passed object using the appropriate -<type>Value method.
So in your case, intValue is applied automatically to the passed NSNumber
object, and the resulting integer is passed to setVoltage:.
You are correct in that you are creating an NSNumber instance and passing that. But, you're passing it to setValue:forKey: and it's doing some work for you. It's finding the appropriate setter method for voltage (setVoltage:), checking the data type and unboxing the number into an int before calling the setter.

Why do we create instances of classes in for loops?

So I am busy reading an objective-c book by Big Nerd Ranch. I'm on chapter 17 at the moment and managed to complete the required challenge at the end of the chapter. However, I just have two question that I would like to understand.
In the following bit of code - StockHolding is a custom class that has instance variables and the stocks (an array) points to three instances of stockholding with values setting its stock value and cost in dollars.
At first I tried to access the array to get the data from the objects it pointed to - but it seems that was not going to work as the array doesn't know what data its objects contain - just where they are in memory, right?
What I want to know is why was it necessary to create a new instance of stockholding (holdings) in this for loop to access those variables?
How does the new instance of stockholding know what the values of my stocks are?
for (StockHolding *holdings in stocks){
NSLog (# "%# has %d shares. Cost: $%.2f. Stock value: $%.2f", [holdings stockName],[holdings numberOfShares], [holdings costInDollars], [holdings valueInDollars]);
}
I'm going to try have a guess here to see if maybe I understand it a little better?
We create an instance of our class in the for loop so that we have access to its instance methods and variables - then we use the stocks array to get the variables from those objects in the array?
I may be completely off.. :(
Any advice?
stocks is an array having the objects of type StockHolding
So in order to access all values in the array and print the values.You need to get all the StockHolding instance inside the array we use for ...in method
note Here new instance is not created just new reference is made to the memory that is in the array so that you can access it and use it
Absolutely no new instances are created in the for loop at all. Since Objective-C objects are always represented as pointers, one variable != one instance. The holdings local variable inside the loop is assigned the pointer to the element of the array which is currently being enumerated upon each iteration. It's just a "reference" to an already existing object.
You're not creating new instances. You're iterating through existing instances.
Presumably in [CODE] you have created the objects and added them to the NSArray. The for loop just gives them to you one at a time. You name it holdings, do something with it, then grab the next.
That's all.
In Objective-C objects are typeless. Any message can be sent to any object. Code like [holdings stockName] means "send the message 'stockName' to the object 'holdings'". So the Objective-C runtime will inspect the object to see whether it implements that message. If so then it'll pass execution into the implementation.
The type of your object makes no difference to how processing will occur at runtime.
An NSArray stores anything that conforms to the NSObject protocol. So it can hold any old mix of objects. The same goes for the other collections.
Although you could write all your code without mentioning a single object type, you usually don't because if you say which type of objects you're dealing with then the compiler can perform some sanity checks. That makes you less likely to write broken code.
So the code:
for (StockHolding *holdings in stocks)
just means "let me do something to every object in the collection stocks and don't give me any compiler warnings when I treat them like instances of StockHolding". They may actually be other classes. If they're other classes that implement stockName, numberOfShares and the rest then your code will work perfectly.
So, for example:
NSMutableArray *arrayOfStrings = [NSMutableArray array];
[arrayOfStrings addObject:#"34.3"];
[arrayOfStrings addObject:#"19.8"];
float total;
for(NSNumber *number in arrayOfStrings)
{
total += [number floatValue];
}
Will compile and work perfectly — not because the strings are actually converted to numbers but because both classes implement floatValue to return a float. So each NSNumber *number is actually an NSString, and if you tried to call, say, isEqualToNumber: on any of them you'd raise an exception because that isn't implemented by strings. But telling the compiler you're going to act as if they're numbers means you don't get a warning for using floatValue and when the runtime spots that the object implements floatValue execution continues as usual.
The for..in loop is used for fast enumeration.
This
for (StockHolding *holdings in stocks)
{
}
won't create any new object, it takes one object from array and cast it to the specified type and assign it to the specified variable.
Means:
Takes the object from the array . Equivalent to [stocks objectAtIndex:index];
Assign it to the specified object. Equivalent to StockHolding *holdings = [stocks objectAtIndex:index];
Note that Only the reference is used (assignment) there is no object is allocated.

Writing struct into NSMutableArray

I have a game object which processed in two completely different places. In Contact Listener i check some conditions and if they occur i must save one or more portions of complex data. So i decided to use struct. For example:
struct SomeStruct
{
int value1;
int value2;
CGPoint value3;
b2Vec2 value4;
};
typedef SomeStruct SomeStruct;
In Game Scene i go through all game objects and if its the stack/array not empty, do some stuff and wipe it.
In Contact Listener it repeats from the beginning.
I must use this architecture because of strict order of execution (method must be called after other methods).
I suspect that i need something like vector or NSMutableArray (i think it will not work with struct), so vector may the the only way.
But don't understand how to achieve it. May you help me with some code/pseudocode or link to the book/article where i can found a solution?
Cocoa provides NSValue class for that purpose:
This creates an object that you can add to NSMutableArray:
NSValue *someObj = [NSValue valueWithBytes:&myStruct objCType:#encode(SomeStruct)];
You can use [someObj pointerValue] to access a void* representing the address of the structure that you put in NSValue.
There is a lot of solutions for this problem.
Don't use struct. An obj-c class is practically the same thing as a struct.
Use CFArray (CFArrayCreateMutable) and put it there as a pointer.
Use a C++ class with STL vector.
Use a C array (SomeStruct[]) and increase its length when you need it.
Use a classic implementation of a stack, with a linked list (every struct has a pointer to the next value).

Instance pointers in an array

I'm trying to save pointers of class instances into a mutable array. I'm able to do this but getting them back into use seems to be a problem. The next is how I inserted the pointers into the array:
Class *class = [Class new];
/* Do something with the instance */
[instanceArray addObject:class];
I am able to retrieve the wanted index from the array but when I try to access the instance variables etc. I only get compiler shouting at me or sometimes I get every variable as zero.
How am I supposed to get the instance back to use from the array? I know they are pointers but playing with them didn't seem to work.
Using addObject: the element is inserted at the end of the array. To retrieve it you can use -[NSArray objectAtIndex:]
Pointer arithmetic works in C since then your array is just a pointer to the first index, and array[i] is the same as *(array + i). In Objective-C this may still be done, however you're using an NSArray object. Now you don't have a pointer to the first object anymore, but to the instance of the class. To retrieve the objects stored in the array, you'll have to call the corresponding methods.
EDIT
So you are able to retrieve it from the array and then your pointer is not nil, so you do have access to the object. You know in Objective-C, all instance variables are private so you can't access them from outside. You'd have to declare them as properties first (please refer to the documentation). Also, when you declare a variable to be of type id, accessing a property with dot-syntax doesn't work, it will cause a compiler error.

How do you declare instance of the class in Objective C?

Let's imagine I have Fraction class. So, the correct way to create instance of it is:
Fraction *myFraction;
or
myFraction = Fraction;
or
myFraction = [Fraction new];
or something else?
In the book i'm studying the correct one is first, but it looks unreasonable to me. Why do we have to create a pointer for it? Why don't we make the real instance?
That first expression means - give me a pointer to the new instance of Fraction class, doesn't it?
The first declares a variable named myFraction of type Fraction *, but doesn't create anything, nor initialize myFraction. The second isn't valid. The third creates a new Fraction and assigns it to a previously declared variable named myFraction. Often in Objective-C, you'll declare and initialize a variable in a single statement:
Fraction *myFraction = [[Fraction alloc] init];
As for whether to use new or alloc followed by init, it's largely a matter of taste.
Variables for storing objects are pointers in part because Objective-C inherited C's call-by-value semantics. When one variable is assigned to another (such as when passing it to a function), the value will be copied. At best, this is inefficient for immutable objects. At worst, it leads to incorrect behavior. Pointers are a way around call-by-value and the copy-on-assign semantics: the value of a variable with pointer type is just the pointer. It can be copied without touching the target object. The cost for this is you need some form of memory management.
It would be a good idea to read Kernihan and Ritchie's "The C Programming Language" so you can get an idea about how variables are declared.
There are two modes of allocation in C and Obj-C and C++: manual and automatic.
Integers and floats and characters and such are generally automatically declared. They are created when the declaration passes (i.e. int i), and deleted when the scope they were created in goes away, i.e. when you exit the block in which they were declared. They're called automatics. (it's also possible to declare them "static" but for the purposes of this discussion regarding allocation, these are the same)
Objects are too complicated to pass around to functions, as function parameters are "pass by value", meaning that the parameter gets a copy of the value being passed in, instead of the variable itself. It'd take a huge amount of time to copy a whole object all the time.
For this reason, you want to just tell the various functions where they can find the object. Instead of handing off a copy of the object, you hand off a copy of the address of the object. The address is stored in an automatic with a type of pointer. (This is really just an integer, but it's size is dictated by the hardware and OS, so it needs to be a special type.)
The declaration Fraction *myFraction; means "myFraction is a pointer, and just so you know, it's going to point to a Fraction later."
This will automatically allocate the pointer, but not the whole Fraction. For that to happen, you must call alloc and init.
The big reason why you have this two step process is that since we typically want objects to stick around for a while, we don't want the system automatically killing them at the end of a function. We need them to persist. We create places to hang the object in our functions, but those hangers go away when they aren't needed. We don't want them taking the object with them.
Ultimately, you might make declarations like this:
Fraction *myFraction = [[Fraction alloc] initWithNumerator: 2 Denominator: 3];
which says: "Make me a Fraction, and set it to be 2/3, and then put the address of that Fraction into 'myFraction'."
Why do we have to create a pointer for it? Why don't we make the real instance?
In Objective-C, every object is pointer type. So, you need to use either new or alloc/init.
Fraction *myFraction = [ Fraction new ] ;
or
Fraction *myFraction = [ [Fraction alloc] init ] ;
And myFraction needs to be released.
That first expression means - give me a pointer to the new instance of Fraction class, doesn't it?
No, you are just declaring a pointer of type Fraction. And the second statement is not even valid.