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.
Related
I'm confused by the code, below. Before I added the mutableCopy line, it didn't work. After I added the line, it did.
Why isn't aDict mutable to begin with? I declared aDict as an NSMutableDictionary.
- (void) myRoutine: (NSMutableDictionary *) dictOfDicts
{
NSMutableDictionary * aDict = dictOfDicts[dictOfDictsKey];
int data = [aDict[aDictKey] intValue];
aDict = [aDict mutableCopy];
aDict[aDictKey] = #(++data);
}
The declaration of dictOfDicts says it's a pointer to a mutable dictionary. However, it does not use Objective-C generics syntax to say what the types of the keys or values are. So, the most we (and the compiler) can assume is that the keys are id<NSCopying> and the values are id, completely generic object pointers.
You then initialize your aDict variable with a value obtained from dictOfDicts. You've declared that aDict is also a pointer to a mutable dictionary. That's its "static type", but the real type of the object it points to is determined at runtime by whatever object is held in dictOfDicts under that key. It might be a mutable dictionary or it might be something else. It compiles just find because the compiler can't know what type of object that value is.
However, the real type (a.k.a. "dynamic type") of the object governs what operations succeed or fail/crash/whatever. In your case, it sounds like it's an immutable dictionary. So, when you attempt to mutate it, "it didn't work" (you don't specify what actually happened).
You make a mutable copy and you're allowed to mutate that. However, that's now a separate object that the one in dictOfDicts. So, you're not modifying what you think you are.
The solution is to put mutable dictionaries into dictOfDicts in the first place. Or, even better, put objects of a custom class of your own design into it, and operate on real properties.
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.
I am trying to create a mutable array in objetive c to hold references to objects. The objects in the array are regularly updated through user interaction and i want the array to automatically reflect changes made to the objects as they occur. Does anyone know if there is a way to do this? Perhaps store pointers to the objects instead of the objects themselves in the array? Any help would be much appreciated
Thanks in advance
Edit: I should mention that the objects are not exactly being updated in the strict sense of the word. They are being reinitialized. For ex if i had a controller:
MyController = [MyController alloc] initWith.....]]
the above call is made again with different init parameters.
The array always stores the pointers.... It holds a strong reference to it or sends it a retain message (if using non ARC).
So
[myMutableArray addObject: anObject];
adds the pointer to it.
If you now change anObject's properties and access it later through the array, it will
give you the pointer to just that object with the changes to its properties.
Edit:
No, if you alloc/init, you are creating a new object instance and allocate new memory for it on the heap (ie, it's another pointer to a new memory address).
What exactly are you trying to accomplish? There sure is a way, if you provide a little more detail.
If you alloc/init the object with the same class, why not just create a method to change the object's properties:
Instead of
myObject = [[MyClass alloc] initWithParameter1: one parameter2: two];
You could create a method that changes these properties:
[myObject updateParameter1: anotherOne parameterTwo: anotherTwo];
And, of course, the advantage of a mutable array is, that you can change its contents, so like #Eli Gregory pointed out, you can replace an object with another one (or rather the pointers to it).
Because you want to point to a newly allocated and initialized object, you can't 'update' the pointer, what you can do is 'replace' the pointer with a new one at a certain index.
A method you could use to do this is:
- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject
so it would look something like:
NewViewController *new = [[NewViewController alloc] init..];
[myArray replaceObjectAtIndex:x withObject:new];
Is this pointer assignment correct?
customclass.somearray = &*otherarray;
where somearray and otherarray are NSArray objects.
If not, how do I solve my problem:
I want to share this otherarray object with customclass.somearray. And I want all changes
made to customclass.somearray to be made to the original otherarray too.
Doing it this way, it works. I just want to ask, is it correct?
Your two variables are pointers of the same type, so just assign one to the other:
customclass.somearray = otherarray;
The way you have written this is unnecessary. Using the dereference operator * essentially gives you the "contents" of the pointer. The address-of operator & correspondingly gives you the address of whatever you apply it to. Your pointer otherarray contains an address. If you dereference that address and then take the address of that, you end up right back where you started.
Be aware that the left side of this assignment is a property access (assuming that customclass is also an object and not just a struct). This means that the compiler will change your expression into:
[customclass setSomearray:&*otherarray];
// And my version will be changed into:
[customclass setSomearray:otherarray];
That is, it becomes a method call rather than a simple assignment. This does not affect the syntax you should use, however.
When working in Objective-C, you never deal with objects directly, but always refer to them via pointers. Always. In C++, you can declare an actual object on the stack, for example, but you never do that in Objective-C. So, if you have:
NSArray *otherArray = [NSArray arrayWithObjects:#"foo", #"bar", nil];
then otherArray is a pointer to an instance of NSArray. Likewise, your somearray property will be of type NSArray*, so the types will match and you can just assign one to the other:
customclass.somearray = otherarray;
Hope that helps.
I am getting a problem, while inserting an object into the main List.
[editContactList addObject:editcontacts];
[editObject.contactList insertObject:editContactList atIndex:0];//error as mutating method sent to immutable object
[editcontacts release];
If you get that particular error, you don't actually have an NSMutableArray; you have an NSArray. Which is immutable. (Note that simply casting an NSArray to NSMutableArray does nothing, the array itself needs to be an instance of a mutable array, rarely seen with instance variables, especially those made accessible publicly.)
Edit: We're going to need some more information; how are these variables defined, how are they initialized, etc.