NSNumber lvalue assignment woes

Marjock
Unregistered
 
Post: #1
Basically, I'm trying to assign the value 4.0f to a NSNumber numberWithFloat.

To do this I use the line:

Code:
[[[allQuads objectAtIndex:i] objectForKey:@"bottomLeft"] objectAtIndex:a] = 4.0f;


However, when I try to do this I get an "invalid lvalue in assignment" error.

I realise the line of code might look a little confusing. Basically, it's an NSNumber numberWithFloat inside an array inside a dictionary inside another array.

Or, as it is described when I NSLog it:

Code:
<CFArray 0x33d940 [0xa01c00e0]>{type = mutable-small, count = 2, values = (
    0 : <CFDictionary 0x342e70 [0xa01c00e0]>{type = immutable, count = 4, capacity = 4, pairs = (
    0 : bottomLeft = <CFArray 0x342e50 [0xa01c00e0]>{type = immutable, count = 3, values = (
    0 : <CFNumber 0x342d70 [0xa01c00e0]>{value = +0.0000000000, type = kCFNumberFloat32Type}
    1 : <CFNumber 0x342d70 [0xa01c00e0]>{value = +0.0000000000, type = kCFNumberFloat32Type}
    2 : <CFNumber 0x342d70 [0xa01c00e0]>{value = +0.0000000000, type = kCFNumberFloat32Type}
)}


Any ideas where I'm going wrong?

(If you need more code, just say. I wasn't sure how much to post and decided against needlessly cluttering the thread).

Cheers,
Mark
Quote this message in a reply
Moderator
Posts: 508
Joined: 2002.09
Post: #2
This should do the trick:

Code:
NSNumber *theNumber = [[[allQuads objectAtIndex:i] objectForKey:@"bottomLeft"] objectAtIndex:a];

[theNumber setFloatValue:4.0f];

"When you dream, there are no rules..."
Quote this message in a reply
Member
Posts: 257
Joined: 2004.06
Post: #3
You know, this may sound like a flippant reply (but it isn't! Honest!) but I don't think you can change the value of an NSNumber once you've created it. From the docs on NSValue (of which NSNumbers are a subclass of): NSValue objects are always immutable.

Your best bet is to just use an NSMutableArray and replace the NSNumber with a new NSNumber set to the value you want, not use NSArrays at all, or create your own object derived from NSObject with a float value in it with accessors for changing it.

Edit: If you still want to use NSNumbers with an NSMutableArray, this is the function you'll want to use: - (void)replaceObjectAtIndex:(unsigned)index withObject:(id)anObject

The brains and fingers behind Malarkey Software (plus caretaker of the world's two brattiest felines).
Quote this message in a reply
Marjock
Unregistered
 
Post: #4
Quote:This should do the trick:

Code:
NSNumber *theNumber = [[[allQuads objectAtIndex:i] objectForKey:@"bottomLeft"] objectAtIndex:a];

[theNumber setFloatValue:4.0f];


Uh, but that's not actually making [[[allQuads objectAtIndex:i] objectForKey:@"bottomLeft] objectAtIndex:a] equal to 4, is it?

It just looks like it's making an NSNumber which has the same value as <the really long line of code> but then changing its value to 4.0,

However, I'll look into the setFloatValue: thing as well.

Also, cheers Malarkey, I'll try your way if the above fails =)

Thanks,
Mark
Quote this message in a reply
Marjock
Unregistered
 
Post: #5
I actually thought about it and the replaceObjectAtIndex plan is not only far easier than anythign else but it also fits in far more logically with my code =)

So, I've done that.

Thanks heaps,
Mark
Quote this message in a reply
Member
Posts: 257
Joined: 2004.06
Post: #6
Well, that and I don't think setFloatValue actually exists for NSNumber. Wink

The brains and fingers behind Malarkey Software (plus caretaker of the world's two brattiest felines).
Quote this message in a reply
Moderator
Posts: 1,560
Joined: 2003.10
Post: #7
I'm surprised no one explained what was wrong with his original line of code...

An lvalue, if you didn't know, is a value which can legally appear on the left side of an assignment statement. myVariable, myArray[0], myStruct.member, *myPointer, etc. are valid lvalues. They all have addresses in physical memory where a new value can be stored.

What you were trying to do was to use the return value of a method call as an lvalue. It had no address in physical memory, so there isn't anything anything logical the compiler could do with that statement.
Quote this message in a reply
Marjock
Unregistered
 
Post: #8
Ahh, cheers for that, Alex =)

I'm now faced with yet another problem, though ='/

My code is as below:

Code:
    for(i = 0; i < numberOfQuads; i++)
    {
        NSString *tempString = [quadSplitter objectAtIndex:i];
        quadPointSplitter = [tempString componentsSeparatedByString:@","];
        
        for(a = 0; a < 3; a ++)
        {
            [[[allQuads objectAtIndex:i] objectForKey:@"topLeft"] replaceObjectAtIndex:a withObject:[NSNumber numberWithFloat:4.0]];

            NSLog(@"%@",[[[allQuads objectAtIndex:i] objectForKey:@"topLeft"] objectAtIndex:a]);
        }
    }


As closely as I can tell, all of my "[[[allQuads objectAtIndex:i] objectForKey:@"topLeft"] objectAtIndex:a]"'s should now have a value of 4.0. However it seems to be completely ignoring this and the NSLog is printing out the three values as, -100.0, 100.0 and 0.0

Any ideas?

Thanks yet again, and sorry I seem to keep coming back with problems Rasp

-Mark
Quote this message in a reply
Moderator
Posts: 1,560
Joined: 2003.10
Post: #9
Judging from the NSLog output from your first post, it looks like [[allQuads objectAtIndex:i] objectForKey:@"topLeft"] is being allocated as an NSArray rather than an NSMutableArray. I've had the same problem before... Cocoa doesn't always make it obvious what the problem is when you try to modify an immutable object.
Quote this message in a reply
Marjock
Unregistered
 
Post: #10
Nah, I've changed the array to be mutable since the first post. The equivelant NSLog output now is:

Code:
<CFArray 0x340be0 [0xa01c00e0]>{type = mutable-small, count = 2, values = (
    0 : <CFDictionary 0x3424d0 [0xa01c00e0]>{type = immutable, count = 4, capacity = 4, pairs = (
    0 : bottomLeft = <CFArray 0x33c6e0 [0xa01c00e0]>{type = mutable-small, count = 3, values = (
    0 : <CFString 0x3427f0 [0xa01c00e0]>{contents = "-100.0"}
    1 : <CFString 0x342810 [0xa01c00e0]>{contents = "100.0"}
    2 : <CFString 0x342830 [0xa01c00e0]>{contents = "0.0"}
)}


Thanks,
Mark
Quote this message in a reply
Marjock
Unregistered
 
Post: #11
I read through some Apple documentation and discovered that I shouldn't have Mutable objects inside collections, because when they mutate the amount on memory needed change and confuses the collection (or something to that effect). So I went through and changed all but the very outer array to immutable objects, and changed some of my code so it could deal with these.

It works =D =D =D

Thanks everybody so much for your help, it is greatly appreciated.

-Mark
Quote this message in a reply
DoG
Moderator
Posts: 869
Joined: 2003.01
Post: #12
I dont see why you cant have mutable objects in an array, I do it all the time and it works fine.

Of course, sets and dictionaries are a different story, as the set creates a hash table of some sort, and that hash might be based on the content of the object. Otherwise, dynamic memory is not a problem, the collections only store a pointer to the objects.
Quote this message in a reply
Marjock
Unregistered
 
Post: #13
Quote:Of course, sets and dictionaries are a different story, as the set creates a hash table of some sort, and that hash might be based on the content of the object.


Yeah, I was putting mutable arrays inside a dictionary. But what you're saying is that it should be okay for me to store mutable arrays inside other mutable arrays? Good, 'cause that will be useful, I'm sure.

Thanks,
Mark
Quote this message in a reply
DoG
Moderator
Posts: 869
Joined: 2003.01
Post: #14
I do use mutable arrays in other arrays and dictionaries, works just fine. Note, that in dictionaries, only the key cannot be mutable, in sets the object itself cannot be mutable.
Quote this message in a reply
Post Reply