Get all keys of an NSDictionary as an NSArray - objective-c

Is it possible to get all the keys from a specific NSDictionary as a seperate NSArray?

Just use
NSArray*keys=[dict allKeys];
In general, if you wonder if a specific class has a specific method, look up Apple's own documentation. In this case, see NSDictionary class reference. Go through all the methods. You'll discover many useful methods that way.

Yes it's possible. Use allKeys method:
NSDictionary *yourDictionary;
NSArray * yourKeys
yourKeys = [yourDictionary allKeys];

And if you want to get all keys and values, here's what you do:
for (NSString *key in dictionary) {
id value = dictionary[key];
NSLog(#"Value: %# for key: %#", value, key);
}

Related

NSDictionary case insensitive objectForKey:

NSDictionary has objectForKey but it's case-sentive for keys. There is No function available like
- (id)objectForKey:(id)aKey options:(id) options;
where in options you can pass "NSCaseInsensitiveSearch"
To get key's from NSDictionary which is case-insesitive one can use the following code written below.
You need to add Category of NSDictionary Class with this functionality
- (id)objectForCaseInsensitiveKey:(NSString *)key {
NSArray *allKeys = [self allKeys];
for (NSString *str in allKeys) {
if ([key caseInsensitiveCompare:str] == NSOrderedSame) {
return [self objectForKey:str];
}
}
return nil;
}
This isn't included for a couple of reasons:
NSDictionary uses hash equality, and for pretty much any good hashing algorithm, any variation in the source string results in a different hash.
More importantly, NSDictionary keys are not strings. Any object that conforms to NSCopying can be a dictionary key, and that includes a whole lot more than strings. What would a case-insensitive comparison of an NSNumber with an NSBezierPath look like?
Many of the answers here offer solutions that amount to transforming the dictionary into an array and iterating over it. That works, and if you just need this as a one-off, that's fine. But that solution is kinda ugly and has bad performance characteristics. If this were something I needed a lot (say, enough to create an NSDictionary category), I would want to solve it properly, at the data structure level.
What you want is a class that wraps an NSDictionary, only allows strings for keys and automatically lowercases keys as they are given (and possibly also remembers the original key if you need a two-way mapping). This would be fairly simple to implement and is a much cleaner design. It's too heavy for a one-off, but if this is something you're doing a lot, I think it's worth doing cleanly.
The correct answer is that you should use case-folded keys as dictionary keys. This is not the same as converting them to upper or lower case and it won't destroy the O(1) average case search/insert complexity.
Unfortunately, Cocoa doesn't seem to have an appropriate NSString method to case-fold a string, but Core Foundation has CFStringFold() which you can use for that purpose. Let's write a short function to do the necessary work:
NSString *foldedString(NSString *s, NSLocale *locale)
{
CFMutableStringRef ret = CFStringCreateMutableCopy(kCFAllocatorDefault, 0,
(__bridge CFStringRef)s);
CFStringNormalize(ret, kCFStringNormalizationFormD);
CFStringFold(ret, kCFCompareCaseInsensitive, (__bridge CFLocaleRef)locale);
return (__bridge_transfer NSString *)ret;
}
Note that the locale argument is important. If you specify NULL, you will get the current system locale. This will be fine in most cases, but Turkish users might be surprised that "I" matches "i" rather than "ı". You might therefore want to pass [NSLocale currentLocale], and if you're saving the results you might also want to save the locale identifier and create the locale from that.
So, when adding to the dictionary, you now need to do
[dict setObject:obj forKey:foldedString(myKey, locale)];
and to look up again
[dict objectForKey:foldedString(myKey, locale)];
One final observation is that you might wish to store the case-folded keys alongside the original values, then you don't have to fold them on every access to the dictionary.
In the code written below, I search for a actual key for a input key. So , if input key=#"naMe" then the actual key=#"name".
NSDictionary *dic=[NSDictionary dictionaryWithObjectsAndKeys:#"John",#"Name",#"123456",#"empId", nil];
NSString *key=#"naMe";
NSString *name=[dic objectForKey:key];
if(name==nil){
NSPredicate *searchPred=[NSPredicate predicateWithFormat:#"self LIKE[cd] %#",key];
NSArray *searchedKeys=[[dic allKeys] filteredArrayUsingPredicate:searchPred];
if(searchedKeys.count>0){
name=[dic objectForKey:[searchedKeys objectAtIndex:0]];
}
}
NSLog(#"Name = %#",name);
Many answers are correct, but here's a more example:
NSDictionary* dict= #{ #"hello" : #"Hey" };
NSArray* keys= [dict allKeys];
NSUInteger index=[keys indexOfObjectPassingTest: ^BOOL (id obj, NSUInteger index, BOOL* stop)
{
if( [obj caseInsensitiveCompare: #"Hello"]==NSOrderedSame)
{
*stop= YES;
return YES;
}
else
{
return NO;
}
}];
Personally I find this method easier, but everyone has his programming style.
EDIT
A less readable but shorter solution:
NSDictionary* dict= #{ #"hello" : #"Hey" };
NSArray* keys= [dict allKeys];
NSUInteger index=[keys indexOfObjectPassingTest: ^BOOL (id obj, NSUInteger index, BOOL* stop)
{
return *stop= [obj caseInsensitiveCompare: #"Hello"]==NSOrderedSame ;
}];
If you are only storing into, and retrieving from, the NSDictionary in one place (maybe two or three), you could use
[myString lowercaseString]
in both. The more rigorous answers are useful if the dictionary object is used all over your code.

Get all values in a JSON dictionary, without accessing by key

JSON Example:
[{
"title1":"Hey",
"title2":"Hoh",
"title3":"Hah",
"title4":"Hoo"
}]
How can I get value (hey,hoh,hah,hoo) without using valueForKey?
Could anyone guide me please?
--------------Edit--------------
I use JSON-Framework. And Now I use NSDictionary *jsonDict = [string JSONValue];
Assuming you have your data in an NSDictionary, try allValues.
Remember however than an NSDictionary is unsorted, so the order of the values is undefined.
As Todd already said, NSDictionary has a method allValues - check the NSDictionary Documentation
An example of looping through the value's is
for(NSString *value in [jsonDict allValues]){
NSLog(#"Found Value %#",value);
}
Again, these values will be unsorted as they are coming from a dictionary.

Save part of NSDictionary

I have a NSDictionary with a NSString and NSArray
I have to save only the NSArray in a variable without knowing the key.
Is this possible?
If I'm understanding you correctly, you have a dictionary that contains both an NSString and an NSArray, and you want to extract just the NSArray, without knowing what the key is.
One way to do that is to look through the dictionary with fast enumeration:
NSString *key;
for(key in someDictionary){
id someObject = [someDictionary objectForKey: key];
}
and then look at the objects to see which one is an NSArray:
if ([someObject isKindOfClass:[NSArray class]]) {
// do something with the array
}
(obligatory warning: explicitly checking an object's class is often a sign of a flawed design. In most cases, you should be checking for behavior (-respondsToSelector), not class identity)

Is it possible to invoke NSDictionary's valueForKeyPath: when a key contains periods?

I'm trying to get the value of the repeatInterval key in the com.apple.scheduler plist. I'd like to just use NSDictionary's valueForKeyPath: method like so:
CFPropertyListRef value;
value = CFPreferencesCopyValue(CFSTR("AbsoluteSchedule"),
CFSTR("com.apple.scheduler"),
kCFPreferencesCurrentUser,
kCFPreferencesCurrentHost);
NSNumber *repeatInterval = [(NSDictionary *)value valueForKeyPath:#"com.apple.SoftwareUpdate.SUCheckSchedulerTag.Timer.repeatInterval"];
But the problem with this is that the first key is really "com.apple.SoftwareUpdate", not just "com". I can get around this by getting that first value separately:
NSDictionary *dict = [(NSDictionary *)value valueForKey:#"com.apple.SoftwareUpdate"];
NSNumber *repeatInterval = [dict valueForKeyPath:#"SUCheckSchedulerTag.Timer.repeatInterval"];
I just wanted to know if there is a way to escape periods in a keypath so I can eliminate this extra step.
NSDictionary doesn't have a valueforKeyPath: method. It just invokes the NSObject implementation which is the root of your problem.
Maybe you could reimplement it in a category on NSDictionary with your own escape characters.

Accessing objects in NSMutableDictionary by index

To display key/values from an NSMutableDictionary sequentially (in a tableview), I need to access them by index. If access by index could give the key at that index, I could than get the value. Is there a way to do that or a different technique?
You can get an NSArray containing the keys of the object using the allKeys method. You can then look into that by index. Note that the order in which the keys appear in the array is unknown. Example:
NSMutableDictionary *dict;
/* Create the dictionary. */
NSArray *keys = [dict allKeys];
id aKey = [keys objectAtIndex:0];
id anObject = [dict objectForKey:aKey];
EDIT: Actually, if I understand what you're trying to do what you want is easily done using fast enumeration, for example:
NSMutableDictionary *dict;
/* Put stuff in dictionary. */
for (id key in dict) {
id anObject = [dict objectForKey:key];
/* Do something with anObject. */
}
EDIT: Fixed typo pointed out by Marco.
you can get an array of all the keys with the allKeys method of the dictionary; and then you can access the array by index. however, a dictionary by itself does not have an inherent ordering, so the ordering of the keys you get before and after a change to the dictionary can be completely different