I am typing in text from a book for NSDictionary and get an error from it? - objective-c

I typed in text from a book and
I get this error: Passing argument of 1 of "initWithObjects:forKeys:count:" from incompatible pointer type
NSDictionary *dict = [[NSDictionary alloc] initWithObjects: #"hello", #"there", #"persn"
forKeys: #"aa", #"bb", #"cc"
count: 3 ];
NSLog(#"%#", [dict objectForKey: #"bb"]);

In Objective-C, methods can't use var-args like that, they must always come at the end of the invocation.
In fact, the parameters to your message invocation are actually pointers to buffers of objects and keys.
Try this:
id objects[] = {#"hello", #"there", #"person"};
id keys[] = {#"aa", #"bb", #"cc"};
NSDictionary *dict1 = [[NSDictionary alloc] initWithObjects:objects forKeys:keys count:3];
NSLog(#"%#", [dict1 objectForKey: #"bb"]);

Related

NSDictionary dictionaryWithObjectsAndKeys vs literal notation

What are the differences between using NSDictionary/NSArray constructors and the literal notation?
NSDictionary *dict1 = [NSDictionary dictionaryWithObjectsAndKeys:#"bar", #"foo"];
NSDictionary *dict2 = #{ #"foo" : #"bar" };
NSArray *arr1 = [NSArray arrayWithObject:#"one", #"two"];
NSArray *arr2 = #[ #"one", #"two" ];
What about accessing dictionary and array elements?
NSLog(#"%#", [dict1 objectForKey:#"foo"]);
NSLog(#"%#", dict2[#"foo"]);
NSLog(#"%#", [arr1 objectAtIndex:0]);
NSLog(#"%#", arr2[0]);
Is the difference purely readability, or is there a performance/behavior difference as well?
As explained in the Clang documentation, the literal #{} and #[] forms are identical to dictionaryWithObjects:forKeys:count: and arrayWithObjects:count:, which verify that no nil values are present.
Similarly, the subscript notations translate directly to objectAtIndexedSubscript:/setObject:atIndexedSubscript: and objectForKeyedSubscript:/setObject:forKeyedSubscript: (which can be implemented for your own classes if you so desire).
Compiling this code…
#import Foundation;
int main() {
NSDictionary *dict1 = [NSDictionary dictionaryWithObjectsAndKeys:#"bar", #"foo", nil];
NSDictionary *dict2 = #{#"foo" : #"bar"};
NSString *result1 = dict2[#"bar"];
NSArray *arr1 = [NSArray arrayWithObjects:#"one", #"two", nil];
NSArray *arr2 = #[#"one", #"two"];
NSString *result2 = arr2[1];
return 0;
}
…and opening the binary with Hopper reveals this pseudocode, which is not perfect, but good enough to see what's going on:

Sort NSMutableArray based on strings from another NSArray

I have an NSArray of strings that I want to use as my sort order:
NSArray *permissionTypes = [NSArray arrayWithObjects:#"Read", #"Write", #"Admin", nil];
I then have a NSMutableArray that may or may not have all three of those permissions types, but sometimes it will only be 2, sometimes 1, but I still want it sorted based on my permissionsTypes array.
NSMutableArray *order = [NSMutableArray arrayWithArray:[permissions allKeys]];
How can I always sort my order array correctly based on my using the permissionTypes array as a key?
I would go about this by creating a struct or an object to hold the permission types.
Then you can have...
PermissionType
--------------
Name: Read
Order: 1
PermissionType
--------------
Name: Write
Order: 2
and so on.
Then you only need the actual array of these objects and you can sort by the order value.
[array sortUsingComparator:^NSComparisonResult(PermissionType *obj1, PermissionType *obj2) {
return [obj1.order compare:obj2.order];
}];
This will order the array by the order field.
NSMutableArray *sortDescriptors = [NSMutableArray array];
for (NSString *type in permissionTypes) {
NSSortDescriptor *descriptor = [[[NSSortDescriptor alloc] initWithKey:type ascending:YES] autorelease];
[sortDescriptors addObject:descriptor];
}
sortedArray = [myArray sortedArrayUsingDescriptors:sortDescriptors];
Use whichever sorting method on NSMutableArray you prefer, you will either provide a block or a selector to use for comparing two elements. In that block/selector rather than comparing the two strings passed in directly look each up in your permissionTypes array using indexOfObject: and compare the resulting index values returned.
I suggest you another approuch:
- (void)viewDidLoad
{
[super viewDidLoad];
arrayPermissions = [[NSMutableArray alloc] init];
NSDictionary *dicRead = [NSDictionary dictionaryWithObjectsAndKeys:
#"Read", #"Permission", nil];
NSDictionary *dicWrite = [NSDictionary dictionaryWithObjectsAndKeys:
#"Write", #"Permission", nil];
NSDictionary *dicAdmin = [NSDictionary dictionaryWithObjectsAndKeys:
#"Admin", #"Permission", nil];
NSLog(#"my dicRead = %#", dicRead);
NSLog(#"my dicWrite = %#", dicWrite);
NSLog(#"my dicAdmin = %#", dicAdmin);
[arrayPermissions addObject:dicRead];
[arrayPermissions addObject:dicWrite];
[arrayPermissions addObject:dicAdmin];
NSLog(#"arrayPermissions is: %#", arrayPermissions);
// create a temporary Dict again
NSDictionary *temp =[[NSDictionary alloc]
initWithObjectsAndKeys: arrayPermissions, #"Permission", nil];
// declare one dictionary in header class for global use and called "filteredDict"
self.filteredDict = temp;
self.sortedKeys =[[self.filteredDict allKeys]
sortedArrayUsingSelector:#selector(compare:)];
NSLog(#"sortedKeys is: %i", sortedKeys.count);
NSLog(#"sortedKeys is: %#", sortedKeys);
}
hope help

How to switch two values in an NSDictionary in Objective-C?

I have an NSDictionary with two values. Now I want to switch the values. Here is my code:
NSDictionary *aDictionary = [[NSDictionary alloc] init];
[aDictionary setValue:#"theValue1" forKey:#"theKey1"];
[aDictionary setValue:#"theValue2" forKey:#"theKey2"];
NSString *tmpValue = [aDictionary objectForKey:#"theKey1"];
[aDictionary setValue:[myDict objectForKey:#"theKey2"] forKey:#"theKey1"];
[aDictionary setValue:tmpValue forKey:[myDict objectForKey:#"theKey2"]];
NSLog(#"%#", myDict);
//output
theKey1 = theValue2;
theKey2 = theValue2;
theValue2 = theValue1;
What am I doing wrong?
Other than a couple of larger problems (you should be using NSMutableDictionary instead of NSDictionary if you want to change things, and you should use the setObject:forKey: method instead of the setValue:forKey: method), the root of your problem is this line:
[aDictionary setValue:tmpValue forKey:[myDict objectForKey:#"theKey2"]];
Think about what key you're setting.

Can I update an object stored in two collections by changing it in just one?

If I have something like this:
SomeObject *obj = [[SomeObject alloc] init];
obj.someIvar = 100;
NSMuteableArray *arr = [[NSMutableArray alloc] initWithCapacity:10];
[arr addObject:obj];
NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithCapacity:50];
[dict setValue:obj forKey:#"key"];
[obj release];
Can I update obj like so:
SomeObject *objFromDict = [dict objectForKey:#"key"];
objFromDict.someIvar = 5200;
...and expect the object in arr to be updated as well? I'm assuming collections are storing and giving out pointers.
Yes, you are right.
In NSMuteableArray *arr and NSMutableDictionary *dict will be stored reference to object SomeObject *obj. When you are calling [dict objectForKey:#"key"]; you get this reference and in expression objFromDict.someIvar = 5200; you are modifying property someIvar.
When you will try to get the same object from arr the value of someIvar will be also changed because of arrays and dictionaries just store references to instances.

NSMutable Dictionary adding objects

Is there a more efficient way to add objects to an NSMutable Dictionary than simple iteration?
Example:
// Create the dictionary
NSMutableDictionary *myMutableDictionary = [NSMutableDictionary dictionary];
// Add the entries
[myMutableDictionary setObject:#"Stack Overflow" forKey:#"http://stackoverflow.com"];
[myMutableDictionary setObject:#"SlashDotOrg" forKey:#"http://www.slashdot.org"];
[myMutableDictionary setObject:#"Oracle" forKey:#"http://www.oracle.com"];
Just curious, I'm sure that this is the way it has to be done.
NSDictionary *entry = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithDouble:acceleration.x], #"x",
[NSNumber numberWithDouble:acceleration.y], #"y",
[NSNumber numberWithDouble:acceleration.z], #"z",
[NSDate date], #"date",
nil];
If you have all the objects and keys beforehand you can initialize it using NSDictionary's:
dictionaryWithObjects:forKeys:
Of course this will give you immutable dictionary not mutable. It depends on your usage which one you need, you can get a mutable copy from NSDictionary but it seems easier just to use your original code in that case:
NSDictionary * dic = [NSDictionary dictionaryWith....];
NSMutableDictionary * md = [dic mutableCopy];
... use md ...
[md release];
Allow me to add some information to people that are starting.
It is possible to create a NSDictionary with a more friendly syntax with objective-c literals:
NSDictionary *dict = #{
key1 : object1,
key2 : object2,
key3 : object3 };
NSMutableDictionary *example = [[NSMutableDictionary alloc]initWithObjectsAndKeys:#5,#"burgers",#3, #"milkShakes",nil];
The objects come before the keys.