I'm using ABPeoplePicker to show a list of contacts.
I'd like to filter this list of contacts to only show the contacts that have email addresses. How would I do so?
I needed it, so I started working on something like that. Check out https://github.com/stuffmc/MCFilteredPeoplePickerNavigationController
here is the good blog tutorial for extracting address book values,
http://blog.slaunchaman.com/2009/01/21/cocoa-touch-tutorial-extract-address-book-address-values-on-iphone-os/
try with below:
ABPeoplePickerNavigationController *peoplePicker = [[ABPeoplePickerNavigationController alloc] init];
[peoplePicker setPeoplePickerDelegate:self];
[peoplePicker setDisplayedProperties:[NSArray arrayWithObject:[NSNumber numberWithInt:kABPersonEmailProperty]]];
ABContactHelper is a greater wrapper for the Addressbook and has some methods for filtering contacts based on various things.
https://github.com/erica/ABContactHelper
I'm trying to do a similar thing. I've gotten an instance of ABAddressBook, removed the entries I don't want, then set picker.addressBook = filteredBook. It...KINDA works. The list seems to be filtered, but entries are duplicated like it expects the full list to be there and it just copies existing entries until it has the expected count, or something.
Related
When I click a button, a UIAlertView prompts the user to type a name. This name is then created as a new 'Customer' object and inserted into a mutable array.
There is a separate mutable array called 'CustListByName', which stores a list of all names.
The problem im having is that when adding a second or third name, the app crashes. Sometimes it happens on the second try, other times on the third try. There is no information given in the debugger except for (lldb). The program reports EXC_BAD_ACCESS and then it dumps me to a screen with a bunch of assembly code.
The crash is happening in these lines of code:
Essentially, it clears the array of names and then repopulates it based upon the object array. I've studied in step by step with a breakpoint but everything seems correct up until the point of crash. It is also confusing why this happens on the second or third try, never the first.
[custListByName removeAllObjects];
for (Customer *object in custListByObject) {
[custListByName addObject:object->name];
}
Here is the code where a customer is created and inserted everytime the new customer button is clicked:
Customer *tempCust = [[Customer alloc] init];
tempCust->name =[[alertView textFieldAtIndex:0] text];
[custListByObject addObject:tempCust];
[tempCust release];
I would really appreciate help with this, thanks!
What I suspect is happening is that the UIPickerView is attempting to load a row using information from your customer array after you have already cleared it, and before you repopulate it. This would cause a bad access error.
What you may consider doing instead, is keeping two arrays, an NSMutableArray for loading the customers, and an NSArray as the actual data source for the UIPickerView. Then right before you reload the UIPickerView, you say:
dataSourceArray = [loadingArray copy];
[pickView reloadAllComponents];
Hopefully this helps.
Edit:
Here's what your updated code would look like if your loading array was called loadingCustListByName:
[loadingCustListByName removeAllObjects];
for (Customer *object in custListByObject) {
[loadingCustListByName addObject:object->name];
}
custListByName = [loadingCustListByName copy];
[pickView reloadAllComponents];
Doing this will ensure that the UIPickerView's datasource array always matches up with the number of rows it thinks it has.
Could you tell me please, how can I make something like this:
For example I have an app which contains info about your pets. But firstly, you should add a pet to a database. In a special view, you enter your pet's name, age, breed, color and etc (keys) and then you save it. Here we are, now you have your first pet in the app. But then you wanna add new pets...
How can I save all these dictionaries with same keys ? You don't know how may dictionaries to create because you don't know how many pets an user wanna add in the app. What is the easiest way?
What if user wants to add like thousands of pets in the app ? I am sure, I shouldn't create thousands of dictionaries in the code for every possible animal. But how do I do that ?
Like dictionary1 for Deisy, dictionary2 for Bruno, dictionary3 for Hamlet and etc.
Here is a rough description of how it could work:
Somewhere you need to define a collection to hold that pets.
NSMutableSet *myPets = [[NSMutableSet alloc] init];
When the user has entered the data and presses the save button, some method is called in your view controller. Within that method you collect the data, like this:
NSDictionary *pet = [NSDictionary dictionaryWithObjectsAndKeys:nameField.text, #"name", breedField.text,#"breed", nil];
[myPets addObject:pet];
At this point the pet has been put into the myPets NSMutableSet and the compiler will release it, so it doesn't exist anymore. The next time the user enters data and presses the button again, a new pet will be created and put into myPets. Don't worry about millions of instances being created, the compiler will take care of it.
If you want to retrieve individual pets afterwards, you can do something like this
for (NSDictionary *aPet in myPets) {
if ([[aPet objectForKey:#"name"] isEqualToString:#"Lassie"]) {
// do what you want to do with Lassie
}
}
You need an NSArray to hold the NSDictionaries.
I have looked at the sample code and still not able to figure out some key functionality of the framework without more in depth documentation. Normally there are books about frameworks but it seems like with this framework, you're on your own until it picks up more mainstream usage.
How do I get the roster list? I see that XMPPRosterCoreDataStorage has an NSMutableSet of rosterPopulationSet. Is this the set of XMPPUserCoreDataStorageObjects, i.e., users, that make up a roster?
My way I'm guessing is a hack--get the presence of every user as it's announced, and stash it in an array. Those are the online buddies. Somehow get the entire roster list, and everyone who is not online, is offline.
I figure that there should be an array of XMPPUserCoreDataStorageObjects, i.e., 30 contacts, 30 entries in the XMPPUserCoreDataStorageObjects table?
How would I access this array and how would I tell if they are online or not?
For online status, am I supposed to query something else, b/c it's not encapsulated in XMPPUserCoreDataStorageObjects is it?
I suppose I could use the didReceivePresence or similar methods, but all in all, I want to use the framework and not fight against it.
Appreciate it!
Thanks
Use XMPPRoster extension with either XMPPRosterCoreDataStorage or XMPPRosterMemoryStorage
Take a look at following code. Please note that this is not complete code but should give you an idea.
XMPPRosterMemoryStorage *rosterstorage = [[XMPPRosterMemoryStorage alloc] init];
xmppRoster = [[XMPPRoster alloc] initWithRosterStorage:rosterstorage];
[xmppRoster activate:xmppStream];
[xmppRoster fetchRoster];
Working on an app that makes heavy use of the Address Book framework. There are a number of View Controllers that interact with Address Book data, and they all work just fine. Except for one, and it's killing me.
I have a class that wraps address book access, in a method such as:
- (NSDictionary*)labelsToValues:(ABPropertyID)propertyID {
ABAddressBookRef addressBook = ABAddressBookCreate();
ABRecordRef aRecord = ABAddressBookGetPersonWithRecordID(addressBook, [self recordIdFromAddressBookId]);
NSMutableDictionary *entries = [NSMutableDictionary dictionary];
ABMultiValueRef multiValueProperty = ABRecordCopyValue(aRecord, propertyID);
// do some other stuff
And then I call it in places like this:
- (NSDictionary*)emailProperties {
return [self labelsToValues:kABPersonEmailProperty];
}
And it works! Of course it does, I'm sending the message with an argument that is a Constant from the Address Book framework. So it should always work!
But that's not the case. This particular emailProperties: message is one that I'm calling in several places... and sometimes it works, but sometimes it doesn't. When things go awry, I put it through the debugger and I get something like this:
How is that possible!? Even odder, if I sort of "prime" the problematic View Controller by viewing other View Controllers where everything behaves as expected, and then I return to the problematic View Controller, everything works fine. So, I'm guessing this is some sort of linking error, but I'm not sure how to even begin with troubleshooting that.
Turns out my question was a dupe of Address Book constants evaluating as zero, please vote to close.
I'm creating an iPhone app that will pull data down from a Web API, including email addresses. I'd like to display an image associated with each email address in table cells, so I'm searching the Address Book for images and falling back on a default if the email address isn't in the book. This works great, but I have a few concerns:
Performance: The recipes I've found for looking for an address book record by Email address (or phone number) are reportedly rather slow. The reason for this is that one must iterate over every address book record, and for each one that has an image, iterate over all email addresses to find a match. This can be time-consuming for a large address book, of course.
Table Cells: So I thought I'd gather up all the email addresses for which I need to find images and find them all at once. This way I iterate through the book only once for all addresses. But this doesn't work well for table cells, where each cell corresponds to a single email address. I'd either have to gather all the images before displaying any cells (potentially slow), or have each cell look up each image as it loads (even slower, as I'd need to iterate through the book to find a match for each email address).
Asynchronous Lookup: So then I thought I'd look them up in bulk, but asynchronously, using NSInvocationOperation. For each image found in AddressBook, I'd save a thumbnail in the app sandbox. Then each cell could just reference this file and show the default if it doesn't exist (because it's not in the book or hasn't yet been found). If the image is later found in the asynchronous lookup, the next time the image needs to be displayed it would suddenly appear. This might work well for periodic regeneration of images (for when images have been changed in the address book, for example). But then for any given instance of my app, an image may not actually show up for a while.
Asynchronous Table Cell Lookup: Ideally, I'd use something like markjnet's asynchronous table cell updating to update table cells with an image once it has been downloaded. But for this to work, I'd have to spin off an NSInvocationOperation job for each cell as it's displayed and if the cached icon is missing from the sandbox. But then we're back to inefficiently iterating through the entire address book for each oneāand that can be a lot of them if you've just downloaded a whole bunch of new email addresses.
So my question is: How do others do this? I was fiddling with Tweetie2, and it looks like it updates displayed table cells asynchronously. I assume it's sending a separate HTTP request for every image it needs. If so, I imagine that searching the local address book by email address isn't any less efficient, so maybe that's the best approach? Just not worry about the performance issues associated with searching the address book?
If so, is saving a thumbnail image in the sandbox the best approach to caching? And if I wanted to create a new job to update all the thumbnails with any changes in the address book say once a day, what's the best approach to doing so?
How do the rest of you solve this sort of problem? Suggestions would be much appreciated!
Regardless of what strategy you use for the actual caching of images, I would only make one pass through the Address Book data each time you get a batch of email addresses, if possible. (And yes, I would do this asynchronously.)
Create an NSMutableDictionary which will serve as your in-memory cache for search results. Initialize this dictionary with each email address from the download as a key, with a sentinel as that key's value (such as [NSNull null]).
Next, iterate through each ABRecordRef in the Address Book, calling ABRecordCopyValue(record, kABPersonEmailProperty) and looping through the results in each ABMultiValue that is returned. If any of the email addresses are keys in your cache, set [NSNumber numberWithInt:ABRecordGetRecordId(record)] as the value of that key in your dictionary.
Using this dictionary as a lookup index, you can quickly obtain the images of ABRecordRefs for only the email addresses that you are currently displaying in your table view given the user's current scroll position, as suggested in hoopjones's answer. You can add an address book change listener to invalidate your cache, trigger another indexing operation, and then update the view, if your application needs that level of "up-to-date-ness".
I'd use the last method you listed (Asynchronous Table Cell Lookup) but only look images for the current records being displayed. I overload the UIScrollViewDelegate methods to find out when a user has stopped scrolling, and then only start making requests for the current visible cells.
Something like this (this is slightly modified from a tutorial I found on the web which I can't find now, apologies for not citing the author) :
- (void)loadContentForVisibleCells
{
NSArray *cells = [self.table visibleCells];
[cells retain];
for (int i = 0; i < [cells count]; i++)
{
// Go through each cell in the array and call its loadContent method if it responds to it.
AddressRecordTableCell *addressTableCell = (AddressRecordTableCell *)[[cells objectAtIndex: i] retain];
[addressTableCell loadImage];
[addressTableCell release];
addressTableCell = nil;
}
[cells release];
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView;
{
// Method is called when the decelerating comes to a stop.
// Pass visible cells to the cell loading function. If possible change
// scrollView to a pointer to your table cell to avoid compiler warnings
[self loadContentForVisibleCells];
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate;
{
if (!decelerate)
{
[self loadContentForVisibleCells];
}
}
Once you know what address records are currently visible, just doing a search for those (5 -7 records probably) will be lightning fast. Once you grab the image, just cache it in a dictionary so that you don't have to redo the request for the image later.
You seem to try to implement lazy images loading in UITableView.
there's a good example from Apple, I'm referencing it here :
Lazy load images in UITableView
FYI, I've released a free, powerful, and easy library for doing asynchronous image loading and fast file caching: HJ Managed Objects
http://www.markj.net/asynchronous-loading-caching-images-iphone-hjobjman/