Downloading Remote PLIST iOS - Returning Null - iphone

Struggling with this one. Looking to download a read only plist for use inside my app...
However struggling to read the contents in a Dictionary... Code below, any pointers would be great..
-(void)loadProducts {
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfURL:[NSURL URLWithString:#"https://dl.dropboxusercontent.com/s/f1nmq1wa7gs96dp/Region1Products.plist"]];
for (NSDictionary* productDictionary in dict) {
ProductItem* productItem = [[ProductItem alloc] init];
productItem.picturesCount = [productDictionary objectForKey:#"PicturesCount"];
productItem.maxPicturesCount = [productDictionary objectForKey:#"MaxPicturesCount"];
productItem.size = [productDictionary objectForKey:#"Size"];
productItem.previewImageName = [productDictionary objectForKey:#"ImageName"];
productItem.sequence = [productDictionary objectForKey:#"Sequence"];
productItem.productName = [productDictionary objectForKey:#"Name"];
productItem.type = [productDictionary objectForKey:#"ProductType"];
productItem.prices = [productDictionary objectForKey:#"Prices"];
productItem.shippingPrices = [productDictionary objectForKey:#"ShippingPrices"];
productItem.description = [productDictionary objectForKey:#"Description"];
productItem.popupMessage = [productDictionary objectForKey:#"PopupMessage"];
productItem.popupDetailMessage = [productDictionary objectForKey:#"PopupDetailMessage"];
productItem.incrementalPricing = [[productDictionary objectForKey:#"IncrementalPricing"] boolValue];
if (YES == productItem.incrementalPricing) {
productItem.incrementalPrices = [productDictionary objectForKey:#"IncrementalPrices"];
}
NSArray *previewItems = [productDictionary objectForKey:#"PreviewItems"];
for (NSDictionary* previewItem in previewItems) {
[productItem addProductPreviewItemFromDictionary:previewItem];
}
[self.productsList addObject:productItem];
}

You're creating an NSDictionary from the url, but the top level object in that plist is an array. To solve this, you can change dict to an NSArray object. I used the following simplified code to test this:
NSArray *array = [NSArray arrayWithContentsOfURL:[NSURL URLWithString:#"https://dl.dropboxusercontent.com/s/f1nmq1wa7gs96dp/Region1Products.plist"]];
for (NSDictionary* productDictionary in array) {
NSLog(#"%#",productDictionary);
}

Related

How to extract specific data has equal value for some key from NSDictionary into a combined NSArray

Right now i have a dictionary like this, it's just a example, i got A to Z:
(
{
id = 13;
name = "Roll";
firstLetter = R;
},
{
id = 14;
name = "Scroll";
firstLetter = S;
},
{
id = 16;
name = "Rock";
firstLetter = R;
},
{
id = 17;
name = "Start";
firstLetter = S;
}
)
I want to extract the dict has the same firstLetter and combine these into a NSArray object. The expected results like this:
R array:
(
{
id = 13;
name = "Roll";
firstLetter = R;
},
{
id = 16;
name = "Rock";
firstLetter = R;
}
)
and S array:
(
{
id = 14;
name = "Scroll";
firstLetter = S;
},
{
id = 17;
name = "Start";
firstLetter = S;
}
)
How to do that?
I believe the better method would be the one suggested by Saohooou
But it can be optimised as
NSArray *array = #[#{#"id": #13,#"name":#"Roll",#"firstLetter":#"R"},
#{#"id": #14,#"name":#"Scroll",#"firstLetter":#"S"},
#{#"id": #15,#"name":#"Rock",#"firstLetter":#"R"},
#{#"id": #16,#"name":#"Start",#"firstLetter":#"S"}];
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
[array enumerateObjectsUsingBlock:^(NSDictionary *dict, NSUInteger idx, BOOL *stop) {
NSString *key = dict[#"firstLetter"];
NSMutableArray *tempArray = dictionary[key];
if (!tempArray) {
tempArray = [NSMutableArray array];
}
[tempArray addObject:dict];
dictionary[key] = tempArray;
}];
NSLog(#"%#",dictionary);
NSMutableDictionay *dic = [NSMutableDictionay dictionay];
for ( YourObject *obj in yourDic.allValues )
{
NSMutableArray *dateArray = dic[obj.firstLetter];
if ( !dateArray )
{
dateArray = [NSMutableArray array];
[dic setObject:dateArray forKey:obj.firstLetter];
}
[dateArray addObject:obj];
}
so dic is what you want
I assume you organized the dict as an NSArray.
NSMutableDictionary* result = [NSMutableDictionary dictionary]; // NSDictionary of NSArray
for (id entry in dict) {
NSString* firstLetter = [entry firstLetter];
// Find the group of firstLetter
NSMutableArray* group = result[firstLetter];
if (group == nil) {
// No such group --> create new a new one and add it to the result
group = [NSMutableArray array];
result[firstLetter] = group;
}
// Either group has existed, or has been just created
// Add the entry to it
[group addObject: entry];
}
result holds what you want.
try this
NSString *currentStr;
//this int is to detect currentStr
NSInteger i;
NSMutableArray* R_Array = [[NSMutableArray alloc] init];
NSMutableArray* S_Array = [[NSMutableArray alloc] init];
for (NSDictionary *myDict in MyDictArray){
NSString *tempStr = [myDict objectForKey:#"firstLetter"];
if(currentStr = nil && [currentStr isEqualToString:""]){
currentStr = tempStr;
if([currentStr isEqualToString:"R"] ){
[R_Array addObject:myDict];
i = 0;
}else{
[S_Array addObject:myDict];
i = 1;
}
}else{
if([currentStr isEqualToString:tempStr]){
(i=0)?[R_Array addObject:myDict]:[S_Array addObject:myDict];
}else{
(i=0)?[R_Array addObject:myDict]:[S_Array addObject:myDict];
}
}
}
Base on your dictionaries. There are only two type, so i just created two array and use if-else for solving the problem. if there are multy values, you can try switch-case to do it.
Lets do this
NSMutaleDictionary * speDict = [[NSMutableDictionary alloc] init];
for(i=0;i<26;i++){
switch (i){
case 0:
[speDict setObject:[NSMutableArray alloc] init] forKey:#"A"];
break;
case 1:
[speDict setObject:[NSMutableArray alloc] init] forKey:#"B"];
break;
Case 2:
[speDict setObject:[NSMutableArray alloc] init] forKey:#"C"];
break;
...........
Case 25:
[speDict setObject:[NSMutableArray alloc] init] forKey:#"Z"];
break;
}
}
for (NSDictionary *myDict in MyDictArray){
NSString *tempStr = [myDict objectForKey:#"firstLetter"];
switch (tempStr)
case A:
[self addToMySpeDictArrayWithObject:myDict andStr:temStr];
break;
case B:
[self addToMySpeDictArrayWithObject:myDict andStr:temStr];
break;
Case C:
[self addToMySpeDictArrayWithObject:myDict andStr:temStr];
break;
...........
Case Z:
[self addToMySpeDictArrayWithObject:myDict andStr:temStr];
break;
}
-(void)addToMySpeDictArrayWithObject:(NSDictionary*)_dict andStr:(NString*)_str
{
NSMutableArray *tempArray = [speDict objectForKey:_str];
[tempArray addObject:_dict];
}
then the speDict is like
A:
//all firstletter is A
myDict
myDict
myDict
B:
//all firstletter is B
myDict
myDict
.......
First of all the sample you've provided is an array of dicts (not a dict as the question notes). Now, the easiest way to query this array is by using an NSPredicate. Something like this perhaps:
NSArray *objects = ...; // The array with dicts
NSString *letter = #"S"; // The letter we want to pull out
NSPredicate *p = [NSPredicate predicateWithFormat:#"firstLetter == %#", letter];
NSArray *s = [objects filteredArrayUsingPredicate:p]; // All the 'S' dicts
If for some reason you need to group all of your objects without having to ask for a specific letter each time, you could try something like this:
// Grab all available firstLetters
NSSet *letters = [NSSet setWithArray:[objects valueForKey:#"firstLetter"]];
for (NSString *letter in letters)
{
NSPredicate *p = [NSPredicate predicateWithFormat:#"firstLetter == %#", letter];
NSArray *x = [objects filteredArrayUsingPredicate:p];
// Do something with 'x'
// For example append it on a mutable array, or set it as the object
// for the key 'letter' on a mutable dict
}
And of course you could further optimize this approach by implementing a method for filtering the array based on a letter. I hope that this makes sense.

Dictionary Value retrieve

In my application ,the dictionary value contains following content.How to retrieve the each and store it new array
contryArray(
{
checka0 = Thailand;
checka1 = Brazil;
checka10 = Marocco;
checka11 = Thailand;
checka12 = Jordan;
checka13 = Colombia;
checka14 = Kuwait;
checka3 = Mexico;
checka4 = "Saoudi Arabia";
checka5 = Chili;
checka7 = Australia;
checka8 = Malta;
checka9 = "South Africa";
checkb0 = havana;
checkb1 = Santos;
checkb10 = Casablanca;
checkb11 = Bangkok;
checkb12 = Aqaba;
checkb13 = Havana;
checkb14 = Shuwaikh;
checkb3 = Veracruz;
checkb4 = Jeddah;
checkb5 = "San Antonio";
checkb7 = Maersk;
checkb8 = Maraxklokk;
checkb9 = Durban;
checkc0 = 1;
checkc1 = "0.7";
checkc10 = 1;
checkc11 = "1.2";
checkc12 = 1;
checkc13 = "1.4";
checkc14 = 1;
checkc3 = "0.9";
checkc4 = "0.8";
checkc5 = "0.9";
checkc7 = "2.7";
checkc8 = "0.8";
checkc9 = "0.9";
}
For ex: checka0-checka14 in one array, Here the problem is checka2 and checka6 is not available, Im new bee in xcode,Please help me to retrieve
Your question is not clear. Possibly you need to get all keys in your dictionary and separating each item with specific word in it(checka/checkb/checkc).
If that is the case then,
You will get all the keys using:
NSArray *dictKeys = [yourDictionary allKeys];
You can implement this in multiple ways, one of them:
For storing it in same array:
for (NSString *key in [yourDictionary allKeys])
{
[yourArray addObject:[yourDictionary objectForKey:key]];
}
For storing it in seperate arrays:
for (NSString *key in [yourDictionary allKeys])
{
if([key rangeOfString:#"checka"].location != NSNotFound)
{
//add checka to first array
[yourFirstArray addObject:[yourDictionary objectForKey:key]];
}
else if([key rangeOfString:#"checkb"].location != NSNotFound)
{
//add checkb to second array
[yourSecondArray addObject:[yourDictionary objectForKey:key]];
}
...
}
if contryArray is your dictionary then access it as follow
[contryArray valueForKey:#"checka0"];
and go on adding this values to another array
You can use the following code:
- (void)filterDictionary:(NSDictionary *)dict
{
NSArray *allKeys = [dict allKeys];
NSMutableArray *allValues = [[NSMutableArray alloc]init];
for(id key in allKeys)
{
id value = [dict valueForKey:key];
[allValues addObject:[value stringValue]];
}
}

NSCFString objectForKey unrecognized selector sent to instance

//initialize the people data list
- (void)initializePeopleListFromJson:(CLLocationCoordinate2D)coordinate auraId:(NSString *)auraId
{
//initialize the NSMutableArray list
self.peopleList = [[NSMutableArray alloc] init];
//retrieve the coordinate of myself
//NSString *myCoordinate = [NSString stringWithFormat:#"%f,%f", coordinate.latitude, coordinate.longitude];
NSString *myCoordinate = #"31.2,121.6";
NSString *url = [NSString stringWithFormat:#"%#%#%#%#", #"http://services.portaura.mobi/AuraMesh/auraFinder/findPeoples?ll=", myCoordinate, #"&source=tencent,netease,kaixin&myAuraId=", auraId];
NSLog(#"*********** %#", url);
//retrieve the people list from web service
NSDictionary* result = [NSDictionary dictionaryWithContentsOfJSONURLString:url];
NSArray *peopleListFromJson = [result objectForKey:#"data"];
// NSLog(#"peopleList: %#", peopleListFromJson);
People *people;
UserProfile *userProfile;
NSDictionary *geoFromJson;
NSDictionary *profileFromJson;
for (NSDictionary *peopleFromJson in peopleListFromJson)
{
people = [[People alloc] init];
userProfile = [[UserProfile alloc] init];
people.foreignId = [peopleFromJson objectForKey:#"foreignId"];
people.id1 = [peopleFromJson objectForKey:#"id"];
people.isFavorited = [peopleFromJson objectForKey:#"isFavorited"];
people.lastActiveTime = [peopleFromJson objectForKey:#"lastActiveTime"];
people.lastActivity = [peopleFromJson objectForKey:#"lastActivity"];
people.lastPlace = [peopleFromJson objectForKey:#"lastPlace"];
people.source = [peopleFromJson objectForKey:#"source"];
NSLog(#"AAAAAAAA %#", [peopleFromJson objectForKey:#"foreignId"]);
//process geo
geoFromJson = [[NSDictionary alloc] init];
geoFromJson = [peopleFromJson objectForKey:#"geo"];
CLLocationCoordinate2D coordinate;
coordinate.latitude = [[geoFromJson objectForKey:#"lat"] floatValue];
coordinate.longitude = [[geoFromJson objectForKey:#"lng"] floatValue];
people.geo = coordinate;
people.distance = [geoFromJson objectForKey:#"distance"];
//process profile
profileFromJson = [[NSDictionary alloc] init];
profileFromJson = [peopleFromJson objectForKey:#"profile"];
people.avatar = [profileFromJson objectForKey:#"avatar"];
people.gender = [profileFromJson objectForKey:#"gender"];
people.location = [profileFromJson objectForKey:#"location"];
people.screenName = [profileFromJson objectForKey:#"screenName"];
people.signature = [profileFromJson objectForKey:#"sigunature"];
//people.userProfile = userProfile;
[self addPeople:people];
}
}
it give me the [__NSCFString objectForKey:]: unrecognized selector sent to instance 0x1808d0,can you give some advice
json like :
{"status":0,"data":{"list":[{"foreignId":"8827857641648129226","geo":{"distance":1359,"lat":31.20926508184017,"lng":121.59068046014856},"id":"netease_8827857641648129226","isFavorited":false,"lastActiveTime":"2012-05-19T20:26:47Z","lastActivity":"Goal http://126.fm/kFEKl","lastPlace":"","profile":{"avatar":"http://oimagea3.ydstatic.com/image?w=48&h=48&url=http%3A%2F%2Fmimg.126.net%2Fp%2Fbutter%2F1008031648%2Fimg%2Fface_big.gif","gender":0,"location":"","screenName":"4671784460","sigunature":"","tags": []},"source":"netease"}......
check ur variable class peopleFromJson it might not be a dictionary at the moment you are calling objectForKey.
put this statement as first line in ur for loop
NSLog(#"%#",NSStringFromClass([peopleFromJson class]));
i have solved the problem,i cannot think the problem is easy,maybe some people only know the cause is the object is NSString not NSDir,but the real problem is depend on json "style",sometimes my code is correct,but for other json is not correct for example my question json. so solved is :
if ( ![peopleListFromJson isKindOfClass:[NSArray class]] && peopleListFromJson!=nil) {
peopleListFromJson =[NSArray arrayWithObject:peopleListFromJson];
}
because i used
NSDictionary* result = [NSDictionary dictionaryWithContentsOfJSONURLString:url];
NSArray *peopleListFromJson = [result valueForKeyPath:#"data.list"];
so peopleListFromJson!=nil is impotent

Objective-C - Hello World app modification

I'm just learning to do the "Hello, World" app. But I have a question. I'd like to change the code so the result reads "World, Hello" but can't figure out what I'm doing wrong.
Here's the original code:
- (IBAction)changeGreeting:(id)sender {
self.userName = self.textField.text;
NSString *nameString = self.userName;
if ([nameString length] == 0) {
nameString = #"World";
}
NSString *greeting = [[NSString alloc] initWithFormat:#"Hello, %#!", nameString];
self.label.text = greeting;
}
and I thought it would work if I could change it to:
- (IBAction)changeGreeting:(id)sender {
self.userName = self.textField.text;
NSString *nameString = self.userName;
if ([nameString length] == 0) {
nameString = #"World";
}
NSString *greeting = [[NSString alloc] initWithFormat:nameString , #"Hello, %#!"];
self.label.text = greeting;
}
However that still didn't work. What would I do to make that work?
Change this line
NSString *greeting = [[NSString alloc] initWithFormat:nameString , #"Hello, %#!"];
To
NSString *greeting = [[NSString alloc] initWithFormat:#"%#, Hello!", nameString];
initWithFormat, uses place holder when you write #"%#, Hello!" the "%#" indicates that the following string nameString will be replaced by it
So when we #"%#, Hello!" we really mean #"nameString, Hello!" (nameString in your example is World)

NSMutableArray of Objects

First off I am very new to Objective C and iPhone programming. Now that that is out of the way. I have read through most of the Apple documentation on this and some third party manuals.
I guess I just want to know if I'm going about this the correct way ...
- (NSMutableArray *)makeModel {
NSString *api = #"http://www.mycoolnewssite.com/api/v1";
NSArray *namesArray = [NSArray arrayWithObjects:#"News", #"Sports", #"Entertainment", #"Business", #"Features", nil];
NSArray *urlsArray = [NSArray arrayWithObjects:
[NSString stringWithFormat:#"%#/news/news/25/stories.json", api],
[NSString stringWithFormat:#"%#/news/sports/25/stories.json", api],
[NSString stringWithFormat:#"%#/news/entertainment/25/stories.json", api],
[NSString stringWithFormat:#"%#/news/business/25/stories.json", api],
[NSString stringWithFormat:#"%#/news/features/25/stories.json", api], nil];
NSMutableArray *result = [NSMutableArray array];
for (int i = 0; i < [namesArray count]; i++) {
NSMutableDictionary *objectDict = [NSMutableDictionary dictionary];
NSString *name = (NSString *)[namesArray objectAtIndex:i];
NSString *url = (NSString *)[urlsArray objectAtIndex:i];
[objectDict setObject:name forKey:#"NAME"];
[objectDict setObject:url forKey:#"URL"];
[objectDict setObject:#"NO" forKey:#"HASSTORIES"];
[result addObject:objectDict];
}
return result;
}
The output of the result is ...
(
{
HASSTORIES = NO;
NAME = News;
URL = "http://www.mycoolnewssite.com/api/v1/news/news/25/stories.json";
},
{
HASSTORIES = NO;
NAME = Sports;
URL = "http://www.mycoolnewssite.com/api/v1/news/sports/25/stories.json";
},
{
HASSTORIES = NO;
NAME = Entertainment;
URL = "http://www.mycoolnewssite.com/api/v1/news/entertainment/25/stories.json";
},
{
HASSTORIES = NO;
NAME = Business;
URL = "http://www.mycoolnewssite.com/api/v1/news/business/25/stories.json";
},
{
HASSTORIES = NO;
NAME = Features;
URL = "http://www.mycoolnewssite.com/api/v1/news/features/25/stories.json";
}
)
Any insight would be appreciated ;-)
It looks fine. There can be some minor improvements if you care.
1.
[NSString stringWithFormat:#"%#/news/news/25/stories.json", api]
can be replaced by
[api stringByAppendingString:#"/news/news/25/stories.json"]
if there's no chance the api appears in the middle or accepts other arguments.
2.
NSString *name = (NSString *)[namesArray objectAtIndex:i];
NSString *url = (NSString *)[urlsArray objectAtIndex:i];
The explicit cast is unnecessary. An id can be implicitly casted to and from other ObjC objects.
3.
You could use a convenient method -dictionaryWithObjectsAndKeys: to construct the dictionary in one-shot, so you don't need a temperary dictionary:
[result addObject:[NSMutableDictionary dictionaryWithObjectsAndKeys:
name, #"NAME",
url, #"URL",
#"NO", #"HASSTORIES", nil]];
4. (optional)
This transform is not useful if the function is not a hot spot.
Since the arrays are only used locally, it's more efficient to use a C array.
static const int arraySize = 5;
NSString* namesCArray[] = {#"News", #"Sports", #"Entertainment", #"Business", #"Features"};
NSString* urlsCArray[arraySize];
urlsArray[0] = [api stringByAppendingString:#"/news/news/25/stories.json"];
...
for (int i = 0; i < arraySize; ++ i) {
...
NSString* name = namesCArray[i];
NSString* url = urlsCArray[i];
...
}
this removes the repeated -count and -objectAtIndex: calls which is very slow compared with direct element access.
5. (optional)
This transform is not useful if the array is short.
You could use fast-enumeration to loop over an ObjC container:
int i = 0;
for (NSString* name in namesArray) {
NSString* url = [urlsArray objectAtIndex:i];
...
++ i;
}
6.
Usually we use [NSNumber numberWithBool:NO] to represent a boxed true/false value, instead of a string #"NO". NSNumber is also used a lot whenever a primitive number (int, float, etc.) cannot be used (e.g. to be stored in an NSArray). I don't know if your API explicitly requires a string NO, so it may not unsuitable for you.