How to see if NSArray, created with valueForKey is empty - ios

I got an array:
NSArray *itemsArray = [self.tournamentDetails.groups valueForKey:#"Items"];
Where self.tournamentDetails.groups is an NSArray, build with a JSON string from a webRequest.
Items is sometimes empty and sometimes it contains objects. So i need an if statement to check if its empty or not. I've tried some different things like:
if ([itemsArray count]!=0)
if (!itemsArray || !itemsArray.count)
Problem is that if my Items object from valueForKey is empty then the itemsArray still contains an object looking like this
<__NSArrayI 0x178abef0>(
<__NSArrayI 0x16618c30>(
)
)
When theres items inside my Items object it looks like this:
<__NSArrayI 0x18262b70>(
<__NSCFArray 0x181e3a40>(
{
BirthDate = 19601006T000000;
ClubName = "Silkeborg Ry Golfklub";
ClubShortName = "";
CompletedResultSum = {
Actual = {
Text = 36;
Value = 36;
};
ToPar = {
Text = "";
Value = 0;
};
};
}
)
)
Meaning that [itemsArray count] is always equal to 1 or more, and then it jumps into the if statement when it should not.
Anyone know how i can create an if statement where if itemsArray contains "Items:[]" it will be skipped and if itemsArray contains "Items:[lots of objects]" it will run?
EDIT: Solution is to check up on the first index like this if([[itemsArray objectAtIndex:0] count] != 0) then run code.

Try this:
if(itemsArray && itemsArray.count>0) //be sure that it has value){
for(NSArray *item in itemsArray){
if(item.count > 0){
// you have an NSDictionary. Will process it
}else{
//item.count == 0 : this is an empty NSArray.
}
}
}

more simpler
for (id obj in itemsArray)
{
if([obj isKindOfClass:[NSArray class]])
{
if(obj.count > 0)
{
//your if condition here
}
}
}

Related

How to check the JSON format in objective c?

