Where's the Difference Between Setobject:Forkey: and Setvalue:Forkey: in Nsmutabledictionary

Objective-C: What is the difference between forKey and forKeyPath?

Both methods are part of Key-Value Coding and should not generally be used for element access in dictionaries. They only work on keys of type NSString and require specific syntax.

The difference between both of them is that specifying a (single) key would just look up that item.

Specifying a key path on the other hand follows the path through the objects. If you had a dictionary of dictionaries you could look up an element in the second level by using a key path like "key1.key2".

If you just want to access elements in a dictionary you should use objectForKey: and setObject:forKey:.

Edit to answer why valueForKey: should not be used:

  1. valueForKey: works only for string keys. Dictionaries can use other objects for keys.
  2. valueForKey: Handles keys that start with an "@" character differently. You cannot access elements whose keys start with @.
  3. Most importantly: By using valueForKey: you are saying: "I'm using KVC". There should be a reason for doing this. When using objectForKey: you are just accessing elements in a dictionary through the natural, intended API.

NSUserDefaults setValue and objectForKey

From the documentation

- (void)setObject:(id)value
forKey:(NSString *)defaultName

The value parameter can be only property list objects: NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary. For NSArray and NSDictionary objects, their contents must be property list objects. See

That works with setObject / objectForKey where you are adding objects inside the NSUserDefaults

Your example will work if objectID is only one type of the six above. Why? because NSUserDefaults takes that object and save it to the file system in a plist file and so it needs to know how to deal with that object to save it. If you added a custom object then the NSUserDefaults will not be able to save that on the file system

.

While setValue / valueForKey works with the properties of the class NSUserDefaults itself not with the objects inside it that you want to save


Edit

So to clarify, What I'm asking is that if I use setObject, can I use valueForKey ? Or vice versa, can I use setValue and then retrieve it using objectForKey ?

Short Answer: Yes You can

Long Answer: NSUserDefaults override the valueForKey and setValueForKey to behave like objectForKey and setObjectForKey

However if the key is the same as a property in the NSUserDefaults then conflicts may happenes ... but in the case of NSUserDefaults where it has no properties then you can use it. But in my opinion you should use the standard methods for readably specially if that is not documented

set a C type value to NSMutableDictionary

The C type const unsigned char * is mapped to Swift as
UnsafePointer. You can create an (optional) Swift string
from that pointer with

let str = String.fromCString(UnsafePointer(txt))
myDict.setValue(str, forKey: "MyText")

This assumes that the C string returned from get_text() is
UTF-8 encoded and NUL-terminated.

The UnsafePointer() conversion is necessary because fromCString()
takes an UnsafePointer argument.
If you change the C function to

const char *get_text(int idx);

then it simplifies to

let str = String.fromCString(txt)

Remark: The proper method to set a value in NSMutableDictionary
is

setObject(_, forKey: _)

The Key-Value Coding method

setValue(_, forKey: _)

has the same effect in most cases. See for example
Where's the difference between setObject:forKey: and setValue:forKey: in NSMutableDictionary?
for more information.

You could also consider to use a Swift Dictionary instead.

Does [NSMutableDictionary setValue: value forKey: key] retain NSString key?

It's very common in Cocoa for NSString parameters to be copied instead of retained. That's because you could have just as easily given the dictionary an instance of NSMutableString. Because the string's value could change, NSDictionary makes a copy.

But, regardless of how NSMutableDictionary really operates, you don't have to worry whether character needs to be retained. Once you've passed it to NSMutableDictionary as a parameter, it's really that class's problem to decide how to store the data, unless the documentation specifically tells you that retaining the objects are your responsibility.

I also wouldn't worry too much about the retainCount of any object. Following the retain count of an object too closely can lead you down rabbit holes that just make you spin your wheels.

Finally, I really don't think you need to create your own autorelease pool here. Unless you know with absolute certainty that theString is going to be very long, or you've already observed high memory utilization in Instruments, adding the autorelease pool is an unnecessary optimization.

setObject:forKey: of NSMutableDictionary overwrites all data in dictionary

The reason why it get emptied is because

[nameDictionary setObject:fullNameArray forKey:tempKey];

here, you set up your dictionary with the object "fullNameArray", then

[fullNameArray removeAllObjects];

remove all the values inside this array, effectively, removing your object in the "nameDictionary", they are the same object, it's not a deep copy of fullNameArray that you store inside your dictionary. Why did you need to store anything into your array anyway? You're only storing 1 value.

[nameDictionary setObject:fullName forKey:tempKey];

will do what you need. Sorry if I mistaken your question, it's quite hard to understand

Does the different way of handling key between NSMutableDictionary and NSCache (copy vs. retain) result in different consequence?

The key here (ha) is in the assignment to dicKey/cacheKey. Specifically, the assignments

dicKey = "changedKey"
cacheKey = "changedKey"

are not changing the value of the original dicKey and cacheKey instances, but creating new string objects and setting the local variables to point to these new objects.


In the dictionary case:

  1. dicKey points to an object K₁ whose value is "key"
  2. mutableDic.setObject("one", forKey: dicKey) copies dicKey into a new key object K₂; K₁ is left alone
  3. dicKey = "changedKey" creates a new object K₃ with the value "changedKey", and assigns dicKey to point to it
    • Since nothing points to K₁ anymore, its reference count goes to 0 and the object is deallocated
  4. mutableDic.setObject("two", forKey: dicKey) copies dicKey into a new key object K₄; K₂ is left alone

The end result is that the dictionary contains K₂ and K₄, while dicKey points to K₃.


In the cache case:

  1. dicKey points to an object K₁ whose value is "key"
  2. cache.setObject("one", forKey: cacheKey) retains K₁ for insertion into the cache
  3. cacheKey = "changedKey" creates a new object K₂ with a value "changedKey" and assigns cacheKey to point to it
    • Since the cache is still retaining K₁, it remains alive and in memory, even if dicKey no longer points to it
  4. cache.setObject("two", forKey: cacheKey) retains K₂ for insertion into the cache

The end result is that the cache contains K₁ and K₂, and cacheKey points to K₂.


If instead of being an NSString, dicKey and cacheKey were NSMutableString, whose value can be modified at runtime without creating a new object, you'd see different behavior in the cache case:

let mutableDic = NSMutableDictionary()
var dicKey: NSMutableString = "key" // K₁
mutableDic.setObject("one", forKey: dicKey) // K₂
dicKey.setString("changedKey") // still K₁
mutableDic.setObject("two", forKey: dicKey) // K₃

print(mutableDic.object(forKey: "key") ?? "") // "one"
print(mutableDic.object(forKey: "changedKey") ?? "") // "two"

// BUT:

let cache = NSCache()
var cacheKey: NSMutableString = "key" // K₁
cache.setObject("one", forKey: cacheKey) // still K₁
cacheKey.setString("changedKey") // still K₁
cache.setObject("two", forKey: cacheKey) // still K₁!

print(cache.object(forKey: "key") ?? "") // "" !!!
print(cache.object(forKey: "changedKey") ?? "") // "two"

iOS -- distinguish an NSDictionary from an NSMutableDictionary?

NSAssert([bar isMemberOfClass: [NSMutableDictionary class]], @"");


Related Topics



Leave a reply



Submit