How can I count the amount of Facebook friends in iOS sdk? - facebook-graph-api

I'm trying to figure out how to get a random userID from my friends.
is there a way to do it with "friendPickerController" ?
the only "count" method I've found is in the selection, which dosen't help.

You can get the total friend count using following method
FBRequest* friendsRequest = [FBRequest requestForMyFriends];
[friendsRequest startWithCompletionHandler: ^(FBRequestConnection *connection,
NSDictionary* result,
NSError *error) {
NSArray* friends = [result objectForKey:#"data"];
NSLOG(#"Total Friend :%#",friends.count);
}];

Just updating in case this helps anyone. While Dipak's answer worked flawlessly for me at the end, it didn't work until I added permission to retrieve the count. I added the following lines of code just before Dipak's code and it returned me the proper friend count.
NSArray *permissions = [NSArray arrayWithObjects:#"friends_about_me", nil];
[FBSession openActiveSessionWithReadPermissions:permissions
allowLoginUI:YES
completionHandler:^(FBSession *session, FBSessionState status, NSError *error) {
}];
[FBSession setActiveSession:[FBSession activeSession]];

Related

Unique identifier associated to the iCloud account

I would like to use a code to identify users, without asking them for their email address or other sensitive information, that would also possibly follow her when she changes device. Long ago I trustily implemented the following piece of code:
NSString *strApplicationUUID=nil;
+(NSString*) sharedUdid{
if (!strApplicationUUID){
NSString *appName=[[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString*)kCFBundleNameKey];
strApplicationUUID = [SSKeychain passwordForService:appName account:#"incoding"];
if (strApplicationUUID == nil) {
strApplicationUUID=[[NSUserDefaults standardUserDefaults] objectForKey:#"udid"];
if (!strApplicationUUID) strApplicationUUID=[[[UIDevice currentDevice] identifierForVendor] UUIDString];
else strApplicationUUID = [[NSUUID UUID] UUIDString];
[SSKeychain setPassword:strApplicationUUID forService:appName account:#"incoding"];
}
}
return strApplicationUUID;
}
That I unfortunately found producing all but unique identifiers for each user. So I temporarily switched to using the token, notwithstanding its length and the fact it is linked to a single device. Is there some better solution?
I switched to using the CloudKit identifier.

does NSMetadataQueryDidUpdateNotification can work with NSFileManager setUbiquitous

i am trying to track my icloud upload progress using NSMetadataQueryDidUpdateNotification..but it can't work... i don't know what the problem is..
here is my code for upload to icloud
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
NSFileCoordinator* fileCoordinator = [[NSFileCoordinator alloc] initWithFilePresenter:nil];
[fileCoordinator coordinateReadingItemAtURL:backupUrl options:NSFileCoordinatorReadingWithoutChanges error:nil byAccessor:^(NSURL *newURL) {
NSFileManager* fm = [NSFileManager defaultManager];
NSError *theError = nil;
BOOL success =[fm setUbiquitous:YES itemAtURL:backupUrl destinationURL:[[ubiq URLByAppendingPathComponent:#"Documents" isDirectory:true] URLByAppendingPathComponent:bName] error:&theError];
if (!(success)) {
[progView dismiss];
UIAlertView* alertFail=[[UIAlertView alloc]initWithTitle:#"Backup Error" message:#"Could not backup to iCloud." delegate:Nil cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alertFail show];
NSLog(#"iCloud error: %#", [theError localizedDescription]);
}
else{
[self loadNotes:bName];
}
}];
});
and this code for tracing my upload progress
- (void)loadNotes:(NSString *)bname {
self.alertQuery = [[NSMetadataQuery alloc] init];
[self.alertQuery setPredicate:[NSPredicate predicateWithFormat:#"%K LIKE %#", NSMetadataItemFSNameKey, bname]];
[self.alertQuery setSearchScopes:#[NSMetadataQueryUbiquitousDataScope]];
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(liveupdate:) name:NSMetadataQueryDidUpdateNotification object:self.alertQuery];
[self.alertQuery startQuery];
}
-(void)liveupdate:(NSNotification *)note {
NSMetadataQuery* query=[note object];
if ([query resultCount]==0){
return;
}
NSMetadataItem* item=[query resultAtIndex:0];
float progress=[[item valueForAttribute:NSMetadataUbiquitousItemPercentUploadedKey]floatValue];
[progView.progBar setProgress:progress animated:NO];
if ([[item valueForAttribute:NSMetadataUbiquitousItemIsUploadedKey] boolValue]){
[query stopQuery];
[query disableUpdates];
_alertQuery=nil;
[progView dismiss];
}
}
what is the wrong with code...
can somebody tell me what is the best way to track icloud upload progress in NSFileManager setUbiquitous....
thank you...
You will probably want to observe the NSMetadataQueryDidFinishGatheringNotification notification, which fires first, with the initial set of results.
But even then, you may not get what you want, because the update notification will only fire if the set of results changes. You are searching for a particular file, and since that file is not being deleted or anything like that, your set of results will remain the same, even if the file uploads or downloads.
In my experience, NSMetadataQuery is not very effective for monitoring upload and download progress. You can hack it to almost work, but it is never exactly what you want.
Probably the best you can do is fire the metadata query, observe the finished-gathering notification, stop the query, and start the query again. Do this at regular intervals of a second or so, and you should be able to track the progress.
You should also consider whether you really want to track progress of an individual file. It will depend how large your files are. In many cases, you may be better to track the number of files to upload/download, or the total bytes remaining.
If this is the case, you can try to setup a metadata that includes a predicate with the uploaded/downloaded status included. This will continually fire notifications when a file finishes uploading/downloading. You can find an example of this here. Look for the method startMonitoringMetadata.

Multiple AFHTTPRequestOperations that has dependency of each other

What I trying to achieve is send two request to the server which orders are matter,and the second request's parameters is unknown until the first request result comes back.
I already tring as the following code snippet using the afnetworking2.0
NSOperationQueue *queue=[[NSOperationQueue alloc]init];
NSMutableURLRequest*request=[NSMutableURLRequest requestWuthURL#"URLSTRING"];
// configure the request with parameters
[request setHTTPBody:JsonData];
[request setHTTPMethod:#"POST"];
AFHTTPRequestOperation* operation=[[AFHTTPRequestOperation alloc]initWithRequest:request];
[operation setComplemetionBlockWithSucess:^(AFHTTPRequestOperation* operation, id responsObject)
{
//parse the result using NSXMLParser;
NSInteger result=weakSelf.parseRule.identifier;
}
failure :^(AFHTTPRequestOperation* operation, NSError *error)
{
NSLog(#"fail");
}];
NSMutableURLRequest*secondRequest=[NSMutableURLRequest requestWuthURL#"URLSTRING"];
//Using the first request result to set the parameters in second request
[secondRequest setHTTPBody:JsonData];
[secondRequest setHTTPMethod:#"POST"];
AFHTTPRequestOperation* secondOperation=[[AFHTTPRequestOperation alloc]initWithRequest:secondRequest];
[secondOperation setComplemetionBlockWithSucess:^(AFHTTPRequestOperation* operation, id responsObject)
{
//do something
}
failure :^(AFHTTPRequestOperation* operation, NSError *error)
{
NSLog(#"fail");
}];
[secondOperation addDependency:Operation];
[queue addOPerations:#[operation,secondOperation]];
Which didn't work, I can get back the first operation result correctly,but the thing is that my second request params setting is execute before the result comes back.Any advice will be really appreciated.
Should I use the dispatch_semaphore? Or Any other suggestion?

Testing HTTP using Kiwi/Nocilla

I just started developing an app that connects to this URL and retrieves the rate exchange for a given pair of currencies.
I need to test the HTTP request and I ended up learning about Kiwi and Nocilla. However, I'm completely new to any kind of testing and there's not a lot of information about Nocilla that can help me to get started.
I added all the NSURLConnectionDataDelegate and NSURLConnectionDelegate methods to the ViewController of my single view application, and the data retrieved from the URL is stored in #property (strong, nonatomic) NSMutableData *receivedData;. When I run the program everything works as expected but I haven't been able to pass the test I wrote:
SPEC_BEGIN(URLConnectionSpec)
__block URLConnectionAppDelegate *app_delegate;
__block URLConnectionViewController *view_controller;
describe(#"URLConnection", ^{
beforeAll(^{
[[LSNocilla sharedInstance] start];
app_delegate = [[UIApplication sharedApplication] delegate];
[[app_delegate shouldNot] beNil];
view_controller = app_delegate.viewController;
});
afterAll(^{
[[LSNocilla sharedInstance] stop];
});
afterEach(^{
[[LSNocilla sharedInstance] clearStubs];
});
context(#"When testing", ^{
it(#"should do something", ^{
stubRequest(#"GET", #"http://rate-exchange.appspot.com/currency?from=USD&to=EUR&q=1");
[view_controller beginCommunication];
[[expectFutureValue([NSString stringWithUTF8String:[view_controller.receivedData bytes]]) shouldEventuallyBeforeTimingOutAfter(2)] equal:#"{\"to\": \"EUR\", \"rate\": 0.76610740799999999, \"from\": \"USD\", \"v\": 0.76610740799999999}"];
});
});
});
SPEC_END
I'm sorry for the long snippet of code.
The test always failed with this message
URLConnection_WhenTesting_ShouldDoSomething] : 'URLConnection, When testing, should do something' [FAILED], expected subject to equal "{"to": "EUR", "rate": 0.76610740799999999, "from": "USD", "v": 0.76610740799999999}", got ""
I tried changing the time to even 10 seconds hoping that the test finished too early but I got the same results. I don't know why 'receivedData' is empty.
I would really appreciate any help
See discussion in comments: the overall structure of the Kiwi test looks good, the Nocilla stubRequest function call doesn't seem to result in the response that the test is expecting.
Perhaps you could use andReturnRawResponse to set up the expected response data. Something like this (assuming I got the Nocilla syntax correct):
NSData *rawData = ...
stubRequest(...).andReturnRawResponse(rawData);
[view_controller beginCommunication];
[expectFutureValue([view_controller.receivedData bytes])
shouldEventuallyBeforeTimingOutAfter(2)] equal:rawData.bytes];

How to get large photo URL in one API call?

I want to display large photos in my Facebook app's feed view immediately. Is it possible to get the large photo src URL from a stream/feed using one API call? The photo id is returned in the stream/feed and one can of course then supply this photo id in an additional FQL or graph API call to retrieve all the information about that photo. However, is there a way using multi-query or batch calls to get a larger photo src url using one API roundtrip?
I haven't tried this with stream/feed photos, but the generally accepted way of doing this is:
http://graph.facebook.com/{ID of object}/picture
If you want the "large" version, you would do:
http://graph.facebook.com/{ID of object}/picture?type=large
I'm not 100% sure if this would work for an actual photo (instead of a user profile picture or page profile pic), but I have a hunch it will - the only caveat is that you obviously must have a logged in user that is authorized to view the photo (unless it's public).
If anybody is looking to this and type large is not enough, I found other solutions.
Type large is kind of small anyway (close to 200px). You can get larger image by adding i.e. ?width=1000 or ?height=1000. Facebook will return picture closest to given dimension and preserve aspect ratio. When passing both dimenstions like ?width=1000&height=1000, facebook will cut image to given dimensions (in this case square).
Use Facebook UserId (Oject ID) to get the picture.
https://graph.facebook.com/173xxxx8635/picture?type=large&redirect=false
which returns JSON data with picture URL.
{
"data": {
"is_silhouette": false,
"url": "https://fbcdn-profile-a.akamaihd.net/xxx/xyz/1cc066a2cae3f301d"
}
}
A good trick with the new api is to get the pic_cover field from the event table and to process it according to the size you want to use
I found when I was having this trouble that it turned out to be the picture I was downloading rather than the size I was setting it.
If for example I downloaded all my photos with a request of
[FBRequestConnection startWithGraphPath:#"/me/photos?fields=created_time,name,picture&type=tagged" parameters:nil HTTPMethod:#"GET" completionHandler:^(FBRequestConnection * connection, id result, NSError *error) {
NSDictionary * userData = (NSDictionary *)result;
NSMutableArray * array = [[NSMutableArray alloc] initWithArray:userData[#"data"]];
for (NSDictionary * dict in eventsToAdd) {
UIImage * image = dict[#"picture"]
}
}];
I am using the dictionary key search "picture" as I want the picture.
This though will get me a lower quality picture than if I searched for "source" in this search:
[FBRequestConnection startWithGraphPath:#"/me/photos?fields=created_time,name,source&type=tagged" parameters:nil HTTPMethod:#"GET" completionHandler:^(FBRequestConnection * connection, id result, NSError *error) {
NSDictionary * userData = (NSDictionary *)result;
NSMutableArray * array = [[NSMutableArray alloc] initWithArray:userData[#"data"]];
for (NSDictionary * dict in eventsToAdd) {
UIImage * image = dict[#"source"]
}
}];
If you go on the Facebook API explorer and search for photos and then click on the picture and source jpg links you can see the difference in size and quality.
Since changing this method I have managed to get rid of using the type parameters as it doesn't seem to make a different.
Note: I am using iPhone and not iPad or a larger screen so I don't know how this affects bigger screens.
The answer by #streetlogics works fine but only on pictures that have {object_id}.
http://graph.facebook.com/{object_id}/picture
But I also wanted large pictures for the feed's shared links, which sometimes don't have {object_id}. I finally realized that the {picture} thumbnail URL contains the encoded URL for the original site's large image:
https://external.xx.fbcdn.net/safe_image.php?d=AQBe9UvGd0vPbAHP&w=130&h=130&url=http%3A%2F%2Fskift.com%2Fwp-content%2Fuploads%2F2015%2F12%2Fpollution.jpg&cfs=1
--> contains -->
http://skift.com/wp-content/uploads/2015/12/pollution.jpg
So I made a loop that checks for {object_id} and if not present then extracts the URL from {picture}:
if(isset($post['object_id'])) {
echo "http://graph.facebook.com/".$post['object_id']."/picture";
}
elseif(isset($post['picture'])) {
echo urldecode(preg_replace('/&cfs.*/', '', preg_replace('/.*url=/', '', $post['picture'])));
}
else {
echo "no_large_image";
}