I will get the JSON Data like this. But I want to check whether key has an Array data or not. If It has 0 then skip. How can I check?
code = 200;
data = {
UserstoreReviewDetails = 0;
storeReviewDetails = 0;
}
or
code = 200;
data = {
UserstoreReviewDetails = (
{// array data}
);
storeReviewDetails = (
{// array data}
);
}
I have tried like this. But getting an exception if data has an Array value.
[[self.jsonValue[#"data"] objectForKey:#"storeReviewDetails"]intValue] != 0
[[self.jsonValue[#"data"] objectForKey:#"storeReviewDetails"] isEqualToString:#"0"]
// try like this
if([[[self.jsonValue[#"data"] objectForKey:#"storeReviewDetails"] isKindOfClass:[NSArray class]]) {
// data is array type
} else {
//data is not an array type
}
Try like this.
NSArray *array = [[self.jsonValue[#"data"] objectForKey:#"storeReviewDetails"];
if (array) {
NSLog("StoreReviewDetails is array");
}
else {
int count = [[self.jsonValue[#"data"] objectForKey:#"storeReviewDetails"]intValue];
}

Checking for zero length array from JSON set

I have JSON data set returned that I am parsing.
If the data contains a record it looks like this:
dictData: {
Recordset = (
{
Record = (
{
MyDate = "2016-06-15 11:04:43";
MyID = 53070;
SomeDescription = "";
}
);
}
);
}
If the data does NOT contains a record it looks like this:
Notice the "" in the return set which is causing me issues.
dictData: {
Recordset = (
""
);
}
I am having trouble accounting for the zero length array in the Recordset.
Here is my base code for parsing the data.
NSDictionary * dictData = [NSDictionary dictionaryWithDictionary:[someOtherDictionary objectForKey:#"Data"]];
NSArray * arrRecordSet = [dictData objectForKey:#"Recordset"];
if([arrRecordSet objectAtIndex:0] != nil) {
NSLog(#"CONTAINS RECORDS");
//Do something with the records
}
else {
NSLog(#"DOES NOT CONTAIN RECORDS");
}
I have tried various iterations of things like checking if [arrRecordSet objectAtIndex:0] length is greater than zero or checking the count size.
I think the double quotes are throwing me off.
Any help?
UPDATE
RAW JSON as requested
ONE RECORD
{
APIResponse = {
Data = {
Recordset = (
{
Record = (
{
MyDate = "2016-06-15 11:04:43";
MyID = 53070;
SomeDescription = "";
}
);
}
);
};
};
}
NO RECORDS
{
APIResponse = {
Data = {
Recordset = (
""
);
};
};
}
So in the case of success the Recordset value is an array with a dictionary and in the case of failure the Recordset value is an array with a string.
So:
NSArray *recordSet = response[#"APIResponse"][#"Data"][#"Recordset"];
if ([recordSet count] > 0 &&
[recordSet[0] isKindOfClass:[NSDictionary class]]) {
// Success
NSDictionary *record = recordSet[0];
...
} else {
// Failure
}
Here you should check first all key for dictionary Recordset if it returns you count>0 then you can say data is available and if not then there is a blank entry.

Save multiple values with same keys in NSMutableDictionary then store the dictionary in NSMutableArray

I know this question has been asked many times but not got the solution or i might not understood that's why posting the question.
for (int web=0; web<[web_arr count]; web++) {
AdditionalBookmark *web_book=[[AdditionalBookmark alloc]init];
UITextField *txtNam = (UITextField*)[self.view viewWithTag:1100+web];
NSString *txtName = txtNam.text;
UITextField *txtLin = (UITextField*)[self.view viewWithTag:1200+web];
NSString *txtLink = txtLin.text;
if ((txtName && txtName.length > 0)||(txtLink && txtLink.length > 0))
{
web_book.additionalBookmark_Name = txtName;
web_book.additionalBookmark_Link= txtLink;
web_book.contactDetails_Id=self.contactDetailsinfo.contactDetailsId;
web_book.additionalBookmark_Id=[[[web_arr objectAtIndex:web] valueForKey:#"WeblinkId"] intValue];
[dictWebLinks setObject:txtName forKey:#"WeblinkName"];
[dictWebLinks setObject:txtLink forKey:#"WeblinkUrl"];
[arrForWebLinks addObject:dictWebLinks];
}
[db updateIntoAdditionalBookmarkWithObject:web_book];
}
[dictUpdate setObject:arrForWebLinks forKey:#"Weblink"];
The problem am facing is this suppose there are two items in the array
Printing description of web_arr:
<__NSArrayM 0x170e4db60>(
{
WeblinkId = 9;
WeblinkName = Hdhd;
WeblinkUrl = "ie.comh";
},
{
WeblinkId = 10;
WeblinkName = Hd;
WeblinkUrl = "nd.com";
}
)
what i am getting is below:
Printing description of arrForWebLinks:
<__NSArrayM 0x170e4db30>(
{
WeblinkName = Hd;
WeblinkUrl = "nd.com";
},
{
WeblinkName = Hd;
WeblinkUrl = "nd.com";
}
)
dictionary is replacing the value for same key holding the latest value only, how can i mange to save the values in same format as in web_arr.
Any help is appreciable.
You are adding the same dictionary to the array over and over:
[dictWebLinks setObject:txtName forKey:#"WeblinkName"];
[dictWebLinks setObject:txtLink forKey:#"WeblinkUrl"];
[arrForWebLinks addObject:dictWebLinks];
You need to create a new one each time:
[arrForWebLinks addObject:#{
#"WeblinkName" : txtName,
#"WeblinkUrl" : txtLink
}];
(and remove dictWebLinks).

Adding NSDictionary keys with null values efficiently in ios5

I'm trying to add some values with keys in my dictionary for posting request to server. I have no issues on ios7 but having issue while creating dictionary in ios5, when a null value enters it doesnt insert that key or thereafter in the dictionary. This is a sample of my code
NSLog(#"name:%#, address:%#,city:%#, state:%#, country:%#, postal:%# ,phone:%#,age:%#, gender:%#",self.pop.firstNameTextField.text,self.pop.addressTextField.text, self.pop.cityTextField.text,[NSNumber numberWithInt:stateId],[NSNumber numberWithInt:countryId],self.pop.postalCodeTextField.text,self.pop.phoneNumberTextField.text,self.pop.ageTextField.text,self.pop.genderTextField.text);
NSDictionary *details = [NSDictionary dictionaryWithObjectsAndKeys:
self.pop.firstNameTextField.text,#"name",
self.pop.addressTextField.text,#"address",
self.pop.cityTextField.text,#"city",
[NSNumber numberWithInt:stateId],#"state",
[NSNumber numberWithInt:countryId],#"country",
self.pop.postalCodeTextField.text,#"postalCode",
self.pop.phoneNumberTextField.text,#"phoneNo",
self.pop.ageTextField.text,#"age",
self.pop.genderTextField.text,#"gender",
nil];
NSLog(#"MyDetails:%#",details);
Log result in ios 7:
name: GamerLegend,address:india,city:, state:1, country:1, postal: ,phone:, age:, gender:
MyDetails:
{
address = India;
age = "";
city = "";
country = 1;
gender = "";
name = "GamerLegend";
phoneNo = "";
postalCode = "";
state = 1;
}
Same Log result in ios5:
name: GamerLegend,address:haripad,city:(null), state:1, country:1, postal:(null) ,phone:(null), age:(null), gender:(null)
MyDetails:
{
address = India;
name = "GamerLegend";
}
I want the log of ios5 same as that of ios7. I did some search and I know I can compare the value beforehand to check if its null and then add to dictionary with empty string. But that will be so tedious. I was wondering if there is any other simple workaround for this. Is there any better solution?
This is my current solution
-(void) checkForNull
{
if([self.pop.firstNameTextField.text length] == 0)
self.pop.firstNameTextField.text=#"";
if([self.pop.addressTextField.text length] == 0)
self.pop.addressTextField.text=#"";
if([self.pop.cityTextField.text length] == 0)
self.pop.cityTextField.text=#"";
if([self.pop.postalCodeTextField.text length] == 0)
self.pop.postalCodeTextField.text=#"";
if([self.pop.phoneNumberTextField.text length] == 0)
self.pop.phoneNumberTextField.text=#"";
if([self.pop.ageTextField.text length] == 0)
self.pop.ageTextField.text=#"18";
if([self.pop.genderTextField.text length] == 0)
self.pop.genderTextField.text=#"";
}
This should work if it fits your requirements:
Create an array of EXPECTED keys. Then you loop through this and compare this with the output of the allKeys method in your dictionary. If a key is missing there you could add the missing key with an empty string, [NSNull null], or whatever floats your boat. (You would need to make the dictionary mutable of course).
Something like this:
for (NSString *expectedKey in allExpectedKeys) {
BOOL keyMissing = YES;
for (NSString *existingKey in [dictionary allKeys]) {
if ([expectedKey isEqualToString:existingKey]) {
keyMissing = NO;
break;
}
}
if (keyMissing) {
[dictionary setObject:[NSNull null] forKey:expectedKey];
}
}

Get an array of 3 ordered values whilst favouring a specified value

Sorry for the somewhat generic title, if anyone has a better suggestion please let me know.
Basically I am writing a custom leaderboard view whereby I want to show 3 scores only. If possible it will show the current user's score in the middle but, if the user is at the top or the bottom of the list, it should still show 3 scores but itll show another users above or below the list.
e.g.
Me (If I am top, then show 2 below)
User 1
User 2
or
User 1
Me (usual case where I am in the middle of two scores)
User 2
or
User 1
User 2
Me (If I am bottom show two scores above me)
I have a function written that does the first part of this but doesnt take into account edge cases which is what I am struggling with. Can anyone please advise?
-(void)getNearbyScores:(int)score{
GCLeaderboardScore *closestScoreAbove = nil; //Custom container for GC properties
GCLeaderboardScore *closestScoreBelow = nil; //Contains playerID, score, alias etc
if ([playerScores count] == 0){ //playerScores is an NSMutableDictionary
return;
}
for (NSString* key in playerScores) {
GCLeaderboardScore *playerScore = (GCLeaderboardScore *)[playerScores objectForKey:key];
if ((closestScoreAbove == nil || closestScoreAbove->score > playerScore->score) && playerScore->score > score){
closestScoreAbove = playerScore;
}
else if ((closestScoreBelow == nil || closestScoreAbove->score < playerScore->score) && playerScore->score < score){
closestScoreBelow = playerScore;
}
}
me->score = score;
me->rank = 1;
if (closestScoreAbove != nil) {
me->rank = closestScoreAbove->rank + 1;
nearbyScores = [NSMutableArray arrayWithObjects: closestScoreAbove, me, closestScoreBelow, nil];
}
else {
nearbyScores = [NSMutableArray arrayWithObjects: me, closestScoreBelow, nil];
}
}
Assuming there is a me GCLeaderboardScore object, the method below should return an array with the desired GCLeaderboardScore objects (untested):
-(NSArray *)getNearbyScores {
if(playerScores.count==0) return nil;
// Create an array sorted by score
NSArray *sortedByScore=[playerScores sortedArrayUsingComparator: ^(id object1, id object2) {
GCLeaderboardScore *score1=object1;
GCLeaderboardScore *score2=object2;
if(score1->score < score2->score) return NSOrderedAscending;
if(score1->score > score2->score) return NSOrderedDescending;
return NSOrderedSame;
}];
// Find index of me
NSUInteger idx=[sortedByScore indexOfObject:me];
// If me not found, return nil
if(idx==NSNotFound) return nil;
// Ideally we want to show the player before and behind
idx=MAX(0,(NSInteger)idx-1);
// maxIdx will be idx+2 or index of last object if lower
NSUInteger maxIdx=MIN(sortedByScore.count-1,idx+2);
// In case we are last, show two previous results (if array large enough)
if (maxIdx > 3)
idx=MAX(0,maxIdx-3);
// And return the objects, may be 1..3 objects
return [sortedByScore subarrayWithRange:NSMakeRange(idx,maxIdx-idx+1)];
}
I assume you have an array of scores. (Actual implementation can be adapted to your code)
Initialize:
firstScoreAbove = VERY_LARGE_SCORE; secondScoreAbove = VERY_LARGE_SCORE + 1;
firstScoreBelow = -1; secondScoreBelow = -2;
Scan the array elements.
if ( newScore > myScore ) {
if ( newScore < firstScoreAbove ) {
secondScoreAbove = firstScoreAbove;
firstScoreAbove = newScore;
} else if ( newScore < secondScoreAbove ) {
secondScoreAbove = newScore;
}
} else {
// similarly for below.
}
After scanning,
If firstScoreAbove has not changed, then myScore is top and output the two below scores.
If firstScoreBelow has not changed, then myScore is lowest and output the two above scores.
Else Output firstScoreAbove, myScore, firstScoreBelow.

Resources