FBFriendPickerViewController select friends programmatically - ios

I want to implement "Select All" feature on FBFriendPickerViewController, but I don't really see any ability to select friends from code. Maybe I'm missing something?

I don't know how exactly is the procedure in StackOverflow for similar questions, anyway if it can still be of any help, the solution is posted here.
Quoting:
I have an NSDictionary dict whose key is the facebook user id and the value is the name. Roughly, this is the code:
NSMutableArray *results = [[NSMutableArray alloc] init];
for (id key in dict) {
NSString *name = [dict valueForKey:key];
id<FBGraphUser> user = (id<FBGraphUser>)[FBGraphObject graphObject];
user.id = key;
[user setName:name]; // This is not mandatory
if (user) {
NSLog(#"adding user: %#", user.name);
[results addObject:user];
}
}
// And finally set the selection property
friendPickerController.selection = results;

Related

Can't add unified CNContact to CNGroup in iOS

Here's what I'm doing:
- (void)doCreateGroup {
[[self contentView] endEditing:true];
NSString * newString = [[[[self contentView] groupNameField] text] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSString * firstError = nil;
if ([newString length] == 0) {
firstError = #"Missing group name";
}
NSError * groupsError = nil;
NSArray * groups = [self.contactStore groupsMatchingPredicate:nil error:&groupsError];
for (CNGroup * group in groups) {
if ([group.name isEqualToString:newString]) {
firstError = #"Group already exists";
}
}
if (firstError) {
[self presentViewController:[WLGCommonUtilities doProcessErrorWithOkay:#"Error" errorMessage:firstError] animated:YES completion:nil];
return;
}
CNMutableGroup * newGroup = [CNMutableGroup new];
[newGroup setName:newString];
CNSaveRequest *saveRequest = [CNSaveRequest new];
[saveRequest addGroup:newGroup toContainerWithIdentifier:nil];
NSError * error = nil;
[self.contactStore executeSaveRequest:saveRequest error:&error];
if (error) {
[self presentViewController:[WLGCommonUtilities doProcessErrorWithOkay:#"Error" errorMessage:[error localizedDescription]] animated:YES completion:nil];
} else {
CNSaveRequest *saveRequest2 = [CNSaveRequest new];
NSArray * groupsAgain = [self.contactStore groupsMatchingPredicate:nil error:&groupsError];
CNGroup * gotGroup;
for (CNGroup * group in groupsAgain) {
if ([group.name isEqualToString:newString]) {
gotGroup = group;
}
}
for (CNContact * contact in self.selectedContactsArray) {
[saveRequest2 addMember:contact toGroup:gotGroup];
}
NSError * error1 = nil;
[self.contactStore executeSaveRequest:saveRequest2 error:&error1];
if (error) {
[self presentViewController:[WLGCommonUtilities doProcessErrorWithOkay:#"Error" errorMessage:[error1 localizedDescription]] animated:YES completion:nil];
} else {
[[self navigationController] dismissViewControllerAnimated:true completion:nil];
}
}
}
this works to create a CNGroup and then add contacts to said CNGroup. Works for all contacts EXCEPT for unified contacts. I've tried everything possible to make this work and it just doesn't. It likely has something to do with the unified CNContact's identifier since that identifier is only stored in temp memory so it can't be added to a CNGroup since it doesn't really haver a REAL CNContact identifier. Contacts framework is a mess! Any help would be appreciated. I've also filed a tech support request with Apple.
EDIT:
One way to get around this is to use Address Framework that is now deprecated. I can add as many unified contacts to Address groups by doing this.
ABRecordRef group = ABGroupCreate();
ABAddressBookAddRecord(addressBook, group, nil);
ABRecordSetValue(group, kABGroupNameProperty,#"My Groups", nil);
for (int i=0;i < nPeople;i++) {
ABRecordRef ref = CFArrayGetValueAtIndex(allPeople,i);
ABGroupAddMember(group, ref, nil);
ABAddressBookSave(addressBook, nil);
}
this does save everything in the contact book to a group, all visible contacts that is. so it does store the Unified contact into the group. if you unlink the contacts while they are in a group, both contacts stay within the group. so the old framework works to solve this. just seems ridiculous that it can't be solved with new Contacts framework. Again, I may be missing something with the new Contacts framework, so if this is possible with the current Contacts framework in iOS please let me know.
i figured it out. this is a mess
step one:
NSMutableArray * finalArray = [NSMutableArray array];
NSMutableArray * unifiedContacts = [NSMutableArray array];
NSMutableArray * fullContacts = [NSMutableArray array];
CNContactFetchRequest * request = [[CNContactFetchRequest alloc] initWithKeysToFetch:keys];
[request setSortOrder:CNContactSortOrderGivenName];
[self.contactStore enumerateContactsWithFetchRequest:request error:&error usingBlock:^(CNContact * _Nonnull contact, BOOL * _Nonnull stop) {
[unifiedContacts addObject:contact];
}];
CNContactFetchRequest * request2 = [[CNContactFetchRequest alloc] initWithKeysToFetch:keys];
[request2 setUnifyResults:false];
[request2 setSortOrder:CNContactSortOrderGivenName];
[self.contactStore enumerateContactsWithFetchRequest:request2 error:nil usingBlock:^(CNContact * _Nonnull contact, BOOL * _Nonnull stop) {
[fullContacts addObject:contact];
}];
for (CNContact * contctUn in unifiedContacts) {
NSMutableArray * nestedContacts = [NSMutableArray array];
for (CNContact * contct in fullContacts) {
if ([contctUn isUnifiedWithContactWithIdentifier:contct.identifier]) {
[nestedContacts addObject:contct];
}
}
if (nestedContacts.count) {
[finalArray addObject:#{#"contact" : contctUn, #"linked" : nestedContacts}];
} else {
[finalArray addObject:#{#"contact" : contctUn}];
}
}
self.mainArray = [finalArray mutableCopy];
this pulls in all contacts from unified contacts and then pulls in all un-unified contacts, splices the groups together and saves them as dictionaries with "linked" being an array of linked contacts if the contact is indeed linked to the contact in question.
step 2: create a group ... this is pretty simple, no need to show the code since this is pretty easy
step 3:
for (id obj in self.filteredSearchArray) {
if ([obj valueForKey:#"linked"]) {
for (id obj2 in [obj valueForKey:#"linked"]) {
[self.selectedContactsArray addObject:obj2];
}
}
}
CNSaveRequest *saveRequest2 = [CNSaveRequest new];
for (CNContact * contact in self.selectedContactsArray) {
[saveRequest2 addMember:contact toGroup:[newGroup copy]];
}
NSError * error1 = nil;
[self.contactStore executeSaveRequest:saveRequest2 error:&error1];
self.selectedContactsArray is the array that contains the contacts you want in the group. it contains all contacts you want in the group in addition it contains the sublinked contacts if a contact you want in the group is linked to a user.
when this save request executes the group now contains the unified contact.
this is a mess. Contacts Framework in iOS is a mess, but this works. No app that creates groups for contacts has solve this, so here's the million dollar solution.
That seems odd indeed. As at least a workaround, have you tried to fetch the selected contacts with a CNContactFetchRequest that has its unifyResults set to false?
I mean, I don't know where you get the selectedContactsArray from, I assume either you can modify an existing request that gave you that data accordingly or you have to somehow refetch the contacts again. That's probably really, really ugly, as you would have to construct a fetch request with a predicate or key set that is guaranteed to match the same contacts (and only those contacts) plus said unifyResults member set to false.
I'd imagine something like this (sorry for using swift, it's a little compacter for me right now, I hope that's okay):
let allMyIds: [String] = self.selectedContactsArray.map { $0.identifier }
let predicate: NSPredicate = CNContact.predicateForContacts(withIdentifiers: allMyIds)
let fetchRequest = CNContactFetchRequest(keysToFetch: someKeys)
// not sure what you'd need here for someKeys...
// I assume it would have to be a key definitely present in all contacts you
// are interested in, e.g. name? I might be wrong though...
fetchRequest.unifyResults = false
_ = self.contactStore.enumerateContacts(with: fetchRequest, usingBlock: { contact, errorPointer in
// your group adding/save preparation code here
})
I admit I am not that familiar with the Contacts framework, so I can't say whether that is really feasible. Especially the set of keys you'd have to provide to the enumerate... method might be tricky if you don't have a key that's guaranteed to be part of all contacts you want.
I apologize for such a half-baked answer, but maybe it can at least give you a new impulse.

Obj-C: Check if object exists in NSMutableArray?

I'm trying to check if NSString 'testing' (47) exists inside of my NSMutableArray 'self.checkfriendData'. I'm using the code below, though after logging my if statement it appears as though it's never executed (even though the statement is true - see console data below, uid = 47, and thus hiding my object should fire?) Any idea as to why this isn't working? Help is much appreciated!
ViewController.m
NSMutableDictionary *viewParams3 = [NSMutableDictionary new];
[viewParams3 setValue:#"accepted_friends" forKey:#"view_name"];
[DIOSView viewGet:viewParams3 success:^(AFHTTPRequestOperation *operation, id responseObject) {
self.checkfriendData = (NSMutableArray *)responseObject;
NSString *testing = #"47";
NSArray *friendorNo = self.checkfriendData;
if ([friendorNo containsObject:testing]) // YES
{
self.addFriend.hidden = YES;
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
}];
Here's what's inside self.checkfriendData:
2017-05-18 19:36:07.266529-0700 This is the friend data check (
{
body = "My name is Britt";
friendphoto = "/sites/default/files/stored/x.jpg";
"node_title" = "Britt";
uid = 47;
}
)
It appears that your NSArray contains NSDictionarys and you are asking if the array contains an NSString. The answer will always be no as the array doesn't directly contain any NSStrings.
If you want to search for the uid of 47 you will have to iterate over the array and check the uid key of each NSDictionary for the value 47.
The code for this would look something like:
for (NSDictionary *dict in friendorNo) {
if ([dict[#"uid"] isEqualToString:testing]) {
self.addFriend.hidden = YES;
}
}

PFQuery to find PFUser whose key matches NSString

I first of all apologize for the most random rambling title ever. Here is my situation. I populate a UITableView by getting a list of all the Facebook friends a user has that also use the app. I get this by:
[FBRequestConnection startForMyFriendsWithCompletionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
if (!error) {
// result will contain an array with your user's friends in the "data" key
self.friendObjects = [result objectForKey:#"data"];
self.jobsTemp = [[NSMutableArray alloc] initWithCapacity:self.friendObjects.count];
NSLog(#"%#", self.friendObjects);
for(NSDictionary *jobsInfo in self.friendObjects) {
FriendArray *jobby = [[FriendArray alloc] init];
jobby.name = [jobsInfo valueForKey:#"name"];
NSLog(#"Name%#", jobby.name);
// jobby.name = jobsInfo[#"additional"];
jobby.facebookid = jobsInfo[#"id"];
[self.jobsTemp addObject:jobby];
}
self.jobsArray = self.jobsTemp;
NSLog(#"ARRAY%#", self.jobsArray);//set #property (nonatomic, copy) NSArray *jobsArray; in the .h
[self.tableView reloadData];
}
}];
Each entry in _User has a column called fbId. What I would like to do is search all PFUsers when a row is clicked and find the PFUser that has a fbId entry that matches the id for that particular row. What I have tried so far is:
FriendArray *job = self.jobsArray[indexPath.row];
PFObject *object = [PFObject objectWithClassName:#"_User"];
PFQuery *query = [PFUser query];
[query whereKey:job.facebookid equalTo:object[#"fbId"]];
NSLog(#"Query%#", [query findObjects]);
However, I cannot figure out what I am doing wrong. Any suggestions?
You will need to create two PFQuery objects. One to represent the first user, the second to find the friend.
The Parse API query method you are looking for is:
- (instancetype)whereKey:(NSString *)key matchesKey:(NSString *)otherKey inQuery:(PFQuery *)query
You will do something like:
[friendQuery whereKey:#"id" matchesKey:#"fbId" inQuery:userQuery]

Tricky Object Sorting and Removing from NSMutableArray

I have an array of objects (that contain a message), every object has the same structure. It has a message property which is an NSDictionary. One dictionary looks like this:
<message: {
keyCreateDate = "06/08/14 21:23";
keyMessage = Lorem ipsum;
keyReceiverChannel = sampleString;
keySenderUser = SampleName;
},...
My goal is to make an "inbox" where i would like to display the newest messages from every user in each cell. I want the show only the newest messages from each user, like the Fb messages, What'sApp or iMessage inbox, every cell in the table view represents the recent message from a friend. It looks very easy, but it's much harder than i imaged. So i need to remove every message from every friend, but always keep newest one. Actually i can remove all message from one user, but can't keep the newest while removing the others. Is it possible to do this?
I can remove all message for one specified user with this code:
NSMutableArray *originalArray = [[NSMutableArray alloc]initWithArray:message];
NSMutableArray *objectsToRemove = [[NSMutableArray alloc]init];
NSMutableArray *cloneArray = [NSMutableArray arrayWithArray:originalArray];
for (NMessage *messageObject in originalArray) {
if ([messageObject.message[#"keySenderUser"] isEqual:usernameString]) {
[objectsToRemove addObject:messageObject];
}
}
if ([objectsToRemove count]>0) {
[cloneArray removeObjectsInArray:objectsToRemove];
NSLog(#"deleted: %#", objectsToRemove);
self.messagesArray = [[NSMutableArray alloc]initWithArray:cloneArray];
I think it would be the easier, if i could somehow add an exception to the [cloneArray removeObjectsInArray:objectsToRemove]; line, that doesn't let to remove the newest ones. But it's also a problem that i need to sort the messages based on the keySenderUser before i delete them. My actual code can't do that, it can find only one pre-defined user's message and remove all of them. Please share with me if you have any idea. Thanks in advance.
I feel bottom up is better in your case where you build a new array which contains latest message dictionary.
The solution is as below.
1. sort the array using date.
2. Create a new list for holding user messages.
2. Loop through each object check whether the user is already present, If not add it to the created list.
The code solution is below, pass in your array of messaged, which would give a list of messages which are latest for an user.
-(NSArray *) GetLatestMessageListForEveryUser:(NSArray *) array
{
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
NSArray *sortedArray = [array sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
NSDate *obj1Date = [formatter dateFromString: [(NSDictionary *)obj1 objectForKey:#"keyCreateDate" ] ];
NSDate *obj2Date = [formatter dateFromString:[(NSDictionary *)obj2 objectForKey:#"keyCreateDate" ] ];
return ([obj1Date earlierDate:obj2Date] == obj1Date);
}];
NSMutableArray *messageArray = [NSMutableArray array];
NSMutableArray *usersArray = [NSMutableArray array];
for (NSDictionary *messageDictionary in sortedArray)
{
NSString *userName = [messageDictionary objectForKey:#"keySenderUser"];
if (![usersArray containsObject:userName])
{
[usersArray addObject:userName];
[messageArray addObject:messageDictionary];
}
}
return messageArray;
}

Multiple dictionaries within an array and Checking for duplicate keys - Objective C

I have an array which contains multiple Dictionaries each one with 3 keys (#"date", #"username", #"text").
What I want to check for, is whether the same user (#"username") exists in more than one dictionary in that Array. And, if she does, combine the text for those "duplicates" into one dictionary.
I have considered this answer to check for duplicates and this one
but I cannot figure out how to combine these two.
Jumping in here because although I think you should work on the code yourself first, I think Miro's answer is more complicated than the issue requires and though I like the idea of using predicates in Greg's answer, here's a 3rd solution that (1) wouldn't require you to change your data structure and (2) references the necessary loops...
The way I'd do it: Create an NSMutableArray then start adding the usernames in order. If the NSMutableArray already contains the username though, don't add another instance of the username, but instead merge the dictionary info.
ex.
// Note: I'm calling your array of user dictionaries userArray.
// Create a username array to store the usernames and check for duplicates
NSMutableArray *usernames = [[NSMutableArray alloc] init];
// Create a new userArray to store the updated dictionary info, merged
// entries et. al.
NSMutableArray *newUserArray = [[NSMutableArray alloc] init];
// Go through the array of user dictionaries
for (NSDictionary *userDict in userArray) {
// If the usernames array doesn't already contain the username,
// add it to both the usernames array and the newUserArray as is
if (![usernames containsObject:[userDict objectForKey:#"username"]]) {
[usernames addObject:[userDict objectForKey:#"username"]];
[newUserArray addObject:userDict];
}
// Otherwise, merge the userArray entries
else {
// Get a mutable copy of the dictionary entry at the first instance
// with this username
int indexOfFirstInstance = [usernames indexOfObject:[userDict objectForKey:#"username"]];
NSMutableDictionary *entry = [[newUserArray objectAtIndex:indexOfFirstInstance] mutableCopy];
// Then combine the "text" or whatever other values you wanted to combine
// by replacing the "text" value with the combined text.
// (I've done so with a comma, but you could also store the value in an array)
[entry setValue:[[entry objectForKey:#"text"] stringByAppendingString:[NSString stringWithFormat:#", %#", [userDict objectForKey:#"text"]]] forKey:#"text"];
// Then replace this newly merged dictionary with the one at the
// first instance
[newUserArray replaceObjectAtIndex:indexOfFirstInstance withObject:entry];
}
}
Maybe something like this [untested] example? Loop through, maintain a hash of existing items, and if a duplicate is found then combine with existing and remove.
NSMutableArray main; // this should exist, with content
NSMutableDictionary *hash = [[NSMutableDictionary alloc] init];
// loop through, backwards, as we're attempting to modify array in place (risky)
for(int i = [main count] - 1; i >= 0; i--){
// check for existing
if(hash[main[i][#"username"]] != nil){
int existingIdx = [hash[main[i][#"username"]] integerValue]; // get existing location
main[existingIdx][#"text"] = [main[existingIdx][#"text"] stringByAppendingString:main[i][#"text"]]; // "combine text" .. or however you'd like to
[main removeObjectAtIndex:i]; // remove duplicate
} else {
[hash setValue:[[NSNumber alloc] initWithInt:i] forKey:main[i][#"username"]]; // mark existance, with location
}
}
If you use NSMutableDictionary, NSMutableArray and NSMutableString you can do it with predicate like that:
NSMutableDictionary *d1 = [#{#"username": #"Greg", #"text" : [#"text 1" mutableCopy]} mutableCopy];
NSMutableDictionary *d2 = [#{#"username": #"Greg", #"text" : [#"text 2" mutableCopy]} mutableCopy];
NSMutableDictionary *d3 = [#{#"username": #"John", #"text" : [#"text 3" mutableCopy]} mutableCopy];
NSMutableArray *array = [#[d1, d2, d3] mutableCopy];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"username = %#", #"Greg"];
NSArray *filterArray = [array filteredArrayUsingPredicate:predicate];
NSMutableDictionary * firstDict = filterArray[0];
for (NSDictionary *d in filterArray)
{
if (firstDict != d)
{
[firstDict[#"text"] appendString:d[#"text"]];
[array removeObject:d];
}
}

Resources