IOS5 - AFNetworking processing request - iphone

I'm making an application in which I have to call some webservices. I chose to work with AFNetworking.
I followed the Twitter example provided in the library. Everything works well except that I have permanently the little "processing circle" in the notification bar (see the image below).
Here's the code I have for my request :
- (id)initWithAttributes:(NSDictionary *)attributes
{
self = [super init];
if (!self) {
return nil;
}
_name = [attributes valueForKeyPath:#"name"];
return self;
}
+ (void)itemsListWithBlock:(void (^)(NSArray *items))block
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSDictionary *user = [defaults objectForKey:#"user"];
NSDictionary *company = [defaults objectForKey:#"company"];
NSMutableDictionary *mutableParameters = [NSMutableDictionary dictionary];
/*
** [ Some stuff to set the parameters in a NSDictionnary ]
*/
MyAPIClient *client = [MyAPIClient sharedClient];
[[AFNetworkActivityIndicatorManager sharedManager] setEnabled:YES];
[[AFNetworkActivityIndicatorManager sharedManager] incrementActivityCount];
NSURLRequest *request = [client requestWithMethod:#"POST" path:#"getMyList" parameters:mutableParameters];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
NSMutableArray *mutableItems = [NSMutableArray arrayWithCapacity:[JSON count]];
for (NSDictionary *attributes in JSON) {
ListItem *item = [[ListItem alloc] initWithAttributes:attributes];
[mutableItems addObject:item];
}
if (block) {
block([NSArray arrayWithArray:mutableItems]);
}
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON){
[[[UIAlertView alloc] initWithTitle:#"Error" message:[error localizedDescription] delegate:nil cancelButtonTitle:nil otherButtonTitles:#"Ok", nil] show];
if (block) {
block(nil);
}
}];
[operation start];
}
Does this means my request isn't finished ? I'm not really getting what I'm doing wrong here...
If someone could help, I'd really appreciate. Thanks.

Don't call [[AFNetworkActivityIndicatorManager sharedManager] incrementActivityCount]; this increase the activity count with 1 and the [operation start]; will call it also. now the activity count is 2 and will get decreased when the operation is done. But since you called the incrementActivityCount it will bring it back to 1 and not 0.
Just call [[AFNetworkActivityIndicatorManager sharedManager] setEnabled:YES]; once, for example place it in the application:applicationdidFinishLaunchingWithOptions: method of your applications appDeletage.
Also I would suggest to add the operation to a NSOperationQueue and not just call start on it.

Related

Mapping a large JSON with Restkit

I am using restkit for a time now. And everything worked perfect. But now I want to map a json into my core database. This is a JSON of (10 MB). You can see the JSON over here.
I have an API class where I do my mapping
-(RKObjectManager *)mapGetItems{
RKEntityMapping* rubriekMapping = [RKEntityMapping mappingForEntityForName:#"Items" inManagedObjectStore:managedObjectStore];
rubriekMapping.identificationAttributes = #[#"itemNum"] ;
[rubriekMapping addAttributeMappingsFromDictionary:#{
#"ItemNum": #"itemNum",
#"ItemDescNl": #"itemDescNl",
#"ItemDescFr": #"itemDescFr",
#"Group1": #"group1",
#"Group2": #"group2",
#"Group3": #"group3",
#"Group4": #"group4",
#"DateCr": #"dateCr",
#"GrpItem": #"grpItem",
#"GrpDesc1": #"grpDesc1",
#"GrpDesc2": #"grpDesc2",
#"GrpDesc1Fr": #"grpDesc1Fr",
#"SalUnitNl": #"salUnitNl",
#"SalUnitFr": #"salUnitFr",
#"LadderQty": #"ladderQty",
#"Netprice": #"netPrice",
#"IsPromo": #"isPromo",
#"IsNew": #"isNew",
}];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:rubriekMapping
pathPattern:nil
keyPath:#"ds-ttitems.tt-items" statusCodes:[NSIndexSet indexSetWithIndex:200]];
NSArray *arrResponsDescriptor = [[NSArray alloc]initWithObjects:responseDescriptor, nil];
[objectManager addResponseDescriptorsFromArray:arrResponsDescriptor];
return objectManager;
}
And a dataModel class, in this class I setup my object store.
This is all going well and everything is set up correctly.
Now for my request I do this.
-(void)fetchRubrieken{
API *api = [API new];
RKManagedObjectStore *store = [[ClaesDataModel sharedDataModel] objectStore];
NSManagedObjectContext *context = store.mainQueueManagedObjectContext;
RKObjectManager *objectManager = [api mapGetItems];
NSString *request = #"/claes/items.json";
[objectManager getObjectsAtPath:request parameters:nil
success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
NSError *error = nil;
BOOL success = [store.mainQueueManagedObjectContext save:&error];
if (!success) RKLogWarning(#"Failed saving managed object context: %#", error);
NSLog(#"done fetching");
}
failure:^(RKObjectRequestOperation *operation, NSError *error) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error"
message:[error localizedDescription]
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
NSLog(#"Hit error: %#", error);
}];
NSError *error = nil;
[context save:&error];
}
The problem is not that it isn't working. It only takes a very very long time. So my question is, how can i make this go faster?
Hope that anybody can help me!
Kind regards,
PS. If you need more details, I will provide but I think this is the essential part.

iOS Facebook SDK 3.2 Image Publish w/Description Open Graph

No matter what I try I cannot get my description to show up on Facebook. I used the debugger and all is well with the generated link and the URL is populated with the appropriate data. The picture is uploaded fine, but the description is not there. Is there something I need to setup in Facebook settings for the app?
Here is the relevant code:
- (id<FBPost>)outfitObjectForOutfit{
id<FBPost> result = (id<FBPost>)[FBGraphObject graphObject];
NSString *format =
#"http://mysite.mobi/app/fbOpen.php?"
#"og:title=%#&og:description=%%22%#%%22&"
#"og:caption=%%22%#%%22&"
#"og:image=http://mysite.mobi/images/transBlank.png&"
#"body=%#";
result.url = [NSString stringWithFormat:format,
#"New Post Title",fldDescription.text,fldDescription.text,fldDescription.text];
return result;
}
And the portion that publishes to FB:
- (void)postOpenGraphActionWithPhotoURL:(NSString*)photoURL
{
id<FBPost> outfitObject = [self outfitObjectForOutfit];
id<FBPostOutfit> action =
(id<FBPostOutfit>)[FBGraphObject graphObject];
action.outfit=outfitObject;
if (photoURL) {
NSMutableDictionary *image = [[NSMutableDictionary alloc] init];
[image setObject:photoURL forKey:#"url"];
NSMutableArray *images = [[NSMutableArray alloc] init];
[images addObject:image];
action.image = images;
}
[FBSettings setLoggingBehavior:[NSSet
setWithObjects:FBLoggingBehaviorFBRequests,
FBLoggingBehaviorFBURLConnections,
nil]];
NSLog(#"%#",action);
NSMutableDictionary *params = [NSMutableDictionary dictionary];
[params setObject:fldDescription.text forKey:#"message"];
[FBRequestConnection startForPostWithGraphPath:#"me/appnamespace:action"
graphObject:action
completionHandler:
^(FBRequestConnection *connection, id result, NSError *error) {
NSString *alertText;
if (!error) {
alertText = [NSString stringWithFormat:
#"Posted Open Graph action, id: %#",
[result objectForKey:#"id"]];
} else {
alertText = [NSString stringWithFormat:
#"error: domain = %#, code = %d",
error.domain, error.code];
NSLog(#"%#",error);
}
[[[UIAlertView alloc] initWithTitle:#"Result"
message:alertText
delegate:nil
cancelButtonTitle:#"Thanks!"
otherButtonTitles:nil]
show];
}
];
}
I figured out my problem. I was confusing what the Facebook examples did (activity publishing) with publishing to a user's wall. This was all that I had to do to get it to work:
NSMutableDictionary* params = [[NSMutableDictionary alloc] init];
[params setObject:fldDescription.text forKey:#"message"];
[params setObject:UIImagePNGRepresentation(userImage) forKey:#"picture"];
[FBRequestConnection startWithGraphPath:#"me/photos"
parameters:params
HTTPMethod:#"POST"
completionHandler:^(FBRequestConnection *connection,
id result,
NSError *error)
{
if (error) {
[[[UIAlertView alloc] initWithTitle:#"Result"
message:#"Sorry there was an error posting to Facebook."
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil]
show];
}
}];
I should also mention that I had to go into the opengraph settings for my app and allow user messages and user generated photos.

facebook integration in iphone with Facebook sdk for ios5 and 6

i have use FAcebook sdk 3.0 to integrate facebook.I have use sample code "HelloFacebookSample"
to post status.
I have change in Info.plist file with my AppId.
I have problem that show armv7s,armv7 architecture problem.I even solve out that by "Build Active Architecture Only "to YEs.
I have code that show button for login/logout for facebook
#import "HFViewController.h"
#import "AppDelegate.h"
#import <CoreLocation/CoreLocation.h>
#interface HFViewController () <FBLoginViewDelegate>
#property (strong, nonatomic) IBOutlet UIButton *buttonPostStatus;
#property (strong, nonatomic) id<FBGraphUser> loggedInUser;
- (IBAction)postStatusUpdateClick:(UIButton *)sender;
- (void)showAlert:(NSString *)message
result:(id)result
error:(NSError *)error;
#end
#implementation HFViewController
#synthesize shareStringFb;
#synthesize buttonPostStatus = _buttonPostStatus;
#synthesize loggedInUser = _loggedInUser;
- (void)viewDidLoad {
[super viewDidLoad];
// Create Login View so that the app will be granted "status_update" permission.
self.buttonPostStatus.enabled = YES;
FBLoginView *loginview = [[FBLoginView alloc] init];
loginview.frame = CGRectOffset(loginview.frame, 5, 5);
loginview.delegate = self;
[self.view addSubview:loginview];
[loginview sizeToFit];
statusText.text=self.shareStringFb;
{
// if the session is closed, then we open it here, and establish a handler for state changes
}
}
-(IBAction)backClick:(id)sender
{
[self.view removeFromSuperview];
}
- (void)viewDidUnload {
self.buttonPostStatus = nil;
self.loggedInUser = nil;
[super viewDidUnload];
}
- (void)loginViewShowingLoggedInUser:(FBLoginView *)loginView {
// first get the buttons set for login mode
self.buttonPostStatus.enabled = YES;
}
- (void)loginViewFetchedUserInfo:(FBLoginView *)loginView
user:(id<FBGraphUser>)user {
// here we use helper properties of FBGraphUser to dot-through to first_name and
// id properties of the json response from the server; alternatively we could use
// NSDictionary methods such as objectForKey to get values from the my json object
self.loggedInUser = user;
}
- (void)loginViewShowingLoggedOutUser:(FBLoginView *)loginView {
self.buttonPostStatus.enabled = NO;
}
// Post Status Update button handler
- (IBAction)postStatusUpdateClick:(UIButton *)sender {
// Post a status update to the user's feed via the Graph API, and display an alert view
// with the results or an error.
NSString *message = [NSString stringWithFormat:#"Updating %#'s status at %#",
self.loggedInUser.first_name, [NSDate date]];
[FBRequestConnection startForPostStatusUpdate:self.shareStringFb
completionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
[self showAlert:message result:result error:error];
self.buttonPostStatus.enabled = YES;
}];
self.buttonPostStatus.enabled = NO;
}
// Post Photo button handler
it show one button with login/logout in simulator but when i test in device it doesn't show that button.
Please any one can tell me what is problem?Why it not show that?Is there any other way to integrate Fb in ios 5 and 6 both.
Use for
this facebook sdk (3.1) for iOS6
ViewController.h
#import <FacebookSDK/FacebookSDK.h>
{
NSDictionary *dictionary;
NSString *user_email;
NSString *accessTokan;
NSMutableDictionary *fb_dict;
}
- (IBAction)btn_loginwithfacebook:(id)sender;
{
if (!FBSession.activeSession.isOpen)
{
// if the session is closed, then we open it here, and establish a handler for state changes
[FBSession openActiveSessionWithReadPermissions:nil allowLoginUI:YES completionHandler:^(FBSession *session,FBSessionState state, NSError *error)
{
if (error)
{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Error" message:error.localizedDescription delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alertView show];
}
else if(session.isOpen)
{
[self btn_loginwithfacebook:sender];
}
}];
return;
}
[FBRequestConnection startWithGraphPath:#"me" parameters:[NSDictionary dictionaryWithObject:#"picture,id,birthday,email,name,gender,username" forKey:#"fields"] HTTPMethod:#"GET" completionHandler:^(FBRequestConnection *connection, id result, NSError *error)
{
if (!error)
{
if ([result isKindOfClass:[NSDictionary class]])
{
//NSDictionary *dictionary;
if([result objectForKey:#"data"])
dictionary = (NSDictionary *)[(NSArray *)[result objectForKey:#"data"] objectAtIndex:0];
else
dictionary = (NSDictionary *)result;
//NSLog(#"dictionary : %#",dictionary);
user_email = [dictionary objectForKey:#"email"];
[dictionary retain];
//NSLog(#"%#",user_email);//
}
}
}];
accessTokan = [[[FBSession activeSession] accessTokenData] accessToken];
//NSLog(#"%#",accessTokan);
NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] init] autorelease];
[request setURL:[NSURL URLWithString:[NSString stringWithFormat:#"https://graph.facebook.com/me?access_token=%#",accessTokan]]];
[request setHTTPMethod:#"GET"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
NSError *error;
NSURLResponse *response;
NSData *urlData=[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSString *str=[[NSString alloc]initWithData:urlData encoding:NSUTF8StringEncoding];
//NSLog(#"%#",str);
fb_dict = [str JSONValue];
[str release];}
FacebookAppID ::370546396320150
URL types
Item 0
URL Schemes
Item 0 ::fb370546396320150

Is this good programming style. Is it efficient to use class methods like this?

I am somewhat new to Objective-C and iOS development (about 1.5 years working with it and really just the last 8 months or so getting heavily involved). I have written a custom class that handles all my web-service requests. I use AFNetworking for these requests (and love it), but I want to make sure that what I am doing is efficient and not going to cause issues later.
From what I can see with Instruments and how the app performs, this seems like a good way to do it, but I am really far from being an expert and would like some feedback and/or advice.
Here is my NetworkClient class:
NetworkClient.h:
#import <Foundation/Foundation.h>
extern NSString * const APIKey;
#interface NetworkClient : NSObject
+(void)processURLRequestWithURL:(NSString *)url
andParams:(NSDictionary *)params
block:(void (^)(id obj))block;
+(void)processURLRequestWithURL:(NSString *)url
andParams:(NSDictionary *)params
syncRequest:(BOOL)syncRequest
block:(void (^)(id obj))block;
+(void)processURLRequestWithURL:(NSString *)url
andParams:(NSDictionary *)params
syncRequest:(BOOL)syncRequest
alertUserOnFailure:(BOOL)alertUserOnFailure
block:(void (^)(id obj))block;
+(void)handleNetworkErrorWithError:(NSError *)error;
+(void)handleNoAccessWithReason:(NSString *)reason;
#end
NetworkClient.m:
#import "NetworkClient.h"
#import "AFHTTPClient.h"
#import "AFHTTPRequestOperation.h"
#import "SBJson.h"
NSString * const APIKey = #"MyAPIKeyThatIsDefinedInDatabasePerApplication";
#implementation NetworkClient
+(void)processURLRequestWithURL:(NSString *)url
andParams:(NSDictionary *)params
block:(void (^)(id obj))block {
[self processURLRequestWithURL:url andParams:params syncRequest:NO alertUserOnFailure:NO block:^(id obj) {
block(obj);
}];
}
+(void)processURLRequestWithURL:(NSString *)url
andParams:(NSDictionary *)params
syncRequest:(BOOL)syncRequest
block:(void (^)(id obj))block {
[self processURLRequestWithURL:url andParams:params syncRequest:syncRequest alertUserOnFailure:NO block:^(id obj) {
block(obj);
}];
}
+(void)processURLRequestWithURL:(NSString *)url
andParams:(NSDictionary *)params
syncRequest:(BOOL)syncRequest
alertUserOnFailure:(BOOL)alertUserOnFailure
block:(void (^)(id obj))block {
// Default url goes here, pass in a nil to use it
if (url == nil) {
url = #"https://MyURLToWebService";
}
// Add in our API Key
NSMutableDictionary *newParams = [[NSMutableDictionary alloc] initWithDictionary:params];
[newParams setValue:APIKey forKey:#"APIKey"];
NSURL *requestURL;
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:requestURL];
NSMutableURLRequest *theRequest = [httpClient requestWithMethod:#"POST" path:url parameters:newParams];
__block NSString *responseString = #"";
AFHTTPRequestOperation *_operation = [[AFHTTPRequestOperation alloc] initWithRequest:theRequest];
__weak AFHTTPRequestOperation *operation = _operation;
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
responseString = [operation responseString];
id retObj = [responseString JSONValue];
// Check for invalid response (No Access)
if ([retObj isKindOfClass:[NSDictionary class]]) {
if ([[(NSDictionary *)retObj valueForKey:#"Message"] isEqualToString:#"No Access"]) {
block(nil);
[self handleNoAccessWithReason:[(NSDictionary *)retObj valueForKey:#"Reason"]];
}
} else if ([retObj isKindOfClass:[NSArray class]]) {
if ([(NSArray *)retObj count] > 0) {
NSDictionary *dict = [(NSArray *)retObj objectAtIndex:0];
if ([[dict valueForKey:#"Message"] isEqualToString:#"No Access"]) {
block(nil);
[self handleNoAccessWithReason:[(NSDictionary *)retObj valueForKey:#"Reason"]];
}
}
}
block(retObj);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Failed with error = %#", [NSString stringWithFormat:#"[Error]:%#",error]);
block(nil);
if (alertUserOnFailure) {
// Let the user know something went wrong
[self handleNetworkErrorWithError:operation.error];
}
}];
[operation start];
if (syncRequest) {
// Process the request syncronously
[operation waitUntilFinished];
}
}
+(void)handleNetworkErrorWithError:(NSError *)error {
NSString *errorString = [NSString stringWithFormat:#"[Error]:%#",error];
// Standard UIAlert Syntax
UIAlertView *myAlert = [[UIAlertView alloc]
initWithTitle:#"Connection Error"
message:errorString
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil, nil];
[myAlert show];
}
+(void)handleNoAccessWithReason:(NSString *)reason {
// Standard UIAlert Syntax
UIAlertView *myAlert = [[UIAlertView alloc]
initWithTitle:#"No Access"
message:reason
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil, nil];
[myAlert show];
}
#end
And here is how I call it:
NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:
#"GetApplications", #"Command",
userInfo.networkID, #"NetworkID",
nil];
[NetworkClient processURLRequestWithURL:nil andParams:params block:^(id obj) {
[MBProgressHUD hideHUDForView:self.view animated:YES];
if ([obj isKindOfClass:[NSArray class]]) {
myTableViewData = (NSArray *)obj;
[self.myTableView reloadData];
}
}];
So my web-service can send back both a Dictionary structured JSON response and an Array formatted JSON response. The NetworkClient method will take both and send back what it gets (I leave it up to the calling code to ensure it gets back what is expected). I use the APIKey as additional security to ensure only my application can access web-service resources (the first thing I check before sending back data is that the APIKey matches that I have for that application in the DB).
Is this an efficient way to do this kind of thing? Any ways to make it better?
I don't understand why you use processURLRequestWithURL:nil since this is made to deal with a specific service. It is also confusing, it only tells me that there is some magic elsewhere, which is the same as if it is not there at all. I would use a singleton:
extern NSString * const kBaseURL;
#interface NetworkClient : AFHTTPClient
+ (NetworkClient *) sharedClient;
#end
NSString* const kNodeApiURL = BASE_URL;
#implementation NetworkClient
+ (NetworkClient*) sharedClient
{
static NetworkClient *_sharedClient = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_sharedClient = [[NetworkClient alloc] initWithBaseURL:[NSURL URLWithString:kBaseURL]];
});
return _sharedClient;
}
- (id)initWithBaseURL:(NSURL*)url
{
if (self = [super initWithBaseURL:url]) {
[self registerHTTPOperationClass:[AFJSONRequestOperation class]];
[self setDefaultHeader:#"Accept" value:#"application/json"];
}
return self;
}
-(id) init {
error(#"Use initWithBaseURL: instead.");
[super doesNotRecognizeSelector:_cmd];
return nil;
}
#end
and then on the PCH
#define BASE_URL #"https://MyURLToWebService"
You are also mixing the GUI with the server API when you add a parameter to show a popup. I don't think the server API should block the thread ever. Write purely asynchronous code and let the caller block the GUI from his own end.
Same with the handleNoAccessWithReason. The API doesn't handle anything, it sucks an input and produces an output. Every piece of code you write should do one (1) thing. It's going to be a lot easier to test, understand, and reuse.
I don't know why you qualified the operation with __weak.
Those parameters you pass, it's going to be a lot easier to understand if you use domain objects like User and Command or whatever. Well, "Command" stinks. Is there really a method with a meaningful name behind your usage code? Because when I debug code where I have to print the parameters to tell what's going on I nerd enrage. If you are writing a server API (and by default you should if you want clean code), you should expose meaningful names.
I would write the code differently, example, I want a cow from the server for a given user:
typedef void (^AFJSONSuccess)(NSURLRequest *request, NSHTTPURLResponse *response, id JSON);
typedef void (^AFJSONFailure)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON);
+(void) cowForUser:(User*)user callback:(void(^)(Cow *cow, NSError *error))callback {
AFJSONSuccess success = ^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
// turn JSON into a cow
callback(cow,nil);
};
AFJSONFailure failure = ^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
// create a custom NSError
callback(nil,error);
};
NetworkClient *client = [NetworkClient sharedClient];
NSMutableURLRequest *request = [client requestWithMethod:#"GET" path:kCowPath parameters:jsonDic];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:sucess failure:failure];
[client enqueueHTTPRequestOperation:operation];
}
Now in usage start the hud, and in the callback block call stop hud and check if the cow is nil. I don't think the hud should block the screen (as you do waiting until the op is done), what if the user decides to move to another screen or cancel the query?
I'm voting to close this question because it belongs in code review.

Facebook sdk post on wall on iPhone app

I have a problem with implementing Facebook posting on wall in my iPhone application.
I installed SDK and linked framework
login is working fine. here's the code:
-(IBAction)loginButtonPressed:(id)sender
{
NSLog(#"loginButtonPressed: called");
AppDelegate *appdel=[[UIApplication sharedApplication] delegate];
appdel.facebookSession=[[FBSession alloc] init];
[appdel.facebookSession openWithCompletionHandler:^(FBSession *session,
FBSessionState status,
NSError *error)
{
//
}];
}
But I have a problem with posting message on user's wall. Here's the code:
-(IBAction)likeButtonPressed:(id)sender
{
NSLog(#"likeButtonPressed: called");
// Post a status update to the user's feedm via the Graph API, and display an alert view
// with the results or an error.
NSString *message = #"test message";
NSDictionary *params = [NSDictionary dictionaryWithObject:message forKey:#"message"];
// use the "startWith" helper static on FBRequest to both create and start a request, with
// a specified completion handler.
[FBRequest startWithGraphPath:#"me/feed"
parameters:params
HTTPMethod:#"POST"
completionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
[self showAlert:message result:result error:error];
}];
}
Help me please. What's wrong with my code? Or should I add some permissions to login request?
this code worked for me.
First we must
#import <FBiOSSDK/FacebookSDK.h>
then
#property (strong, nonatomic) FBRequestConnection *requestConnection;
and of course do not forget to synthesize:
#synthesize requestConnection;
the code itself:
-(IBAction)likeButtonPressed:(id)sender
{
NSLog(#"likeButtonPressed: called");
// FBSample logic
// Check to see whether we have already opened a session.
if (FBSession.activeSession.isOpen)
{
// login is integrated with the send button -- so if open, we send
[self postOnWall];
}
else
{
[FBSession sessionOpenWithPermissions:[NSArray arrayWithObjects:#"publish_stream", nil]
completionHandler:
^(FBSession *session,
FBSessionState status,
NSError *error)
{
// if login fails for any reason, we alert
if (error)
{
NSLog(#" login failed");
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error"
message:error.localizedDescription
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
// if otherwise we check to see if the session is open, an alternative to
// to the FB_ISSESSIONOPENWITHSTATE helper-macro would be to check the isOpen
// property of the session object; the macros are useful, however, for more
// detailed state checking for FBSession objects
}
else if (FB_ISSESSIONOPENWITHSTATE(status))
{
NSLog(#" sending post on wall request...");
// send our requests if we successfully logged in
[self postOnWall];
}
}];
};
}
- (void)postOnWall
{
NSNumber *testMessageIndex=[[NSNumber alloc] init];
if ([[NSUserDefaults standardUserDefaults] objectForKey:#"testMessageIndex"]==nil)
{
testMessageIndex=[NSNumber numberWithInt:100];
}
else
{
testMessageIndex=[[NSUserDefaults standardUserDefaults] objectForKey:#"testMessageIndex"];
};
testMessageIndex=[NSNumber numberWithInt:[testMessageIndex intValue]+1];
[[NSUserDefaults standardUserDefaults] setObject:testMessageIndex forKey:#"testMessageIndex"];
[[NSUserDefaults standardUserDefaults] synchronize];
// create the connection object
FBRequestConnection *newConnection = [[FBRequestConnection alloc] init];
// create a handler block to handle the results of the request for fbid's profile
FBRequestHandler handler =
^(FBRequestConnection *connection, id result, NSError *error) {
// output the results of the request
[self requestCompleted:connection forFbID:#"me" result:result error:error];
};
// create the request object, using the fbid as the graph path
// as an alternative the request* static methods of the FBRequest class could
// be used to fetch common requests, such as /me and /me/friends
NSString *messageString=[NSString stringWithFormat:#"wk test message %i", [testMessageIndex intValue]];
FBRequest *request=[[FBRequest alloc] initWithSession:FBSession.activeSession graphPath:#"me/feed" parameters:[NSDictionary dictionaryWithObject:messageString forKey:#"message"] HTTPMethod:#"POST"];
// add the request to the connection object, if more than one request is added
// the connection object will compose the requests as a batch request; whether or
// not the request is a batch or a singleton, the handler behavior is the same,
// allowing the application to be dynamic in regards to whether a single or multiple
// requests are occuring
[newConnection addRequest:request completionHandler:handler];
// if there's an outstanding connection, just cancel
[self.requestConnection cancel];
// keep track of our connection, and start it
self.requestConnection = newConnection;
[newConnection start];
}
// FBSample logic
// Report any results. Invoked once for each request we make.
- (void)requestCompleted:(FBRequestConnection *)connection
forFbID:fbID
result:(id)result
error:(NSError *)error
{
NSLog(#"request completed");
// not the completion we were looking for...
if (self.requestConnection &&
connection != self.requestConnection)
{
NSLog(#" not the completion we are looking for");
return;
}
// clean this up, for posterity
self.requestConnection = nil;
if (error)
{
NSLog(#" error");
UIAlertView *alert=[[UIAlertView alloc] initWithTitle:#"error" message:error.localizedDescription delegate:nil cancelButtonTitle:#"OK" otherButtonTitles: nil];
// error contains details about why the request failed
[alert show];
}
else
{
NSLog(#" ok");
};
}
try this code
NSHTTPCookieStorage* cookies = [NSHTTPCookieStorage sharedHTTPCookieStorage];
NSArray* facebookCookies = [cookies cookiesForURL:
[NSURL URLWithString:#"http://login.facebook.com"]];
for (NSHTTPCookie* cookie in facebookCookies) {
[cookies deleteCookie:cookie];
}
NSString *FBBody = [NSString stringWithFormat:#"your message you want to post"];
UIImage *img=[UIImage imageNamed:[NSString stringWithFormat:image naemif you want to post]];
FBFeedPost *post = [[FBFeedPost alloc] initWithPhoto:img name:FBBody];
[post publishPostWithDelegate:self];
[[UIAppDelegate indicator] startAnimating];
IFNNotificationDisplay *display = [[IFNNotificationDisplay alloc] init];
display.type = NotificationDisplayTypeLoading;
display.tag = NOTIFICATION_DISPLAY_TAG;
you should set Permissions:"status_update".
like this :
FBLoginView *loginview = [[FBLoginView alloc] initWithPermissions:[NSArray arrayWithObject:#"status_update"]];
or
FBSession *fbSession = [[FBSession alloc] initWithPermissions:[NSArray arrayWithObject:#"status_update"]];