Is there a way via dot notation to access the values of keys in an NSDictionary like this?
NSDictionary *returnVal = [NSDictionary dictionaryWithObjectsAndKeys:#"Saturn", #"name", #"Gas Giant", #"type", nil];
NSLog(#"VALUE: %#", [returnVal valueForKey:#"name"]); // This is how I am doing it now.
There is no dot syntax for NSDictionary, but should consider using objectForKey: instead of valueForKey:
Difference between objectForKey and valueForKey?
Not really, no.
The dot notation is a shorthand way of calling a method with that selector name. In other words, this...
NSLog(#"Hello, %#", foo.bar.name);
...is the same as this...
NSLog(#"Hello, %#", [[foo bar] name]);
When I say "same", I mean they are compiled down to the same code. It's just syntactic sugar.
A plain NSDictionary won't act that way. You could sort of fake it with Key Value Coding, which lets you call valueForKeyPath to get properties like this:
NSLog(#"Hello, %#", [foo valueForKeyPath:#"bar.name"]);
If you really wanted to be able to write foo.bar.name in your code, however, you'd have to make a custom class that overrides forwardInvocation:; this lets you catch an unknown message to an object and do something else with it besides throw an error. In this case, you could change the unknown selector to a lookup on an NSDictionary instance it contains.
But even if you did that, the compiler would probably still generate warnings unless you made header files that declared those property names to exist.
I agree with most of the answers that NSDictionary should be accessed with objectForKey: or similar methods. However it is possible to allow for dot notation access to a NSDictionary, and for learning purposes this might be interesting for someone. Also when for example your are retrieving large JSON dictionaries via AFNetworking, this method can ease the access and readability of your code.
This is my solution:
DictionaryProperties.h: (class wrapping the NSDictionary for property access)
#interface DictionaryProperties : NSObject{
NSMutableDictionary* _backingDict;
}
#property (nonatomic, strong) NSMutableDictionary* backingDict;
+ (DictionaryProperties*) allocWithDictionary:(NSDictionary*)dict;
#end
DictionaryProperties.m:
#import "DictionaryProperties.h"
#implementation DictionaryProperties
#synthesize backingDict = _backingDict;
- (id) initWithDictionary:(NSDictionary*)dict {
if (self) {
if ([dict isKindOfClass:[NSMutableDictionary class]]) {
self.backingDict = (id)dict;
} else {
self.backingDict = [[NSMutableDictionary alloc] initWithDictionary:dict];
}
}
return self;
}
+ (DictionaryProperties*) allocWithDictionary:(NSDictionary*)dict {
return [[DictionaryProperties alloc] initWithDictionary:dict];
}
- (void)forwardInvocation:(NSInvocation *)invocation
{
NSString* key = NSStringFromSelector(invocation.selector);
invocation.selector = #selector(objectForKey:);
[invocation setArgument:&key atIndex:2];
if ([self.backingDict objectForKey:key]) {
[invocation invokeWithTarget:self.backingDict];
} else {
[self doesNotRecognizeSelector:invocation.selector];
}
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
return [self.backingDict methodSignatureForSelector:#selector(objectForKey:)];
}
#end
ExampleDictContent.h: (class declaring what is inside the dictionary)
#import "DictionaryProperties.h"
#interface ExampleDictContent : DictionaryProperties
#property (strong, nonatomic) NSString* someData;
#property (strong, nonatomic) NSString* someOtherData;
#end
#implementation ExampleDictContent
#end
Usage: (simple declaration of a dictionary, allocation of wrapper and property access)
#import "ExampleDictContent.h"
NSDictionary* d = [NSDictionary dictionaryWithObjects:NSArray arrayWithObjects:#"someData content", #"someOtherData content", nil
forKeys:NSArray arrayWithObjects:#"someData", #"someOtherData", nil];
ExampleDictContent* dictWProps = [ExampleDictContent allocWithDictionary:d];
NSLog(dictWProps.someData);
NSLog(dictWProps.someData);
This will print:
someData content
someOtherData content
So basically DictionaryProperties works as a facade for accessing the NSDictionary. It uses forwardInvocation to convert a get-property method call into a getObjectForKey: call on the dictionary. What I like about it, is that it allows for autocompletion on the dictionary, and also allows me to explicitly declare what keys I want to access (in the ExampleDictContent.h file). Note that this solution does not allow for write access to the properties, but that can be added as shown in the link below.
This solution has partly been inspired by karstenlitsche's solution. The main difference is that this solution is based on sub-classing instead of categories.
No, I don't think so.
From the reference manual.
Accessing Keys and Values
– allKeys
– allKeysForObject:
– allValues
– getObjects:andKeys:
– objectForKey:
– objectsForKeys:notFoundMarker:
– valueForKey:
That's listed as the only way to access the keys and the values. So you are doing it alright.
You would be able to access it if the keys were a public property and it was readable.
The way that you have mentioned for accessing element of dictionary is ideal way(using keys).
If you want to do something else, might be you can use-
NSArray *allValues = [returnVal allValues];
Now using this array as well you can perform tasks.
And if you want something specific then mention that, might be for that there can be some other way.
Also as NSDictionary class won't have any property defined, so dot notation is directly not possible.
No, you are doing it the correct way. In the iOS world, often the correct way is the only way. :)
If you really want dot notation (and other nice things you get with typed objects), you're going to have to stuff the dictionary representation into an object. Most commonly my interface will look like:
#interface FooBar : NSObject {
NSString *someData;
int someNumber;
}
#property (nonatomic, copy) NSString *someData;
#property (nonatomic, assign) int someNumber;
+ (FooBar *)FooBarFromDictionary:(NSDictionary *)dataDict;
#end
The implementation should be clear. Then you can
FooBar *fb = [FooBar FooBarFromDictionary:data];
NSLog(#"fb.someData = %#", fb.someData);
Technically, you can do something like this:
typedef id (^valueBlock)(id);
#interface NSDictionary(dotNotationAddons)
#property(nonatomic, readonly) valueBlock value;
#end
#implementation NSDictionary(dotNotationAddons)
-(valueBlock) value
{
return [[^(id key) {
return [self objectForKey:key];
} copy] autorelease];
}
#end
int main (int argc, const char * argv[])
{
#autoreleasepool {
NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:#"1", #"One", #"2", #"Two", #"3", #"Three", #"4", #"Four", nil];
id value = dictionary.value(#"One");
NSLog(#"%#", value);
}
return 0;
}
I don't know if that is what you were looking for, but I hope it helps!
The answer's still no, but you can use the shorthand
myDictionary[#"key"]
instead of
[myDictionary objectForKey:#"key"]
In Swift, there is a solution that may not seem very elegant but does the trick.
It will require a typeAlias for each specific type of Dictionary and also an extension with variables (with getter/setter) for each of the expected keys in your dictionary. Not a good practice at all
It may be easier wrap your dict object in an object (class/struct) with the same treatment.
typealias MyDict = [String:AnyObject]
extension MyDict {
var key: AnyObject? {
get { return self["key"] }
set { self["key"] = newValue }
}
}
// Usage
var myDict = MyDict()
// Get the value
myDict["key"] = "value1" as AnyObject
if let str = myDict.key {
print(str) // prints "value1"
}
// Set the value
myDict.key = "value2" as AnyObject
if let str = myDict["key"] {
print(str) // prints "value2"
}
Related
I have a file Variables.m for storing properties that I can use in all classes within my app. Now I would like to set a value for one of the properties (say username) in class A and I would like it to be available to all the other classes (B,C,D,E..) in my app like a constant. ie. once they initialize a Variables object (say var) in class B, if they issue var.username, they should get the username that I set in class A.
In effect instead of hardcoding a username value, I want to set it programmatically and have all the classes see the value that I just set. Can I achieve this without passing the Variables object around whenever I navigate to a class?
Alternatively, you can use NSUserDefaults
Set variable in class A:
NSString *usernameToSave = #"John Doe";
[[NSUserDefaults standardUserDefaults] setObject:usernameToSave forKey:#"userName"];
Read variable in any class:
NSString *userName = [[NSUserDefaults standardUserDefaults] objectforKey:#"userName"];
Apart from being simple, this has the advantage (or not) that it's persistent across app restarts.
It has the disadvantage that it's not very secure; for passwords and the like you should use Keychain Services as described here.
Create a singelton class that has the appropriate getters and setters for the items you want it to store.
You can then just reference that single instance from any other class.
For example in your Variables class create a class method like so:
+(Variables*)sharedVariables{
static Variables *myVariables = nil;
if (myVariables != nil){
return myVariables;
}
myVariables = [[Variables alloc]init];
return myVariables;
}
If you want a better implementation then google objective C singleton class implementation.
:)
to use this from your other classed you would just type:
[Variables sharedVariables].whatever
You can use Singleton pattern. Like this.
#interface MySingleton : NSObject
{
NSString *username;
}
#property (nonatomic, retain) NSString *username;
+ (MySingleton *) sharedInstance;
#end
#implementation MySingleton
#synthesyse username;
static MySingleton *sMySingleton = nil;
+ (MySingleton *) sharedInstance
{
#synchronized(self)
{
if (sMySingleton == nil)
{
sMySingleton = [NSAllocateObject([self class], 0, NULL) init];
}
}
return sMySingleton;
}
#end
When inserting an object into an array with a property is there any reason to invoke the getter/setter with self? i.e.
[self.myArray insertObject: myObject];
Or can I just use:
[myArray insertObject: myObject];
the gist would be:
.h
#interface ArrayViewController : UIViewController <UITextFieldDelegate>
{
NSMutableArray *myArray;
int itemNumber;
}
#property (nonatomic, retain) NSMutableArray *myArray;
#end
.m
- (IBAction)createMyArray
{
self.myArray = [[NSMutableArray alloc] initWithObjects: nil];
}
-(IBAction) addItemToMyArray
{
NSString *myString = [[NSString alloc] initWithFormat:#"item %d",itemNumber];
[myArray addObject: myString];
//[self.myArray addObject: myString]; //Or should I use self?
[myString release];
NSLog(#"myArray = %#", myArray);
itemNumber++;
}
//- (void)dealloc etc. not shown
Conceptually, it doesn't matter, so long as your getter method only returns the existing field value and doesn't, eg, do some "just in time" allocation or some such.
However, it's good practice to come up with a policy (personal or group) that you stick with, so that the caveats of that policy become second nature. Constantly switching styles results in sloppy, buggy code.
I tend to always use the self. for properties, just to remind myself that they are, in fact, properties, and to make it less likely that I'll accidentally set the value without using the property notation.
Either will work but you need to be aware of what you are doing. Using self. will invoke the setter/getter methods while the other will just access the variable directly. Using the variable directly, while perfectly valid, is discouraged outside of the initializer and dealloc method. The reason is you are losing out on the benefits of the property, especially setting using self. because it will properly assign/copy/retain the value for you correctly. Another reason not use property variables directly is because of atomicity but in your case you declared it as nonatomic.
Both of those are fine. It's mostly a stylistic choice. Using self.myArray will result in a call to the getter [self myArray].
When using alloc/init you should not set the returned value to a property, as these will retain twice:
self.myArray = [[NSMutableArray alloc] initWithObjects: nil];
use
myArray = [[NSMutableArray alloc] initWithObjects: nil];
or
self.myArray = [NSMutableArray array];
for the initialization.
The insert operations are equivalent though.
I typically skip the getter because I rarely find it valuable and it clutters up the readability of the code a bit. However, I tend to use the setter because I find it easier to allow the auto-generated setter methods to handle the retain/release semantics
In your case it's not an obligation to use self.myArray but for this case belloaw it will be an obligation:
-(void) addItemToMyArray:(NSAarray *)myArray
{
NSString *myString = [[NSString alloc] initWithFormat:#"item %d",itemNumber];
[self.myArray addObject: myString];
[myString release];
NSLog(#"myArray = %#", self.myArray);
itemNumber++;
}
to difference between the class attribut and the function argument.
I have a singleton class with this code:
manager.h
#interface Manager : NSObject {
NSString *jobsLimit;
NSMutableDictionary *jobTitles;
}
#property (nonatomic, retain) NSString *jobsLimit;
#property (nonatomic, assign) NSMutableDictionary *jobTitles;
#implementation Manager
#synthesize jobsLimit;
#synthesize jobTitles;
+ (id)sharedManager {
#synchronized(self) {
if(shared == nil)
shared = [[super allocWithZone:NULL] init];
}
return shared;
}
- (id)init {
if (self = [super init]) {
jobsLimit = [[NSString alloc] initWithString:#"50"];
jobTitles = [[NSMutableDictionary alloc] init];
}
return self;
}
Then in the code i'm assigning these variables like this:
self.jobsLimit = [NSString stringWithFormat:#"%d", progressAsInt];
[self.jobTitles addEntriesFromDictionary:anotherDictionary];
- (void)dealloc {
[super dealloc];
[jobsLimit release];
[jobTitles release];
}
Now my question is this code correct? Is the assignment correct?
I'm very confused with when to use alloc and/or retain. Do I need to use alloc if my property is already retained? and If I use alloc should my property be assign?
What will be the reference count now for these variables and will they be dealloc'd/under-dealloc'd when the dealloc is called?
Also for singleton classes do I need to initialize my ivars as in the init method above or I do not have to.
I'd appreciate if someone can help me clear this confusion out and thanks in advance.
Regards,
Your code actually looks correct, but perhaps some explanation is in order, since it sounds like you're a little unsure.
When you assign to a property that has retain semantics using the "." syntax, the accessor method calls retain. The "." syntax is just shorthand for invoking the accessor method, so
self.jobsLimit = [NSString stringWithFormat:#"%d", progressAsInt];
is exactly the same as
[self setJobsLimit:[NSString stringWithFormat:#"%d", progressAsInt]];
That works out to:
create an (autoreleased) string with a numeric value
retain the string (you now own it) and assign it to jobsLimit
If, on the other hand, you assign to the iVar directly (not using the "."-accessor), the setter method is not called. For example:
jobsLimit = [[NSString alloc] initWithString:#"50"];
That is:
allocate a string (you own it), with value "50"
assign it to jobsLimit
Either way, you now own the string referred to by jobsLimit, and are responsible for eventually releasing it (e.g., in your dealloc method).
I guess you need a lot of this : IOS Memory Management
and a bit of : What should my Objective-C singleton look like?
good lectures !
I have numerous classes that use the various NSDictionary/NSArray collection classes as ivars but often I run into the problem of my collection class getting released before the containing class is released.
This seems to happen mostly with the collections classes and not with another model class (ie classes that I either created separately or other NS* non-collection classes).
Here are the two variations I've done and seen other people do:
#implementation ClassX
// myDictionary declared as a property in the .h file as this:
// #property (nonatomic, retain) NSMutableDictionary *myDictionary;
#synthesize myDictionary;
- (id)int
{
if (self = [super init])
{
// Option 1:
// If I don't instantiate and assign with 'self',
// myDictionary ivar will not be available
// at times in doSomething.
myDictionary = [NSMutableDictionary dictionary];
// Option 2:
// Doing this, however will keep the dictionary around.
// because I have invoked an extra retain on the dictionary
self.myDictionary = [NSMutableDictionary dictionary];
// Which one is more correct?
}
return self;
}
- (void)doSomething
{
// this will give the error about trying to invoke
// a method on an already released instance
[myDictionary objectForKey:#"myKey"];
}
- (void)dealloc
{
// If I did self.myDictionary in 'init', I then
// need to do this:
[myDictionary release];
[super dealloc];
}
#end
So which approach is the more correct way to hold an instance of NSDictionary within a class?
Option 2 is correct; Option 1 is wrong.
But you left out the best option: myDictionary = [[NSMutableDictionary alloc] init].
I recommend using
myDictionary = [[NSMutableDictionary alloc] init];
The memory is only within the scope of the method you're in if you call [NSMutableDictionary dictionary]. Once you leave the method, that memory goes with it which is why you need to alloc/init if you want to retain the values.
That's why you don't have to release if you don't encounter an alloc.
So for instance:
- (void) doSomething {
// Do not need to release this string
NSString *someText = #"Hello world!";
// You need to release this string:
NSString *otherText = [[NSString alloc] initWithString:#"Hello world!"];
[otherText release];
}
Edited: Removed self after #mipadi #st3fan and caught my mistake. Forgot to post the change. Thanks for keeping me accountable.
I'm looking to create a "crash-proof" NSDictionary as I'm using a JSON serializer that converts a server response into an NSDictionary. As as result, sometimes the key for the dictionary is not present. Currently, this will crash the application, however I'd rather an empty NSString was returned so I can display this in the interface.
A solution could be that I check for the key every time I access the dictionary, e.g.
if([returnedDictionary objectForKey:#"key"]){
// Display [returnedDictionary objectForKey:#"key"];
}else{
// Display #"";
}
However this soon results in bloated, hard-to-read code.
I had thought about creating a custom NSDictionary object, something like:
#interface NSSafeDictionary : NSDictionary .....
that overrides objectForKey with the above statement.
Is this a satisfactory approach?
Thanks
Are you always going to want to get strings out of your dictionary or will other objects be stored in it as well? If it's only strings, I think the easiest way around this is to construct a category on NSDictionary.
#interface NSDictionary ( EmptyStrings )
- (NSString *)stringForKey:(id)aKey;
#end
#implementation NSDictionary ( EmptyStrings )
- (NSString *)stringForKey:(id)aKey {
id object = [self objectForKey:aKey];
if (object == nil ) {
return #"";
}
if ([object isKindOfClass:[NSString class]) {
return object;
} else {
return nil;
}
}
#end
Given that it comes in over the network, I would think that you would want to sanitise the data more than just checking for empty values but if not, you don't really need to inherit from NSDictionary.
A simple utility method in your class would do the trick.
Or you could create a category on NSDictionary:
#interface NSDictionary (Safe)
-(NSString*)safeStringForKey:(NSString*)key;
#end
(I'm sure you can figure out the implementation.)