Adding NSDictionary keys with null values efficiently in ios5 - ios

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];
}
}

Related

Parsing Json Output correctly

I am trying to correctly target the elements within the Json Output and I am getting closer but I presume there is a easy and obvious way I am missing.
My Json looks like this with a upper level event.
JSON SNIPPET UPDATED
chat = (
(
{
Key = senderId;
Value = {
Type = 0;
Value = "eu-west-1:91afbc3f-890a-4160-8903-688bf0e9efe8";
};
},
{
Key = chatId;
Value = {
Type = 0;
Value = "eu-west-1:be6457ce-bac1-412d-9307-e375e52e22ff";
};
},
{
Key = timestamp;
Value = {
Type = 1;
Value = 1430431197;
};
},
//Continued
I am targeting this level using
NSArray *chat = array[#"chat"];
for ( NSDictionary *theCourse in chat )
{
NSLog(#"---- %#", theCourse);
// I tried the following to target the values
//NSLog(#"chatId: %#", [theCourse valueForKey:#"Key"]);
//NSLog(#"timestamp: %#", theCourse[#"senderId"] );
}
}
I need to parse the value data for each key which if I was using an array would do like [theCourse valueForKey:#"Key"] but I think I may not be going deep enough?
As you would expect, [theCourse valueForKey:#"Key"] gives me the Key values but I need the associate values of those keys.
You can create an easier dictionary:
NSArray *chat = array[#"chat"][0];
NSMutableDictionary* newDict = [NSMutableDictionary dictionary];
for (NSDictionary* d in chat)
[newDict setValue:d[#"Value"][#"Value"] forKey:d[#"Key"]];
Now you can use the newDict.
NSLog(#"chatId: %#", [newDict valueForKey:#"chatId"]);

Access email in EKParticipant/EKAttendee

I want to get the email address of the attendee of an event in the EKEventKit.
I have the following code:
if ( event.attendees.count > 0)
{
NSArray *people = event.attendees;
for(EKParticipant *person in people)
{
if ( person.participantType == EKParticipantTypePerson && person.URL.resourceSpecifier.length > 0)
{
NSString *dataString = [NSString stringWithFormat:#"event_id=%ld&name=%#&is_me=%d&email=%#&role=%#",event_id,person.name, person.isCurrentUser,person.URL.resourceSpecifier, #"attendee"];
//<DO SOMETHING USEFUL WITH dataString>;
}
}
}
When I run the code person populates with the following data:
EKAttendee <0x17809acc0> {UUID = 4F657EA4-452A-412B-A9AA-FEC5551DC096; name = A. Real Person; email = realperson#therightdomain.com; status = 0; role = 0; type = 1}
How to I access the email field?
I tried (as above) to use URL.resourceSpecifier, but that frequently is some strange string that is definitely NOT an email address.
The "Description" of the EKParticipant object is a property list of sorts. I tried several different methods of parsing that list into something containing key:value pairs unsuccessfully. So I wrote the following:
// This is re-useable code that converts any class description field into a dictionary that can be parsed for info
NSMutableDictionary *descriptionData = [NSMutableDictionary dictionary];
for (NSString *pairString in [person.description componentsSeparatedByString:#";"])
{
NSArray *pair = [pairString componentsSeparatedByString:#"="];
if ( [pair count] != 2)
continue;
[descriptionData setObject:[[pair objectAtIndex:1] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] forKey:[[pair objectAtIndex:0]stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]];
}
With this I simply get the email address with
[descriptionData valueForKey:#"email"]
I tried to answer this same question in "how to get ekevent EKparticipant email?" thread:
What you need to do is use EKPrincipal:ABRecordWithAddressBook and then extract email from there. Like this:
NSString *email = nil;
ABAddressBookRef book = ABAddressBookCreateWithOptions(nil, nil);
ABRecordRef record = [self.appleParticipant ABRecordWithAddressBook:book];
if (record) {
ABMultiValueRef value = ABRecordCopyValue(record, kABPersonEmailProperty);
if (value
&& ABMultiValueGetCount(value) > 0) {
email = (__bridge id)ABMultiValueCopyValueAtIndex(value, 0);
}
}
Note that calling ABAddressBookCreateWithOptions is expensive so you might want to do that only once per session.
If you can't access the record, then fall back on URL.resourceSpecifier.
In Swift 4:
private static func getParticipantDescriptionData(_ participant: EKParticipant) -> [String:String] {
var descriptionData = [String: String]()
for pairString in participant.description.components(separatedBy: ";") {
let pair = pairString.components(separatedBy: "=")
if pair.count != 2 {
continue
}
descriptionData[pair[0].trimmingCharacters(in: .whitespacesAndNewlines)] =
pair[1].trimmingCharacters(in: .whitespacesAndNewlines)
}
return descriptionData
}

How to see if NSArray, created with valueForKey is empty

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
}
}
}

iOS filter array of dictionary base on value and not the key

I have array with dictionaries like this:
Array: (
{
customerUS= {
DisplayName = "level";
InternalName = "Number 2";
NumberValue = 1;
},
customerCAN= {
DisplayName = "PurchaseAmount";
InternalName = "Number 1";
NumberValue = 3500;
};
}
)
I want to filter the dictionaries base on particular value and not the key. For example I want all the dictionaries with values on any key of 3500. Does any body knows how can I do this?
I'll really appreciate your help.
Try a predicate format like:
#"%# IN SELF", testValue
When you filter the array each will be run against the IN. When you pass IN a dictionary it uses the values of the dictionary.
you can also use
-keysOfEntriesPassingTest:
of NSDictionary. Just pass in a block like so:
for(NSDictionary *myDictionary in myArray){
NSSet *resultSet = [myDictionary keysOfEntriesPassingTest:^(id key, id object, BOOL *stop) {
//assuming that 3500 is an int, otherwise use appropriate condition.
if([[NSNumber numberWithInt:object] isEqual:[NSNumber numberWithInt:3500]]){
return YES;
}else{
return NO;
}
}];
if (resultSet.count>0){
//do whatever to myDictionary
}
}

What is the right way to check for a null string in Objective-C?

I was using this in my iPhone app
if (title == nil) {
// do something
}
but it throws some exception, and the console shows that the title is "(null)".
So I'm using this now:
if (title == nil || [title isKindOfClass:[NSNull class]]) {
//do something
}
What is the difference, and what is the best way to determine whether a string is null?
As others have pointed out, there are many kinds of "null" under Cocoa/Objective C. But one further thing to note is that [title isKindOfClass:[NSNull class]] is pointlessly complex since [NSNull null] is documented to be a singleton so you can just check for pointer equality. See Topics for Cocoa: Using Null.
So a good test might be:
if (title == (id)[NSNull null] || title.length == 0 ) title = #"Something";
Note how you can use the fact that even if title is nil, title.length will return 0/nil/false, ie 0 in this case, so you do not have to special case it. This is something that people who are new to Objective C have trouble getting used to, especially coming form other languages where messages/method calls to nil crash.
it is just as simple as
if([object length] >0)
{
// do something
}
remember that in objective C if object is null it returns 0 as the value.
This will get you both a null string and a 0 length string.
Refer to the following related articles on this site:
Is if (variable) the same as if (variable != nil) in Objective-C
h
I think your error is related to something else as you shouldn't need to do the extra checking.
Also see this related question: Proper checking of nil sqlite text column
I have found that in order to really do it right you end up having to do something similar to
if ( ( ![myString isEqual:[NSNull null]] ) && ( [myString length] != 0 ) ) {
}
Otherwise you get weird situations where control will still bypass your check. I haven't come across one that makes it past the isEqual and length checks.
Whats with all these "works for me answers" ? We're all coding in the same language and the rules are
Ensure the reference isn't nil
Check and make sure the length of the string isn't 0
That is what will work for all. If a given solution only "works for you", its only because your application flow won't allow for a scenario where the reference may be null or the string length to be 0. The proper way to do this is the method that will handle what you want in all cases.
If you want to test against all nil/empty objects (like empty strings or empty arrays/sets) you can use the following:
static inline BOOL IsEmpty(id object) {
return object == nil
|| ([object respondsToSelector:#selector(length)]
&& [(NSData *) object length] == 0)
|| ([object respondsToSelector:#selector(count)]
&& [(NSArray *) object count] == 0);
}
There are two situations:
It is possible that an object is [NSNull null], or it is impossible.
Your application usually shouldn't use [NSNull null]; you only use it if you want to put a "null" object into an array, or use it as a dictionary value. And then you should know which arrays or dictionaries might contain null values, and which might not.
If you think that an array never contains [NSNull null] values, then don't check for it. If there is an [NSNull null], you might get an exception but that is fine: Objective-C exceptions indicate programming errors. And you have a programming error that needs fixing by changing some code.
If an object could be [NSNull null], then you check for this quite simply by testing
(object == [NSNull null]). Calling isEqual or checking the class of the object is nonsense. There is only one [NSNull null] object, and the plain old C operator checks for it just fine in the most straightforward and most efficient way.
If you check an NSString object that cannot be [NSNull null] (because you know it cannot be [NSNull null] or because you just checked that it is different from [NSNull null], then you need to ask yourself how you want to treat an empty string, that is one with length 0. If you treat it is a null string like nil, then test (object.length == 0). object.length will return 0 if object == nil, so this test covers nil objects and strings with length 0. If you treat a string of length 0 different from a nil string, just check if object == nil.
Finally, if you want to add a string to an array or a dictionary, and the string could be nil, you have the choice of not adding it, replacing it with #"", or replacing it with [NSNull null]. Replacing it with #"" means you lose the ability to distinguish between "no string" and "string of length 0". Replacing it with [NSNull null] means you have to write code when you access the array or dictionary that checks for [NSNull null] objects.
You just check for nil
if(data[#"Bonds"]==nil){
NSLog(#"it is nil");
}
or
if ([data[#"Bonds"] isKindOfClass:[NSNull class]]) {
NSLog(#"it is null");
}
MACRO Solution (2020)
Here is the macro that I use for safe string instead of getting "(null)" string on a UILabel for example:
#define SafeString(STRING) ([STRING length] == 0 ? #"" : STRING)
let say you have an member class and name property, and name is nil:
NSLog(#"%#", member.name); // prints (null) on UILabel
with macro:
NSLog(#"%#", SafeString(member.name)); // prints empty string on UILabel
nice and clean 😊
Extension Solution (2020)
If you prefer checking nil Null and empty string in your project you can use my extension line below:
NSString+Extension.h
///
/// Checks if giving String is an empty string or a nil object or a Null.
/// #param string string value to check.
///
+ (BOOL)isNullOrEmpty:(NSString*)string;
NSString+Extension.m
+ (BOOL)isNullOrEmpty:(NSString*)string {
if (string) { // is not Nil
NSRange range = [string rangeOfString:string];
BOOL isEmpty = (range.length <= 0 || [string isEqualToString:#" "]);
BOOL isNull = string == (id)[NSNull null];
return (isNull || isEmpty);
}
return YES;
}
Example Usage
if (![NSString isNullOrEmpty:someTitle]) {
// You can safely use on a Label or even add in an Array for example. Remember: Arrays don't like the nil values!
}
if(textfield.text.length == 0){
//do your desired work
}
Try this for check null
if (text == nil)
#interface NSString (StringFunctions)
- (BOOL) hasCharacters;
#end
#implementation NSString (StringFunctions)
- (BOOL) hasCharacters {
if(self == (id)[NSNull null]) {
return NO;
}else {
if([self length] == 0) {
return NO;
}
}
return YES;
}
#end
NSString *strOne = nil;
if([strOne hasCharacters]) {
NSLog(#"%#",strOne);
}else {
NSLog(#"String is Empty");
}
This would work with the following cases, NSString *strOne = #"" OR NSString *strOne = #"StackOverflow" OR NSString *strOne = [NSNull null] OR NSString *strOne.
If that kind of thing does not already exist, you can make an NSString category:
#interface NSString (TrucBiduleChoseAdditions)
- (BOOL)isEmpty;
#end
#implementation NSString (TrucBiduleChoseAdditions)
- (BOOL)isEmpty {
return self == nil || [#"" isEqualToString:self];
}
#end
What works for me is if ( !myobject )
Complete checking of a string for null conditions can be a s follows :<\br>
if(mystring)
{
if([mystring isEqualToString:#""])
{
mystring=#"some string";
}
}
else
{
//statements
}
I only check null string with
if ([myString isEqual:[NSNull null]])
if ([linkedStr isEqual:(id)[NSNull null]])
{
_linkedinLbl.text=#"No";
}else{
_linkedinLbl.text=#"Yes";
}
if ([strpass isEqual:[NSNull null]] || strpass==nil || [strpass isEqualToString:#"<null>"] || [strpass isEqualToString:#"(null)"] || strpass.length==0 || [strpass isEqualToString:#""])
{
//string is blank
}
For string:
+ (BOOL) checkStringIsNotEmpty:(NSString*)string {
if (string == nil || string.length == 0) return NO;
return YES;
}
Refer the picture below:
For string:
+ (BOOL) checkStringIsNotEmpty:(NSString*)string {
if (string == nil || string.length == 0) return NO;
return YES;}

Resources