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:
valueForKey:
works only for string keys. Dictionaries can use other objects for keys.valueForKey:
Handles keys that start with an "@" character differently. You cannot access elements whose keys start with@
.- Most importantly: By using
valueForKey:
you are saying: "I'm using KVC". There should be a reason for doing this. When usingobjectForKey:
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 *)defaultNameThe 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 asUnsafePointer
. 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:
dicKey
points to an object K₁ whose value is "key"mutableDic.setObject("one", forKey: dicKey)
copiesdicKey
into a new key object K₂; K₁ is left alonedicKey = "changedKey"
creates a new object K₃ with the value "changedKey", and assignsdicKey
to point to it- Since nothing points to K₁ anymore, its reference count goes to 0 and the object is deallocated
mutableDic.setObject("two", forKey: dicKey)
copiesdicKey
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:
dicKey
points to an object K₁ whose value is "key"cache.setObject("one", forKey: cacheKey)
retains K₁ for insertion into the cachecacheKey = "changedKey"
creates a new object K₂ with a value "changedKey" and assignscacheKey
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
- Since the cache is still retaining K₁, it remains alive and in memory, even if
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
How to Post String with Special Character and Thai Language Using Xml Parsing in Objective C
Avfoundation, How to Turn Off the Shutter Sound When Capturestillimageasynchronouslyfromconnection
How to Trap on Uiviewalertforunsatisfiableconstraints
How to Test If a String Is Empty in Objective-C
Why Does Apple Recommend to Use Dispatch_Once for Implementing the Singleton Pattern Under Arc
Stop Uiwebview from "Bouncing" Vertically
How to Disable Back Swipe Gesture in Uinavigationcontroller on iOS 7
How to Implement a Pop-Up Dialog Box in iOS
Core Data Background Context Best Practice
How to Create a Uiview Bounce Animation
An App Id with Identifier '' Is Not Available. Please Enter a Different String
How to Create a Delay in Swift
Best Way to Cache Images on iOS App
Class Amsupporturlconnectiondelegate Is Implemented in Both
Arkit - Apply Cifilter to a Specific Vertices of Arfaceanchor
Determine If the Access to Photo Library Is Set or Not - PHPhotolibrary