objective-c Accessing array given as value of NSDictionary - objective-c

let's say i have a nsdictionary which contains an array as value.
NSMutableDictionary *test = [NSMutableDictionary dictionaryWithObjectsAndKeys:
[[NSMutableArray alloc]initWithObjects:"#Audi",#"Mercedes",#"Ferrari",nil], #"box 1",
[[NSMutableArray alloc]initWithObjects:"#Chervrolet",#"Mercedes",#"Bentley",nil], #"box 2",
[[NSMutableArray alloc]initWithObjects:"#Audi",#"Dodge",#"Ferrari",nil], #"box 2",
nil]
that's my simple dictionary with the arrays inside.
well now i need to check if theres a value in it.
here how i check if theres a certain key
if([test objectForKey#"box 2"]) { NSLog(#"item exists"); }
how can i access now the array inside one of the value? let's say to check if the array contains an item or to add one?
let's say i want to check if box 2 contains an Audi, and if not, i want to add it

Using containsObject you can check if object exist in array.
if([[test valueForKey:#"box 2"] containsObject:#"Audi"])
NSLog(#"Audi exists");
else
{
//[[test valueForKey:#"box 2"] addObject:#"Audi"];
//EDIT
NSMutableArray *data = [test valueForKey:#"box 2"];
[data addObject:#"Audi"];
[test setObject:data forKey:#"box 2"];
NSLog(#"Add Audi");
}

Related

Contacts Framework - fetching Email Field in Objective C

I am trying to fetch needed fields from the contacts, using the Contact Framework. All needed fields are properly fetched, EXCEPT the email. If there is one contact without an email recorded, then the entire app crashes. If all contacts have an email defined, all works well. I have a class called ContacList in which a method
fetchContactsFromContactsFrameWork is defined as follows:
-(void)fetchContactsFromContactsFrameWork{
contactStore = [[CNContactStore alloc] init];
NSArray *keyToFetch = #[CNContactEmailAddressesKey,CNContactFamilyNameKey,CNContactGivenNameKey,CNContactPhoneNumbersKey,CNContactPostalAddressesKey,CNContactThumbnailImageDataKey,CNContactOrganizationNameKey];
CNContactFetchRequest *fetchRequest = [[CNContactFetchRequest alloc] initWithKeysToFetch:keyToFetch];
[contactStore enumerateContactsWithFetchRequest:fetchRequest error:nil usingBlock:^(CNContact * _Nonnull contact, BOOL * _Nonnull stop) {
[groupsOfContact addObject:contact];
}];
phoneNumberArray = [#[] mutableCopy];
NSDictionary *peopleDic;
for (CNContact *contact in groupsOfContact) {
NSArray *thisOne = [[contact.phoneNumbers valueForKey:#"value"] valueForKey:#"digits"];
peopleDic = #{#"name":contact.givenName,
#"familyName":contact.familyName,
#"company":contact.organizationName,
#"image":contact.thumbnailImageData != nil ? contact.thumbnailImageData:#"",
#"email":contact.emailAddresses.firstObject != nil ? contact.emailAddresses.firstObject:#"",
#"phone":thisOne,
#"selected":#"NO"
};
[phoneNumberArray addObject:peopleDic];
}
totalPhoneNumberArray = [phoneNumberArray mutableCopy];
}
I am then using the array totalPhoneNumberArray in my PeopleTableViewController where I want to have access to the fetched information. In this I have created a method fetchedContacts, that loos like:
- (void)fetchContacts{
[[ContactList sharedContacts] fetchAllContacts]; //fetch all contacts by calling single method thanks to class 'ContactList"
NSArray *contactsArray = [[NSArray alloc]init];
_arrayOfContacts = [[NSMutableArray alloc]init]; //This will be the edited array to pass to the next ViewController
contactsArray = [[ContactList sharedContacts]totalPhoneNumberArray];//fetched original array now has local name 'contactsArray'
if (contactsArray.count !=0) {
for (int i=0; i<contactsArray.count; i++) {
NSMutableArray *person = [[NSMutableArray alloc]init];//person array will hold 6 properties...
UIImage *contactPic = [UIImage imageWithData:[[contactsArray objectAtIndex:i] valueForKey:#"image"]] ?: [UIImage imageNamed:#"noPerson.png"];
[person addObject:contactPic];
[person addObject:[[contactsArray objectAtIndex:i] valueForKey:#"name"]];
[person addObject:[[contactsArray objectAtIndex:i] valueForKey:#"familyName"]];
[person addObject:[[contactsArray objectAtIndex:i] valueForKey:#"company"]];
[person addObject:[[contactsArray objectAtIndex:i] valueForKey:#"phone"]];
CNLabeledValue *emailValue = [[contactsArray objectAtIndex:i]valueForKey:#"email"] ?:[[CNLabeledValue alloc]initWithLabel:#"email" value:#""];
//[person addObject:#"no email"];
[person addObject:emailValue.value];
//person array now has the form:{image,name,familyName,company,phone,email}
[_arrayOfContacts addObject:person];//arrayOfContacts holds all 'persons' fetched from main contactsArray...
}
}
}
As I explained already, this works perfectly, UNLESS one person has an empty email field, in which case it crashes...I have tried so many things: Turning the CNLabeledValue *emailValue to a NSString, testing for the length of that string, to no avail. Any help will be so much appreciated...
You have code that says:
CNLabeledValue *emailValue = [[contactsArray objectAtIndex:i]valueForKey:#"email"] ?: [[CNLabeledValue alloc]initWithLabel:#"email" value:#""];
[person addObject:emailValue.value];
But, when you populated that email value in the dictionary, you said that if there was no email address, use #"". So, the code above will then proceed to call value on #"", which will not work.
Rather than populating the dictionary with #"" when there is no email address, I'd suggest not setting that dictionary key at all. Or, if you're going to use a "special value" to indicate that there was no email address, you'd generally store [NSNull null]. Frankly, you should be doing the same with the image, too.
For example, I might do:
peopleDic = #{#"name" : contact.givenName ?: #"",
#"familyName" : contact.familyName ?: #"",
#"company" : contact.organizationName ?: #"",
#"image" : contact.thumbnailImageData ?: [NSNull null],
#"email" : contact.emailAddresses.firstObject ?: [NSNull null],
#"phone" : thisOne,
#"selected" : #"NO"
};
Of course, that means that when you retrieve the email value, you check to see if it is NSNull, and if so, set the label accordingly:
for (NSDictionary *contact in contactsArray) {
NSMutableArray *person = [[NSMutableArray alloc]init];//person array will hold 6 properties...
UIImage *contactPic = [contact[#"image"] isKindOfClass:[NSData class]] ? [UIImage imageWithData:contact[#"image"]] : [UIImage imageNamed:#"noPerson.png"];
[person addObject:contactPic];
[person addObject:contact[#"name"]];
[person addObject:contact[#"familyName"]];
[person addObject:contact[#"company"]];
[person addObject:contact[#"phone"]];
CNLabeledValue *email = contact[#"email"];
[person addObject:[email isKindOfClass:[CNLabeledValue class]] ? email.value : #""];
//person array now has the form:{image,name,familyName,company,phone,email}
[_arrayOfContacts addObject:person];//arrayOfContacts holds all 'persons' fetched from main contactsArray...
}
If you're interested in showing phone numbers as a string, there are a few options. Here are a few alternatives:
for (CNContact *contact in groupsOfContact) {
// if you want all phone numbers, you can get as an array, or build a joined string
NSArray *allPhoneNumberAsArray = [[contact.phoneNumbers valueForKey:#"value"] valueForKey:#"stringValue"];
NSString *allPhoneNumberAsSingleString = [allPhoneNumberAsArray count] > 0 ?[allPhoneNumberAsArray componentsJoinedByString:#"; "] : #"No phones";
// if you want only home phone numbers, filter those with `label` of `CNLabelHome`
NSArray *allHomePhoneNumberAsArray = [[[contact.phoneNumbers filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"label == %#", CNLabelHome]] valueForKey:#"value"] valueForKey:#"stringValue"];
NSString *allHomePhoneNumberAsSingleString = [allHomePhoneNumberAsArray count] > 0 ? [allHomePhoneNumberAsArray componentsJoinedByString:#"; "] : #"No home phones";
// if you only want the first home number, it's even easier
NSString *firstHomePhoneNumberAsSingleString = [allHomePhoneNumberAsArray firstObject] ?: #"No home phones";
...
}
NSMutableArray *emailArray;
NSString* email;
for (CNLabeledValue <NSString *>*label in contact.emailAddresses)
{
email = label.value;
NSLog(#"email : %#",email);
if ([email length] > 0) {
[emailArray addObject:email];
}
}

Adding multiple values to an NSString from an array

I have an array of items, each with their own unique descriptions. Basically, I want to create a method which takes each item from the array and returns a single descriptive string which shows the description of each item in said array.
- (NSString *) itemList
{
NSString *list = [[NSString alloc] init];
for (Item *i in _items)
{
/**
Unsure :S
*/
[NSString stringWithFormat:#"%#: %#.\n", [i firstId], [i name]];
}
return list;
}
Basically, this is the coded logic that I have so far.
Assume I have two items which are initialised as such:
Item *testItem1 = [[Item alloc] initWithIdentifiers:#[#"shovel", #"spade"] name:#"a shovel" andDesc:#"This is a mighty fine shovel"];
Item *testItem2 = [[Item alloc] initWithIdentifiers:#[#"gem", #"crystal"] name:#"a gem" andDesc:#"This is a shiny gem"];
I then add those items to my Inventory object:
[testInventory put:testItem1];
[testInventory put:testItem2];
By calling the Inventory method itemList
[testInventory itemList];
on my inventory (code listed above), I want the following result:
#"shovel: a shovel.\ngem a gem."
Does anyone have any suggestions or pointers. I'm sure it's simple; it's just that I've only recently picked up Obj - C :)
Thanks
You can just use:
list = [list stringByAppendingFormat:#"%#: %#\n", [i firstId], [i name]];
or try NSMutableString:
NSMutableString *list = [[NSMutableString alloc] init];
[list appendFormat:#"%#: %#\n", [i firstId], [i name]];
You can do it more elegantly by overriding the description method for your Item class like this:
- (NSString *) description {
return [NSString stringWithFormat:"%#: %#.", [self firstId], [self name]];
}
and then to generate the string for all the items in the array:
NSString* itemsString = [itemList componentsJoinedByString:#"\n"];
I like adding the collection of strings to a mutable array and then calling componentsJoinedByString. It works even more cleanly if it is the description method you want on each object because you don't have to do the collecting loop first.
Create nsmutablearray
For each item in list
Nsmutablearray add object item.property
Return nsmutablearray componentsJoinedByString #", "
If you want the item's description though, you can just do, assuming you have an array with the objects already
TheArray componentsJoinedByString #", "

searching in UITableView, but keep each section with a result

When I look at this table for a product, I force myself to search by product name search.
Within this list, you will find the name, image, product description and thumb.
See the code below:
-(void) lookinfor
{
NSString *searchText = search_bar.text;
NSMutableArray *searchArray = [[NSMutableArray alloc] init];
dict_produtos = [[NSMutableDictionary alloc] init];
for (NSDictionary *dictionary in array_sections)
{
NSArray *array = [dictionary valueForKey:#"products"];
[searchArray addObjectsFromArray:array];
}
for (NSDictionary *dicts in searchArray)
{
NSString *sTemp = [dicts objectForKey:#"name"];
NSRange titleResultsRange = [sTemp rangeOfString:searchText options:NSCaseInsensitiveSearch];
if (titleResultsRange.length != 0)
{
[dict_produtos setObject:sTemp forKey:#"name"];
[dict_produtos setObject:[dicts objectForKey:#"thumb"] forKey:#"thumb"];
[dict_produtos setObject:[dicts objectForKey:#"image"] forKey:#"image"];
[dict_produtos setObject:[dicts objectForKey:#"description"] forKey:#"description"];
}
}
searchArray = nil;
}
I get the whole list back perfectly, ie, looking for the name and get the thumb to enter the cell of the table, perfect, that's what I need..
So, when counting the lines of the section, only returns 1 line (name, image, thumb and description). So only returns 1 product.
That was the only solution I found to keep all the data together
For this reason I could not keep the sections while im searching and moreover, appears only 1 result (the others do not appear, even having found more than 1 record)
Does anyone have a better solution for this?
Thanks for all help!

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
"

Only last element of dictionary is adding into Core Data

I have a dictionary and I am trying to load all of its data into Core Data.
However, it is inserting only the last element into Core Data.
NSArray *NameArray = [resultsDictionary objectForKey:#"Sections"];
for (NSDictionary *Dictionary in NameArray) {
[section setValue:[Dictionary objectForKey:#"Name"] forKey:#"name"];
}
You override the value for "name" key in every iteration. Thats why only last one gets saved. You should insert a new object or update existing one for every dictionary item.
NSArray *NameArray = [resultsDictionary objectForKey:#"Sections"];
for (NSDictionary *Dictionary in NameArray) {
Section *newSection = <#create new object or fetch existing one#>
[newSection setValue:[Dictionary objectForKey:#"Name"] forKey:#"name"];
}