NSDictionary into a NSInputStream - objective-c

Is it possible to put in my NSDictionary into a NSInputStream?
This would be my NSDictionary
NSArray *keys = [NSArray arrayWithObjects:#"name", #"device_token", #"identifier", nil];
NSArray *values = [NSArray arrayWithObjects:#"Test iPhone", initDeviceToken, [UIDevice currentDevice].uniqueIdentifier, nil];
NSDictionary *parameters = [NSDictionary dictionaryWithObjects:values forKeys:keys];
I tried something like this but it didn't worked...
NSInputStream *inputStream = [[NSInputStream alloc] init];
[inputStream setValue:#"123" forKey:#"identifier"];
Thx a lot

Sure. The way you can do it is serialize your dictionary into an NSData object using NSPropertyListSerialization, and then write your data object out to your NSInputStream.
The downside is that this requires that your dictionary only hold plist objects (numbers, strings, dates, data, arrays, and dictionaries).

Yes.
Any object that conforms to the NSCoding protocol is serializable and as such writable to a stream. Of course the items in a container object must also conform to the NSCoding protocol.

Related

Storing dictionary of dictionaries in NSUserDefaults

I am trying to store a dictionary which contains two dictionaries in NSUserDefaults.
NSUserDefaults *def = [NSUserDefaults standardUserDefaults];
NSDictionary *defDict = [def dictionaryRepresentation];
defaultTopics = [[NSArray alloc] initWithObjects:#"Animals",
#"Numbers",
#"AroundTown",
#"Actions", nil];
defaultValues = [[NSArray alloc] initWithObjects:#1, #0, #0, #0, nil];
NSDictionary *dd = [[NSDictionary alloc] initWithObjects:defaultValues forKeys:defaultTopics];
NSDictionary *de = [[NSDictionary alloc] initWithObjects:#[dd, dd] forKeys:#[#"English", #"Indonesian"]];
[defDict setValue:de forKey:#"UnlockedTopics"];
[def synchronize];
After this, NSLog(#"%#", [def dictionaryRepresentation]);, prints the correct dictionary, as long as I don't quit the app everything is as expected. But then, if I quit the app and relaunch,
[defDict objectForKey:#"UnlockedTopics"]
is always nil. What is the reason, and how to fix this?
The reason the dictionary of dictionaries is not getting stored is that you are never storing it. All you're doing is setting the key of a dictionary. You are calling
[defDict setValue:de forKey:#"UnlockedTopics"];
But that is not the same thing as setting any #"UnlockedTopics" key-value pair in NSUserDefaults. If you want to write to NSUserDefaults, write to it - e.g. by sending setObject:forKey: to NSUserDefaults.

NSMutableDictionary won't save data

hope someone can help me with a problem I've been wrestling with...
Using MapBox to develop a map-based app, and I want to attach an NSMutableDictionary to each of the map annotations to store additional data. I had it working but XCode kept throwing me warning about some of my data/object types, so I went through and tidied those up, and now it's broken. The idea is that on ViewDidLoad, the program runs through a set of plist dictionaries to set up each annotation correctly - that's still running okay, because my initial anno markers pop up with their correct settings. However rather than run back to the plist every time, I want to attach a dictionary to each annotation's userinfo property, which I can then use for toggling selection data and other functions. Here's my code:
NSDictionary *ExploreSteps = [[NSDictionary alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"ExploreSteps" ofType:#"plist"]];
for (NSString *key in [ExploreSteps allKeys])
{
//Loop through keys for each anno
NSDictionary *thisStep = [ExploreSteps objectForKey:key];
NSNumber *annoIndex = [thisStep objectForKey:#"Index"];
NSNumber *isLive = [thisStep valueForKey:#"isLive"];
NSString *annoTitle = [thisStep objectForKey:#"Title"];
NSString *annoText = [thisStep objectForKey:#"Text"];
NSString *imagefile = [thisStep objectForKey:#"Imagefile"];
double longitude = [[thisStep objectForKey:#"Longitude"] doubleValue];
double latitude = [[thisStep objectForKey:#"Latitude"] doubleValue];
NSString *pagefile = [thisStep objectForKey:#"Pagefile"];
NSString *audiofile = [thisStep objectForKey:#"Audiofile"];
CLLocationCoordinate2D annoCoord = CLLocationCoordinate2DMake(latitude, longitude);
RMAnnotation *annotation = [[RMAnnotation alloc] initWithMapView:mapView coordinate:annoCoord andTitle:annoTitle];
annotation.annotationIcon = [UIImage imageWithContentsOfFile: [[NSBundle mainBundle] pathForResource:imagefile ofType:#"png"]];
annotation.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:annoIndex, #"index", isLive, #"isLive", annoTitle, #"annoTitle", annoText, #"annoText", imagefile, #"imagefile", pagefile, #"pagefile", audiofile, #"audiofile", nil];
NSLog(#"Title: %#",[annotation.userInfo objectForKey:#"annoTitle"]);
[mapView addAnnotation:annotation];
}
The NSLog should spit out the annoTitle string, but instead it's giving me a null every time, and the behaviour of the rest of the app also shows that info stored in the dictionary simply isn't "getting through".
Any ideas? Thanks in advance!
ETA: Modified code for initializing the dictionary (not that it seems to make any difference to the problem!):
NSMutableDictionary *myUserInfo = [[NSMutableDictionary alloc] initWithObjectsAndKeys:annoIndex, #"index", isLive, #"isLive", annoTitle, #"annoTitle", annoText, #"annoText", imagefile, #"imagefile", pagefile, #"pagefile", audiofile, #"audiofile", nil];
annotation.userInfo = myUserInfo;
NSLog(#"Title: %#",[annotation.userInfo objectForKey:#"annoTitle"]);
NSLog(#"Length: %u",[[annotation.userInfo allKeys] count]);
(Title now returns "(null)", while Length returns "1", if that's at all helpful...)
Almost certainly one of your objects is nil. You mention that allKeys] count] returns 1 so I can go further and say that your value for isLive is nil. Hence your original line:
[NSMutableDictionary dictionaryWithObjectsAndKeys:annoIndex, #"index", isLive, #"isLive", annoTitle, #"annoTitle", annoText, #"annoText", imagefile, #"imagefile", pagefile, #"pagefile", audiofile, #"audiofile", nil];
Acts exactly the same as:
[NSMutableDictionary dictionaryWithObjectsAndKeys:annoIndex, #"index", nil, #"isLive", annoTitle, #"annoTitle", annoText, #"annoText", imagefile, #"imagefile", pagefile, #"pagefile", audiofile, #"audiofile", nil];
And the dictionary takes annoIndex to be the final key-value pair.
I'd suggest that probably you want to take a mutable copy of thisStep and strip out the keys you don't want, then pass it along as the userInfo.
It's the way you are creating the NSMutableDictionary for userInfo. Take a look at this Difference between [[NSMutableDictionary alloc] initWithObjects:...] and [NSMutableDictionary dictionaryWithObjects:...]?
"
+dictionaryWithObjects: returns an autoreleased dictionary
-initWithObjects: you must release yourself
if you want the dictionary to persist as a instance variable, you should create it with an init method or retain an autoreleased version, either way you should be sure to release it in your dealloc method
"

How to convert json string to nsdictionary on json parser framework on objective c

I am trying to convert raw json string to NSDictionary. but on NSDictionary i got different order of objects as on json string but i need exactly same order in NSDictionary as on json string. following is code i have used to convert json string
SBJSON *objJson = [[SBJSON alloc] init];
NSError *error = nil;
NSDictionary *dictResults = [objJson objectWithString:jsonString error:&error];
From NSDictionary's class reference:
The order of the keys is not defined.
So, basically you can't do this when using a standard NSDictionary.
However, this may be a good reason for subclassing NSDictionary itself. See this question about the details.
NSDictionary is an associative array and does not preserve order of it's elements. If you know all your keys, then you can create some array, that holds all keys in correct order (you can also pass it with your JSON as an additional parameter). Example:
NSArray* ordered_keys = [NSArray arrayWithObjects: #"key1", #"key2", #"key3", .., nil];
for(NSString* key is ordered_keys) {
NSLog(#"%#", [json_dict valueForKey: key]);
}
//parse out the json data
NSError* error;
NSDictionary* json = [NSJSONSerialization
JSONObjectWithData:responseData //1
options:kNilOptions
error:&error];
NSArray* latestLoans = [json objectForKey:#"loans"]; //2
NSLog(#"loans: %#", latestLoans); //3
Source: Follow this link http://www.raywenderlich.com/5492/working-with-json-in-ios-5
Good tutorial but works only on iOS5

IOS Category on NSArray Causes "instance message does not declare a method with selector"

I am trying to use the Category described in this article:
http://iphonedevelopment.blogspot.com/2008/10/shuffling-arrays.html
I have setup the following:
// NSArray+Shuffle.h
#import <Foundation/Foundation.h>
#interface NSArray (Shuffle)
-(NSArray *)shuffledArray;
#end
// NSArray+Shuffle.m
#import "NSArray+Shuffle.h"
#implementation NSArray (Shuffle)
-(NSArray *)shuffledArray
{
NSMutableArray *array = [NSMutableArray arrayWithCapacity:[self count]];
NSMutableArray *copy = [self mutableCopy];
while ([copy count] > 0)
{
int index = arc4random() % [copy count];
id objectToMove = [copy objectAtIndex:index];
[array addObject:objectToMove];
[copy removeObjectAtIndex:index];
}
// Using IOS 5 ARC
// [copy release];
return array;
}
#end
Then in my code that I want to use this, I imported the Category:
#import "NSArray+Shuffle.h"
Then, I attempted to use it like this:
NSArray *orderedGallary = [[NSArray alloc] initWithObjects:
[NSDictionary dictionaryWithObjectsAndKeys:
#"Pic1", #"pageName",
[UIImage imageNamed:#"Pic1.jpg"],#"pageImage",
nil],
[NSDictionary dictionaryWithObjectsAndKeys:
#"Pic2", #"pageName",
[UIImage imageNamed:#"Pic2.jpg"],#"pageImage",
nil],
nil];
NSArray *shuffler = [[NSArray alloc] shuffledArray:orderedGallary];
_pageData = [shuffler shuffledArray:orderedGallary];
But, I get the following compiler error message:
ModelController.m: error: Automatic Reference Counting Issue: Receiver type 'NSArray' for instance message does not declare a method with selector 'shuffledArray:'
Any ideas?
shuffledArray is a method that takes no parameters, it is different from shuffledArray:, which is a method that takes one parameter.
It looks like what you meant was:
NSArray* shuffled = [orderedGallery shuffledArray];
Here you are sending this message to your original array, and it returns a new array that is shuffled.
You're trying too hard. You only need to send -shuffledArray to orderedGallery.
NSArray *orderedGallary = [[NSArray alloc] initWithObjects:
[NSDictionary dictionaryWithObjectsAndKeys:
#"Pic1", #"pageName",
[UIImage imageNamed:#"Pic1.jpg"],#"pageImage",
nil],
[NSDictionary dictionaryWithObjectsAndKeys:
#"Pic2", #"pageName",
[UIImage imageNamed:#"Pic2.jpg"],#"pageImage",
nil],
nil];
_pageData = [orderedGallery shuffledArray];
See how you have declared shuffledArray not to take any arguments? Simply sending this message to any instance of NSArray will return your shuffled array.
shuffledArray does not take a parameter but is called directly on the array:
NSArray *myShuffledArray = [orderedGallery shuffledArray]
You have declared (in the .h) and defined (in the .m) a method named shuffledArray.
You are calling a method named shuffledArray: (notice the colon, which indicates an argument).
You want to be calling
NSArray *shuffled = [orderedGallery shuffledArray];
you don't need the argument because you are sending the method to the ordered array.
(There's no object that's actually a "shuffler" - independent of the array - so I wouldn't use that name as the variable name. The array is shuffling a copy of itself and returning the new shuffled array.)

Change from a NSMutableArray to a .plist

I have been working through several tutorials on uitableviews.
I have put, as instructed, all the info into a 'listofitems' as below
listOfItems = [[NSMutableArray alloc] init];
NSArray *countriesToLiveInArray = [NSArray arrayWithObjects:#"Iceland", #"Greenland", #"Switzerland", #"Norway", #"New Zealand", #"Greece", #"Rome", #"Ireland", nil];
NSDictionary *countriesToLiveInDict = [NSDictionary dictionaryWithObject:countriesToLiveInArray forKey:#"Countries"];
NSArray *countriesLivedInArray = [NSArray arrayWithObjects:#"India", #"U.S.A", nil];
NSDictionary *countriesLivedInDict = [NSDictionary dictionaryWithObject:countriesLivedInArray forKey:#"Countries"];
[listOfItems addObject:countriesToLiveInDict];
[listOfItems addObject:countriesLivedInDict];
This creates a sectioned table view. I would like to know how to change it into a .plist instead of typing it all out into the RootViewController.m. I would still like it to be in a sectioned tableview.
Is there a simple method for changing from this NSMutableArray,NSArray and NSDictionary to a plist?
There's a simple method for this writeToFile:atomically::
[listOfItems writeToFile:destinationPath atomically:YES];
This will automatically create a file with plist inside it.
that sorta depends on what you want in a plist, and what you put into it. if the entries and contents are all CFPropertyList types (CFString,CFDate,CFData,CFDictionary,CFArray,CFNumber...) then just create it with something like CFPropertyListCreateDeepCopy.
if you have non-convertible custom objects (e.g., your own NSObject subclasses), then see the cocoa archiving topics.
This is the simple function end hear relization
This is function is updating NSArray
- (void) WriteRecordToFile:(NSMutableDictionary*)countDict {
// Here to write to file
databasePathCallCount = #"plist path";
NSMutableArray *countArray = [NSMutableArray arrayWithContentsOfFile:databasePathCallCount];
if(countArray)
[countArray addObject:countDict];
[countArray writeToFile:databasePathCallCount atomically:NO];
}