CKDiscoverAllContactsOperation not fetching contacts - objective-c

I am using CKDiscoverAllContactsOperation but its not working fine for me.
-(void)queryForAllUsers: (void (^)(NSArray *records))completionHandler {
CKDiscoverAllContactsOperation *op = [[CKDiscoverAllContactsOperation alloc] init];
[op setUsesBackgroundSession:YES];
op.queuePriority = NSOperationQueuePriorityNormal;
[op setDiscoverAllContactsCompletionBlock:^(NSArray *userInfos, NSError *error) {
if (error) {
NSLog(#"An error occured in %#: %#", NSStringFromSelector(_cmd), error);
//abort();
} else {
NSLog(#"Number of records in userInfos is: %ld", (unsigned long)[userInfos count]);
dispatch_async(dispatch_get_main_queue(), ^(void){
completionHandler(userInfos);
});
}
}];
[self.container addOperation:op];
}
The container which I'm using is publicCloudDatabase.

The search only works if different users activate the app, approved to be Discoverable and have the other person's iCloud email address in their Contacts.

You should use the discoverAllContactUserInfosWithCompletionHandler on the container like this:
[self.container discoverAllContactUserInfosWithCompletionHandler:^(NSArray *userInfos, NSError *error) {
..
}
this function will only return the contacts that can be linked to an iCloud account and the person has also started up your app.

Related

Objective-C AFnetworking: stopping a request

Evening, I'm working with the Marvel-API, trying to download all the characters.
To download all the characters you have to do multiple requests, in each request you can specified the limit and the offset.
So I've set the limit at the max of 100 and for every request I increase the offset by 100.
Doing that, I do infinite request. Of course.
So I thought that I should stop when the "results" array retrieved from the JSON object is empty.
So the logic should be good, I keep requesting characters 100 by 100 until there are no more to retrieve.
But of course working with networking and async code isn't always so easy. And obviously I got stocked.
I'm sure that the problems is in these lines of code:
#pragma mark - Requesting data
-(void)getData {
NetworkManager *networkManager = [NetworkManager alloc];
while(self.requestMustEnd == false) {
NSLog(#"offset: %d", networkManager.offset);
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
[manager GET:networkManager.getUrlPath parameters:nil progress:nil success:^(NSURLSessionTask *task, id responseObject) {
NSLog(#"JSON: %#", responseObject);
[self parseResponseData:responseObject];
} failure:^(NSURLSessionTask *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
[networkManager increaseOffset];
}
}
#pragma mark - Parsing Method
-(void)parseResponseData:(NSDictionary *)responseDictionary {
NSArray *marvelArray = [[responseDictionary objectForKey:#"data"] objectForKey:#"results"];
if (marvelArray.count == 0) {
self.requestMustEnd = true;
}
for(NSDictionary* marvel in marvelArray)
{
Character *currentMarvelEntity = [[Character alloc] initWithMarvel:marvel];
//NSLog(#"currentMarvelEntity %#", currentMarvelEntity.name);
[self.marvelCharacters addObject:currentMarvelEntity];
}
[self.tableView reloadData];
}
The key part to stop the request is:
if (marvelArray.count == 0) {
self.requestMustEnd = true;
}
But, still, it never end to request. it is not for the if condition, I'm sure. But probably because, having an async code, the getData func no matter what keep requesting data.
Any tips?
This post may help. Try:
[manager.operationQueue cancelAllOperations];

OAuthTokenRequest using STTwitterAPI fails

Using following code to get OAuth token but it always fails with error
Your credentials do not allow access to this resource
I have taken following code sample from
https://github.com/nst/STTwitter/blob/master/demo_cli/reverse_auth/main.m
Even I have allowed Read and Write access in application settings at
https://apps.twitter.com/app/XXXX/permissions
STTwitterAPI *twitter = [STTwitterAPI twitterAPIWithOAuthConsumerName:nil consumerKey:#"MY CONSUMER KEY" consumerSecret:#"MY CONSUMER SECRET"];
[twitter postReverseOAuthTokenRequest:^(NSString *authenticationHeader) {
STTwitterAPI *twitterAPIOS = [STTwitterAPI twitterAPIOSWithFirstAccount];
[twitterAPIOS verifyCredentialsWithSuccessBlock:^(NSString *username) {
[twitterAPIOS postReverseAuthAccessTokenWithAuthenticationHeader:authenticationHeader successBlock:^(NSString *oAuthToken, NSString *oAuthTokenSecret, NSString *userID, NSString *screenName) {
NSLog(#"REVERSE AUTH OK");
} errorBlock:^(NSError *error) {
NSLog(#"ERROR, %#", [error localizedDescription]);
}];
} errorBlock:^(NSError *error) {
NSLog(#"ERROR");
}];
} errorBlock:^(NSError *error) {
NSLog(#"ERROR");
}];
Any help, where I am going wrong.

ios fetch defer deeplink always null objective c by using facebook sdk

I am using facebook SDK , and when I am trying to invite friend via facbook by using fb invite deep linking.
NSDictionary * getParam = #{
#"access_token":accessToken,
#"fields":#"canonical_url",
#"pretty":#(YES),
};
NSString * getCanoicalURL = [NSString stringWithFormat:#"%#/%#",FB_CANONICAL_API, fbAPILinkID];
[self GET:getCanoicalURL parameters:getParam success:^(NSURLSessionDataTask * _Nonnull task, id _Nonnull responseObject)
{
NSError *error;
FacebookLink * getResult = [MTLJSONAdapter modelOfClass:[FacebookLink class] fromJSONDictionary:responseObject error:&error];
if (error)
{
handler(nil,error);
}
else
{
handler(getResult.canonicalUrl,nil);
}
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error)
{
handler(nil,error);
}];
The below is my invite friend method it show successfully :
-(void)inviteFriend:(NSString*)canonicalUrl
{
FBSDKAppInviteContent *content =[[FBSDKAppInviteContent alloc] init];
content.appLinkURL =[NSURL URLWithString:canonicalUrl];
[FBSDKAppInviteDialog showFromViewController:self withContent:content delegate:self];
}
But when I try to fetch for defer deep link it always null:
FBSDKAppLinkUtility fetchDeferredAppLink:^(NSURL *url, NSError *error)
{
NSLog(#"fetch defer app link :%#",url);
if (error) {
NSLog(#"Received error while fetching deferred app link %#", error);
}
if (url) {
[[UIApplication sharedApplication] openURL:url];
}
}];
Be sure that your iPhone's Limit Ad Tracking setting is off, at Settings -> Privacy -> Advertising
Get parts of a NSURL in objective-c
This will be ur exact reference and answer not so manual coding as above.

How can I refactor duplicated codes for error?

I'm using block for my APIs and the API class throws error via block like below code.
[HJHLifeAPI deletePlantWithIdentifier:identifier completionHandler:^(NSError *error) {
if (error) {
[[error alertView] show];
return ;
}
[self refresh:self.refreshControl];
}];
But the problem is that I use this pattern of codes in several places. As a result, I should write several duplicated codes for error handling. Is there any way to refactor this code? I think exception can be one solution, but I think Apple don't encourage developers to use it.
It's up to How your HJHLifeAPI is designed.
I usually use AFNetworking for API things and here's an example.
// This is the method like deletePlantWithIdentifier:
// It actually invoke __requestWitPath:
- (void)requestSomethingWithId:(NSString *)memId done:(NetDoneBlock)done
{
NSMutableDictionary *param_ = #{#"key":#"id"};
[self __requestWithPath:#"/apiPath.jsp" parameter:param_ done:done];
}
#pragma PRIVATE
- (void)__requestWithPath:(NSString *)apiPath parameter:(NSDictionary *)parameter done:(NetDoneBlock)done
{
AFHTTPRequestOperationManager *manager = [[AFHTTPRequestOperationManager alloc] initWithBaseURL:[NSURL URLWithString:SERVER_URL]];
AFHTTPRequestOperation *operation = [manager POST:apiPath parameters:parameter constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
} success:^(AFHTTPRequestOperation *operation, id responseObject) {
done();
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
// Error Handle Here
}];
[operation start];
}
You can handle all errors in one __request....
Create the block
void(^errorHandler)(NSError *error) = ^(NSError *error) {
if (error) {
[[error alertView] show];
return ;
}
[self refresh:self.refreshControl];
}
Save it somewhere (don't forget to copy it)
self.errorHandler = errorHandler;
Reuse it everywhere:
[HJHLifeAPI deletePlantWithIdentifier:identifier completionHandler:self.errorHandler];

dispatch_group_t issue, dispatch_group_notify is calling back before leaving the group

I have the following snippet of code below that fetches data from Parse using PFQueues in the background and returns data and a status. This structure is based off of waiting for the dispatch_group_t to notify that's it's completed all entered groups. Unfortunately dispatch_group_notify(downloadGroup, dispatch_get_main_queue(), ^{
is called before the completion blocks call dispatch_group_leave. By the time the dispatch_group_leave() is called on any of the completion blocks, an EXC_BAD_INSTRUCTION is thrown. I've attached an image below for the instruction error. Does anyone know if I'm doing something wrong or if Parse has some annoyances that prevent me from using this method?
- (void)downloadAndCacheObjectsWithCompletion:(void (^)(NSError *))callback
{
__block NSError *downloadError1;
__block NSError *downloadError2;
__block NSError *downloadError3;
__block NSError *downloadError4;
NSLog(#"%#", NSStringFromSelector(_cmd));
dispatch_group_t downloadGroup = dispatch_group_create();
dispatch_group_enter(downloadGroup);
[self fetchDataWithCompletion:^(NSArray *artwork, NSError *error) {
downloadError1 = error;
dispatch_group_leave(downloadGroup);
}];
dispatch_group_enter(downloadGroup);
[self fetchDataWithCompletion:^(NSArray *artworkPhotos, NSError *error) {
downloadError2 = error;
dispatch_group_leave(downloadGroup);
}];
dispatch_group_enter(downloadGroup);
[self fetchDataWithCompletion:^(NSArray *artists, NSError *error) {
downloadError3 = error;
dispatch_group_leave(downloadGroup);
}];
dispatch_group_enter(downloadGroup);
[self fetchDataWithCompletion:^(NSArray *badges, NSError *error) {
downloadError4 = error;
dispatch_group_leave(downloadGroup);
}];
dispatch_group_notify(downloadGroup, dispatch_get_main_queue(), ^{
NSError *returnError;
if (downloadError1 || downloadError2 || downloadError3 || downloadError4) {
returnError = [[NSError alloc] initWithDomain:#"ParseFactory" code:-1 userInfo:#{NSLocalizedDescriptionKey: #"There was an error retrieving the content"}];
}
if (callback) {
callback(returnError);
}
});
}
- (void)fetchDataWithCompletion:(void(^)(NSArray *data, NSError *error))callback
{
NSLog(#"Fetching Data");
if ([self.cachedData objectForKey:kDataClassName]) {
if (callback) {
callback([self.cachedData objectForKey:kDataClassName], nil);
}
return;
}
PFQuery *dataQueue = [PFQuery queryWithClassName:kDataClassName];
dataQueue.cachePolicy = kPFCachePolicyCacheThenNetwork;
[dataQueue findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
[self.cachedData setObject:objects forKey:kDataClassName];
} else {
NSLog(#"Fetching Data Error: %#", error);
}
if (callback) {
callback(objects, error);
}
}];
}
The download process listed above is called from AppDelegate as such
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//Register PFObject subclasses
[Data registerSubclass];
[Parse setApplicationId:#"appkey" clientKey:#"clientkey"];
[[ParseFactory sharedInstance] downloadAndCacheObjectsWithCompletion:^(NSError *error) {
}];
return YES;
}
Stack trace:
The error you're seeing indicates that your program calls dispatch_group_leave too many times. It's trivial to reproduce. I reproduced it with this program:
int main(int argc, const char * argv[])
{
#autoreleasepool {
dispatch_group_t group = dispatch_group_create();
dispatch_group_leave(group);
}
return 0;
}
Therefore I deduce that your fetchDataWithCompletion: method calls its completion block more than once. If you can't figure out why, edit your question to include the source code of that method (and any related methods or declarations).
I come in late, but it seems clear your issue comes from the kPFCachePolicyCacheThenNetwork.
Parse will call the completion block twice, one with cached data (even the 1st time), one with downloaded data... so your dispatch_group_leave will be called twice as much as your dispatch_group_enter.