Problems with Replacing a String is a NSMutableString

View: New views
6 Messages — Rating Filter:   Alert me  

Problems with Replacing a String is a NSMutableString

by Charles philip Chan :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hello:

I am currently having a problem with replacing a string in an
NSMutableString and I am not too sure whether it is a bug in the current
SVN tree or I am doing something stupid. Here are the code snippets:
...
NSMutableString *albumIndexTemp;
...
// PlayItem is just a dictionary of strings. Since there is
// only 1 key with the value of "Album". The first index of
// the array should return something like
// "ID_CLIP_INFO_NAME4".
albumIndexTemp = [[playingItem allKeysForObject:@"Album"]
               objectAtIndex: 0];

// This should return something like "ID_CLIP_INFO_VALUE4"
[albumIndexTemp replaceOccurrencesOfString:@"NAME"
                withString:@"VALUE"];

[albumBox setStringValue:[playingItem objectForKey:albumIndexTemp]];
[albumBoxMini setStringValue:[playingItem objectForKey:albumIndexTemp]];

----------------------------------------------------------------------

However, this doesn't seem to work. I have a similiar stanza above
(without the string replacement) and it worked:

if ([[playingItem objectForKey:@"ID_CLIP_INFO_NAME1"]
                               isEqual:@"Artist"]) {
   [artistBox setStringValue:[playingItem
              objectForKey:@"ID_CLIP_INFO_VALUE1"]];
   [artistBoxMini setStringValue:[playingItem
              objectForKey:@"ID_CLIP_INFO_VALUE1"
}

---------------------------------------------------

What am I doing wrong?

Thanks.

Charles



_______________________________________________
Discuss-gnustep mailing list
Discuss-gnustep@...
http://lists.gnu.org/mailman/listinfo/discuss-gnustep

attachment0 (199 bytes) Download Attachment

Re: Problems with Replacing a String is a NSMutableString

by David Ayers-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hello Charles,

Charles philip Chan schrieb:

> I am currently having a problem with replacing a string in an
> NSMutableString and I am not too sure whether it is a bug in the current
> SVN tree or I am doing something stupid. Here are the code snippets:
> ...
> NSMutableString *albumIndexTemp;
> ...
> // PlayItem is just a dictionary of strings. Since there is
> // only 1 key with the value of "Album". The first index of
> // the array should return something like
> // "ID_CLIP_INFO_NAME4".
> albumIndexTemp = [[playingItem allKeysForObject:@"Album"]
>                objectAtIndex: 0];
>
> // This should return something like "ID_CLIP_INFO_VALUE4"
> [albumIndexTemp replaceOccurrencesOfString:@"NAME"
>                 withString:@"VALUE"];

>
> What am I doing wrong?

I would assume that if playingItem is an NS[(Mutable)Dictionary that the
key returned by allKeysForObject: are immutable.  Keys for collections
are copied by the collection to insure they are immutable.  Allowing
them to be mutable would break the internal hash lookups.

Cheers,
David


_______________________________________________
Discuss-gnustep mailing list
Discuss-gnustep@...
http://lists.gnu.org/mailman/listinfo/discuss-gnustep

Re: Problems with Replacing a String is a NSMutableString

by Charles philip Chan :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

David Ayers <ayers@...> writes:

Hello David:

> I would assume that if playingItem is an NS[(Mutable)Dictionary that the
> key returned by allKeysForObject: are immutable.  Keys for collections
> are copied by the collection to insure they are immutable.  Allowing
> them to be mutable would break the internal hash lookups.

I still don't understand this, the method "allKeysForObject" is supposed
to:

,----
| Returns an array containing all the dictionary's keys that are
| associated with anObject.[1]
`----

So basically I am returning an array of the keys, and since there is
only 1 key for the object "Album" I search for it at index zero in the
array and return it as an NSMutableString. I then want to change the
string to the really key for the "Album" title and search the dictionary
for the object- I am not even touching the dictionary. Also
"playingItem" is defined as mutable:

,----
| NSMutableDictionary *playingItem = myPlayingItem;
`----

Thanks for your reply.

Charles

---
[1] From http://www.gnustep.org/resources/documentation/Developer/Base/Reference/NSDictionary.html#method$NSDictionary-allKeysForObject$


_______________________________________________
Discuss-gnustep mailing list
Discuss-gnustep@...
http://lists.gnu.org/mailman/listinfo/discuss-gnustep

attachment0 (199 bytes) Download Attachment

Re: Problems with Replacing a String is a NSMutableString

by David Chisnall :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On 24 Jul 2008, at 09:20, Charles philip Chan wrote:

> So basically I am returning an array of the keys, and since there is
> only 1 key for the object "Album" I search for it at index zero in the
> array and return it as an NSMutableString. I then want to change the
> string to the really key for the "Album" title and search the  
> dictionary
> for the object- I am not even touching the dictionary. Also
> "playingItem" is defined as mutable:

I think the problem is that you are misunderstanding the Objective-C  
type system.  The type of an object is a property of the object  
itself, not of the label of the object (as it is in languages like C+
+, modulo structural typing).

When you insert an object into a dictionary, the key will be  
immutable, the object may be mutable.  When you call  
allKeysForObject: you get an NSArray (immutable) containing pointers  
to NSStrings (also immutable).  You can not 'return it as an  
NSMutableString,' you return it as an id, because that is what the  
objectAtIndex: method on NSArray returns.

When you do something like this:

id a = {whatever};
NSMutableString *b = a;

You are not changing a into an NSMutableString, you are just  
providing a hint to the compiler that you expect a to respond to any  
messages declared on NSMutableString.  If it does, at runtime,  
possibly using forwarding, then this will work.  If it doesn't, then  
you will have problems, most likely runtime exceptions from  
unrecognised selectors.

You can not modify the key of an item in an NSDictionary, because  
that would alter the mappings without NSDictionary knowing that they  
had altered.  When you later did objectForKey: on the dictionary,  
NSDictionary would call -hash on the key you passed in.  It would  
then look in the bucket associated with this hash and fail to find  
the key, because it put the key in the bucket corresponding to the  
return value of -hash when it was entered.  The documentation on  
NSObject tells you that the return value from -hash may not change  
when an object is in a collection.

Looking at your code, it seems that you don't actually want to change  
the key in the dictionary, you want to change a copy of it.  The  
easiest way to do this is to just send a mutableCopy message, like this:

albumIndexTemp = [[[playingItem allKeysForObject:@"Album"]
                objectAtIndex: 0] mutableCopy];

This will not modify the dictionary state, and will give you an  
NSMutableString you can do things with.

For tracking down this kind of bug (and ensuring it doesn't get  
reintroduced), you might find this macro that I use with Étoilé useful:

#ifdef DEBUG
#define SAFECAST(type, obj) ([obj isKindOfClass:[type class]] \
                ? (type*)obj \
                :    ([NSException raise:@"InvalidCast"\
                                 format:@"Can not cast %@ to %s", obj,\
                                #type], (type*)nil))
#else
#define SAFECAST(type, obj) (type*)obj
#endif

Use it like this:

albumIndexTemp = SAFECAST(NSMutableString, [[playingItem  
allKeysForObject:@"Album"]
                objectAtIndex: 0]);

If you compile in debug mode, this will insert an -isKindOfClass:  
test and throw an exception (which you can find in the debugger  
easily) if you are trying to cast an object pointer to an incorrect  
type.  If you compile in release mode then you will get a pointer  
cast, which has no run time overhead.

David

_______________________________________________
Discuss-gnustep mailing list
Discuss-gnustep@...
http://lists.gnu.org/mailman/listinfo/discuss-gnustep

Re: Problems with Replacing a String is a NSMutableString

by Helge Hess :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On 24.07.2008, at 10:20, Charles philip Chan wrote:
>> Keys for collections are copied
    ^^^                      ^^^^^
>> by the collection to insure they are immutable. Allowing them to be  
>> mutable would break the internal hash lookups.
> I still don't understand this
...
> | Returns an array containing all the dictionary's keys that are
                                                     ^^^^
>
> | associated with anObject.[1]
> `----
>
> So basically I am returning an array of the keys, and since there is
> only 1 key for the object "Album" I search for it at index zero in the
> array and return it as an NSMutableString.

Dictionary keys are never NSMutableString objects. As David says, the  
NSMutableString will get copied when its used as a dictionary key.

   NSString *key = [NSMutableString stringWithString:@"bla"];
   [yourDict setObject:@"this and that" forKey:key];
   // the yourDict has no reference to your 'key' object,
   // it made a copy

Aproximately this happens from a copy-perspective:

   NSString *key = [NSMutableString stringWithString:@"bla"];
   NSString *dictCopy;

   dictCopy = [key copy];
   [yourDict setObject:@"this and that" forKey:dictCopy];
   [dictCopy release];

As mentioned by David a mutable object can't be used as a hashtable  
key for rather obvious reasons :-) (if not, lookup hashtable in  
Wikipedia :-)
NSMutableDictionary ensures the immutability by calling -copy.

Helge
--
Helge Hess
http://helgehess.eu/


_______________________________________________
Discuss-gnustep mailing list
Discuss-gnustep@...
http://lists.gnu.org/mailman/listinfo/discuss-gnustep

Re: Problems with Replacing a String is a NSMutableString

by Charles philip Chan :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

David Chisnall writes:

> I think the problem is that you are misunderstanding the Objective-C
> type system. The type of an object is a property of the object itself,
> not of the label of the object (as it is in languages like C+ +,
> modulo structural typing).

Yes. This was indeed my problem.

> You can not modify the key of an item in an NSDictionary, because that
> would alter the mappings without NSDictionary knowing that they had
> altered. When you later did objectForKey: on the dictionary,
> NSDictionary would call -hash on the key you passed in. It would then
> look in the bucket associated with this hash and fail to find the key,
> because it put the key in the bucket corresponding to the return value
> of -hash when it was entered. The documentation on NSObject tells you
> that the return value from -hash may not change when an object is in a
> collection.

Now I am clear on that.

> Looking at your code, it seems that you don't actually want to change
> the key in the dictionary, you want to change a copy of it.

Yes. This is where I misunderstood David Ayers.

> For tracking down this kind of bug (and ensuring it doesn't get
> reintroduced), you might find this macro that I use with Etoile
> useful:

Thanks.

With you help, I got it working. The only problem is that I still think
that there is a bug with "replaceOccurrencesOfString: withString:". I
tried it with one of Nicola's tutorials and as with my code, I got a:

,----
| : Uncaught exception NSInvalidArgumentException, reason: Can not
| determine type information for -[GSMutableString
| replaceOccurrencesOfString:withString:]
| Aborted
`----

However, once I replace it with the non-standard "replaceString:
withString:", it worked.

Thank you everyone for your help.

Charles



_______________________________________________
Discuss-gnustep mailing list
Discuss-gnustep@...
http://lists.gnu.org/mailman/listinfo/discuss-gnustep

attachment0 (199 bytes) Download Attachment
LightInTheBox - Buy quality products at wholesale price