The Facebook places SDK is only available in Objective-C, I am not to good with understanding OBJC and all the documentation on how to use this library is in OBJC. I pod installed the library using cocoa pods.
use_frameworks!
pod 'FBSDKPlacesKit'
my Podfile uses framework so I don't think I would be needing a header file.
[self.placesManager
generatePlacesGraphRequestForSearchTerm:#"pizza"
categories: #[#"FOOD_BEVERAGE"]
fields: #[FBSDKPlacesFieldKeyName,
FBSDKPlacesFieldKeyAbout,
FBSDKPlacesFieldKeyPlaceID]
distance:1000
cursor:nil // Pagination cursor
completion:^(FBSDKGraphRequest * _Nullable graphRequest, CLLocation * _Nullable location, NSError * _Nullable error) {
if (graphRequest) {
[graphRequest startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
// Handle the response.
// The result will contain the JSON for the place search.
}];
}
}];
and
FBSDKGraphRequest *graphRequest = [self.placesManager
placesGraphRequestForLocation:nil
searchTerm:#"pizza"
categories: #[#"FOOD_BEVERAGE"]
fields: #[FBSDKPlacesFieldKeyName,
FBSDKPlacesFieldKeyAbout,
FBSDKPlacesFieldKeyPlaceID]
distance:1000
cursor:nil];
[graphRequest startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
// Handle the response.
// The result will contain the JSON for the place search.
}];
can someone please convert this to Swift, or tell me how to use this in Swift?
Related
I need my APP to be able to get data on the user Facebook friends.
I managed to get the id of the Facebook friends but I'm stuck on getting their data.
I found an Objective C code that supposed to get the data, the problem is that I am using swift but I don't know how to convert the Objective C code to swift.
This is the code:
FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc]
initWithGraphPath:#"/{user-id}"
parameters:params
HTTPMethod:#"GET"];
[request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection,
id result,
NSError *error) {
// Handle the result
}];
Any suggestions.
The Swift version would be
var request : FBSDKGraphRequest = FBSDKGraphRequest(
graphPath: "/{user-id}/taggable_friends",
parameters: params,
HTTPMethod: "GET"
)
request.startWithCompletionHandler { (
connection: FBSDKGraphRequestConnection!,
result: AnyObject!,
error:NSError!) -> Void in
// Handle the result
}
I'm trying to configure an Open Graph post. I've followed the code examples on the FB developer site, and, using a test_user, a post is supposedly successfully generated. Here is my code:
- (void)createOGObjectForImage:(NSURL *)imageURL
{
NSMutableDictionary<FBGraphObject> *object =
[FBGraphObject openGraphObjectForPostWithType:#"ogminigame:mini_game"
title:#"Mini Game"
image:#"https://fbstatic-a.akamaihd.net/images/devsite/attachment_blank.png"
url:imageURL
description:#""];
[FBRequestConnection startForPostWithGraphPath:#"me"
graphObject:object
completionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
if(!error) {
NSLog(#"Result: %#", [result description]);
[self createOGActionWithResult:result];
} else {
NSLog(#"Error posting the Open Graph object to the Object API: %#", error);
[self sharePhotoWithShareDialog:self openGraphAction:nil];
}
}];
}
However, nothing is appearing on the test user wall. When I step through the code, I can see that when I create the OG object, the result has the following contents:
"FACEBOOK_NON_JSON_RESULT" = true;
More specifically, it looks like this:
So when I create my Action, when I try to retrieve the objectID using:
NSString *objectId = [result objectForKey:#"id"];
it obviously returns nil. Am I missing a stage with the result object? I've tried searching for similar problems but there doesn't seem to be much in the way of an explanation.
Well, it seems the code supplied on the Facebook developer site where you supply your custom stories is incorrect. Namely, it should look like:
- (void)createOGObjectForImage:(NSURL *)imageURL
{
NSMutableDictionary<FBOpenGraphObject> *object = [FBGraphObject openGraphObjectForPostWithType:#"ogminigame:mini_game"
title:#"Mini Game"
image:#"https://fbstatic-a.akamaihd.net/images/devsite/attachment_blank.png"
url:imageURL
description:#""];
[FBRequestConnection startForPostOpenGraphObject:object completionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
if(!error) {
NSLog(#"Result: %#", [result description]);
[self createOGActionWithResult:result];
} else {
NSLog(#"Error posting the Open Graph object to the Object API: %#", error);
[self sharePhotoWithShareDialog:self openGraphAction:nil];
}
}];
}
So you cast the dictionary to an FBOpenGraphObject, rather than an FBGraphObject and call startForPostOpenGraphObject instead of startForPostWithGraphPath.
It seems to me Facebook need to be a bit more consistent with their documentation.
I still have nothing showing on the test_account page, but at least the above doesn't seem to be the cause of the issue...
This is a snippet from AFNetworking's sample code:
+ (void)globalTimelinePostsWithBlock:(void (^)(NSArray *posts, NSError *error))block {
[[AFAppDotNetAPIClient sharedClient] getPath:#"stream/0/posts/stream/global" parameters:nil success:^(AFHTTPRequestOperation *operation, id JSON) {
NSArray *postsFromResponse = [JSON valueForKeyPath:#"data"];
NSMutableArray *mutablePosts = [NSMutableArray arrayWithCapacity:[postsFromResponse count]];
for (NSDictionary *attributes in postsFromResponse) {
Post *post = [[Post alloc] initWithAttributes:attributes];
[mutablePosts addObject:post];
}
if (block) {
block([NSArray arrayWithArray:mutablePosts], nil);
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
if (block) {
block([NSArray array], error);
}
}];
}
What I don't understand are:
The (void (^)(NSArray *posts, NSError *error))block part. Assuming that it is a block, does it mean the block is a parameter of the globalTimelinePostsWithBlock method?
Following the first question, can anyone explain the syntax for me? Why is there a block keyword in the end?
if you don't know how blocks work.. then don't bother trying to understand it just by looking at the code (even if you have used lambda/anonymous functions in other languages like javascript or ruby).. b/c the objective-c syntax is a class on it's own..
i'd recommend you take the time to understand block syntax in obj-c on it's own.. then take a look at examples that use them. This tutorial is excellent (two parts)..
I did what you did before.. and pulled out half my hair.. after looking at the said tutorial.. my hair grew right back up :)
just for fun i'll try to address your specific questions:
1.The (void (^)(NSArray *posts, NSError *error))block part. Assuming that it is a block, does it mean the block is a parameter of the globalTimelinePostsWithBlock method?
yes it is.. so this is a way of calling this method:
// first define the block variable
void(^block)(NSArray *posts, NSError *error) = (NSArray *posts,NSError *error) {
// block body
// posts and error would have been passed to this block by the method calling the block.
// so if you look at the code sample below..
// posts would be [NSArray arrayWithArray:mutablePosts]
// and error would just be nil
}
// call the function
[AFNetworking globalTimelinePostsWithBlock:block];
2. Following the first question, can anyone explain the syntax for me? Why is there a block keyword in the end?
basically the block keyword is the name of the argument.. notice how it's used in the body of the method:
if (block) {
block([NSArray arrayWithArray:mutablePosts], nil);
}
again to understand how/why.. i recommend you look at the above article.. learning blocks in obj-c has a bit of learning curve.. but once you master it.. it's an amazing tool. please take a look at my answer here to see some sample uses for blocks.
Here is also a sample question/answer that provides a case study of converting delegation into a block based approach, which can also illustrate how blocks work.
The block is passed into the method as something to be called when the API call succeeds. globalTimelinePostsWithBlock will call the block passed in with the data (and possibly an NSError)
block in this case isn't a keyword, it's just the name of the variable.
If you wanted to use globalTimelinePostsWithBlock, you would call it like
[ClassName globalTimelinePostsWithBlock:^(NSArray *posts, NSError *error) {
// Check error, then do something with posts
}];
(where ClassName is the name of the class globalTimelinePostsWithBlock is defined on)
Block definition are similar to C-functions.
(void (^)(NSArray *posts, NSError *error))block
The initial void defines the return type of the function.
The ^ is the block pointer. Similar to * for objects.
(NSArray *posts, NSError *error) are the parameters with variable names.
block is the variable in which this block gets stored. (Bad naming here)
I could not figure out how to change the value of results inside the success block. I use __block like some post suggests but results is forever nil. I set breakpoint inside of block and make sure that JSON is not nil, which download data as I expected.
I am using AFNetworking library if that's relevant.
+(NSArray *)eventsByCityID:(NSString *)cityID startIndex:(NSUInteger)start count:(NSUInteger)count
{
__block NSArray *results = nil;
[[DoubanHTTPClient sharedClient] getPath:#"event/list" parameters:#{#"loc":dataSingleton.cityID} success:^(AFHTTPRequestOperation *operation, id JSON) {
results = [JSON valueForKey:#"events"];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"download events error: %# \n\n",error);
}];
return results;
}
More likely than not, that [very poorly named] method getPath:parameters:success:failure: is asynchronous.
Thus, you need to tell something in the success block that the value has changed. I.e.
^{
[something yoManGotEvents:[JSON valueForKey:#"events"]];
}
(Methods shouldn't be prefixed with get outside of very special circumstances. Third party libraries with lots of API using that prefix outside of said circumstances raise question as to what other system specific patterns they may not be following.)
I am currently trying to put together an app - with the foundation of it being (hopefully) built on the Facebook iOS SDK 3.0 tutorial.
The tutorial I am following is located at: http://developers.facebook.com/docs/tutorials/ios-sdk-tutorial/authenticate/
I have found there to be a few changes throughout the various SDK versions from Facebook when it comes to the final release.
However I do have one final issue before the code will compile:
"No known class method for selector 'sessionOpenWithPermissions:completionHandler:'"
This error refers to the following code:
- (void)openSession
{
[FBSession sessionOpenWithPermissions:nil completionHandler:
^(FBSession *session, FBSessionState state, NSError *error) {
[self sessionStateChanged:session state:state error:error];
}];
}
When looking at the FBSession.h file in Xcode there is no mention of sessionOpenWithPermissions.
Can anyone please help me with regard to this? I am new to Objective-C/Xcode and am learning via trial by fire.
I ran into the same issue, got my code working with the below change.
//REPLACE
[FBSession sessionOpenWithPermissions:nil
completionHandler: ^(FBSession *session, FBSessionState state, NSError *error) {
[self sessionStateChanged:session state:state error:error];
}];
//WITH
[FBSession openActiveSessionWithPermissions:nil
allowLoginUI:YES
completionHandler:^(FBSession *session, FBSessionState state, NSError *error) {
[self sessionStateChanged:session state:state error:error];
}];
If you alt click on the method you'll get more info on the parameters to pass.
openActiveSessionWithPermissions options
It looks like the documentation has a bug. According the API Change log, that class method as been replaced.
FBSession class method sessionOpenWithPermissions:completionHandler: has been removed, instead use the new openActiveSessionWithPermissions:allowLoginUI:completionHandler: class method.
API Change log URL