IOS SocketIO chat app issues, Node JS as backend - ios

Friends
i am working on a chat application where there a function in backend like
client.on('mjmChatAddUser', function(user, room)
{
// Guest
if(user == null)
user = mjmChatCreateGuestName();
// Convert special characters to HTML entities
user = htmlEntities(user);
room = htmlEntities(room);
client.username = user;
client.room = room;
mjmChatUsernames.push(user);
client.join(room);
client.emit('mjmChatStatusUser', 'you have joined to '+ room +' room');
client.broadcast.to(room).emit('mjmChatStatusUser', user +' has joined to this room');
client.emit('mjmChatRooms', room);
io.sockets.to(room).emit('mjmChatUsers', mjmChatGetUsersRoom(room));
});
Now from ios side , I want to use ScoketIO to call this function , I have made connection to server but not enable to call this function , this what i am doing , is it right way , please guide me
- (void) viewDidLoad
{
[super viewDidLoad];
// create socket.io client instance
socketIO = [[SocketIO alloc] initWithDelegate:self];
// you can update the resource name of the handshake URL
// see https://github.com/pkyeck/socket.IO-objc/pull/80
// [socketIO setResourceName:#"whatever"];
// if you want to use https instead of http
// socketIO.useSecure = YES;
// pass cookie(s) to handshake endpoint (e.g. for auth)
NSDictionary *properties = [NSDictionary dictionaryWithObjectsAndKeys:
#"localhost", NSHTTPCookieDomain,
#"/", NSHTTPCookiePath,
#"auth", NSHTTPCookieName,
#"56cdea636acdf132", NSHTTPCookieValue,
nil];
NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:properties];
NSArray *cookies = [NSArray arrayWithObjects:cookie, nil];
socketIO.cookies = cookies;
// connect to the socket.io server that is running locally at port 3000
[socketIO connectToHost:#"MY SERVER" onPort:3000];
}
# pragma mark -
# pragma mark socket.IO-objc delegate methods
- (void) socketIODidConnect:(SocketIO *)socket
{
NSLog(#"socket.io connected.");
NSMutableDictionary *dict2 = [NSMutableDictionary dictionary];
[dict2 setObject:#"demo1" forKey:#"user"];
[dict2 setObject:#"php" forKey:#"room"];
[socketIO sendEvent:#"mjmChatAddUser" withData:#{#"Abc":#"php"}];
}
- (void) socketIO:(SocketIO *)socket didReceiveEvent:(SocketIOPacket *)packet
{
NSLog(#"didReceiveEvent()");
// test acknowledge
SocketIOCallback cb = ^(id argsData) {
NSDictionary *response = argsData;
// do something with response
NSLog(#"ack arrived: %#", response);
// test forced disconnect
[socketIO disconnectForced];
};
[socketIO sendMessage:#"hello back!" withAcknowledge:cb];
}
- (void) socketIO:(SocketIO *)socket onError:(NSError *)error
{
if ([error code] == SocketIOUnauthorized) {
NSLog(#"not authorized");
} else {
NSLog(#"onError() %#", error);
}
}
- (void) socketIODidDisconnect:(SocketIO *)socket disconnectedWithError:(NSError *)error
{
NSLog(#"socket.io disconnected. did error occur? %#", error);
}

Related

NSNetService doesn't contain any addresses

I'm hosting a service in a Mac application and connecting with an iOS app. While the iOS app will find the service, the service doesn't contain any addresses, so I can't connect a socket.
This is my hosting code on the Mac:
- (void)start {
queue = dispatch_queue_create("KeyboardServer", DISPATCH_QUEUE_CONCURRENT);
socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:queue];
NSError *error = nil;
if ([socket acceptOnPort:0 error:&error]) {
service = [[NSNetService alloc] initWithDomain:#"local." type:#"_probonjore._tcp." name:#"TestServer" port:[socket localPort]];
service.delegate = self;
[service publish];
} else {
NSLog(#"Unable to create server");
}
}
This is the connecting code on iOS:
- (BOOL)connectToServer:(NSNetService *)service {
NSArray *addresses = service.addresses;
socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:queue];
for (NSData *address in addresses) {
NSError *error;
if ([socket connectToAddress:address error:&error]) {
NSLog(#"Socket connected!");
return true;
}
}
return false;
}
The problem is, service.addresses is always empty and the loop instantly exits.
For anyone curious, I searched around and found a solution.
In the
- (void)netServiceBrowser:(NSNetServiceBrowser *)browser didFindService:(NSNetService *)service moreComing:(BOOL)moreComing
function, you need to:
Add the service to an array to stop the object being deallocated as soon as it goes out of scope
Set the delegate on the object so that you can respond to its address resolution
Call the function to make it resolve
Which looks like this:
- (void)netServiceBrowser:(NSNetServiceBrowser *)browser didFindService:(NSNetService *)service moreComing:(BOOL)moreComing {
NSLog(#"Found Service %#", [service name]);
[services addObject:service];
[service setDelegate:self];
[service resolveWithTimeout:5.0f];
}
You then want to implement
- (void)netService:(NSNetService *)sender didNotResolve:(NSDictionary *)errorDict
and
- (void)netServiceDidResolveAddress:(NSNetService *)service
To catch when the address either resolves or doesn't resolve.

gmail api full email access given the message id of email

I am trying to access the gmail messages in offline access mode. gmail access token I get from the server end.
I followed this link to here
I created my own authenticator class and subclass from GTMOAuth2Authentication and implemented the protocol as mentioned in the above link.
The canAutherize always fail and even though I make gmail query, It crashes in authorize function. Any help would be appreciated.
- (void)viewDidLoad {
[super viewDidLoad];
if ([self.subjectInfo length] > 0) {
[self.subjectLabel setText:self.subjectInfo];
}else {
[self.subjectLabel setText:#""];
}
self.service = [[GTLServiceGmail alloc] init];
[self fetchAccessToken];
// Initialize the Gmail API service & load existing credentials from the keychain if available.
}
// When the view appears, ensure that the Gmail API service is authorized, and perform API calls.
- (void)viewDidAppear:(BOOL)animated {
if (!self.service.authorizer.canAuthorize) {
// Not yet authorized, request authorization by pushing the login UI onto the UI stack.
// [self presentViewController:[self createAuthController] animated:YES completion:nil];
[self fetchAccessToken];
} else {
[self fetchMail:[self gmailMsgId]];
}
}
-(void) fetchAccessToken
{
[[APIManager sharedManager] fetchGmailToken:^(NSDictionary *resultDict) {
if (resultDict != nil) {
self.accessToken = [resultDict objectForKey:#"access_token"];
_authInst = [[GmailAuthenticator alloc] initWithAccessToken:self.accessToken];
self.service.authorizer = _authInst;
}
} failure:^(NSError *error) {
NSLog(#"fail to fetch access token");
}];
}
- (void)fetchMail:(NSString*)messageId {
GTLQueryGmail *query = [GTLQueryGmail queryForUsersMessagesGet];
query.messageId = messageId;
[self.service executeQuery:query
delegate:self
didFinishSelector:#selector(displayResultWithTicket:finishedWithObject:error:)];
}
- (void)displayResultWithTicket:(GTLServiceTicket *)ticket
finishedWithObject:(GTLGmailMessage *)messageResponse
error:(NSError *)error {
if (error == nil) {
NSLog(#"description is %#", [messageResponse description]);
} else {
NSLog(#"error : %#", [error description]);
}
}

Disconnecting with server immediately after connecting

I have written a Singleton Class using GCDAsyncsocket Library to establish connection with any other device having same service using Bonjour.
On one device I am using its Method "startPublishing" to make it a Host(Server), from the Application on another Device(Client) I am calling "StartBrowsing" to find out the available Devices in Network. When user selects any of service in that Network I am calling method "initConnectionWithService", that initiate Connection flow by resolving address of NetService to connect.
BonjourUtilClass.h
#interface BonjourUtilClass : NSObject<GCDAsyncSocketDelegate,NSNetServiceDelegate,NSNetServiceBrowserDelegate>{
NSNetService *netServiceToPublish;
GCDAsyncSocket *socketPub;
NSNetServiceBrowser *netServiceToBrowse;
GCDAsyncSocket *socketSub;
NSMutableArray *mutArrServices;
GCDAsyncSocket *socketConnected;
}
+(id)sharedInstance;
-(void)startPublishing;
-(void)startBrowsing;
-(void)initConnectionWithService:(NSNetService*)netServiceToConnect;
-(void)disconnectWithCurrent;
#end
BonjourUtilClass.m
static BonjourUtilClass *sharedObject = nil;
#implementation BonjourUtilClass
+(id)sharedInstance{
if(!sharedObject){
sharedObject = [[BonjourUtilClass alloc]init];
}
return sharedObject;
}
#pragma mark - Browsing
-(void)startBrowsing{
if(mutArrServices){
[mutArrServices removeAllObjects];
}else{
mutArrServices = [NSMutableArray array];
}
netServiceToBrowse = [[NSNetServiceBrowser alloc]init];
netServiceToBrowse.delegate= self;
[netServiceToBrowse searchForServicesOfType:#"_mrug._tcp" inDomain:#"local."];
}
-(void)stopBrowsing{
}
-(void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didFindService:(NSNetService *)aNetService moreComing:(BOOL)moreComing{
[mutArrServices addObject:aNetService];
if(!moreComing) {
// Sort Services
[mutArrServices sortUsingDescriptors:#[[NSSortDescriptor sortDescriptorWithKey:#"name" ascending:YES]]];
// Update Table View
[[NSNotificationCenter defaultCenter]postNotificationName:kNotifyReloadList object:mutArrServices];
}
}
-(void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didRemoveService:(NSNetService *)aNetService moreComing:(BOOL)moreComing{
[mutArrServices removeObject:aNetService];
if(!moreComing) {
// Sort Services
[mutArrServices sortUsingDescriptors:#[[NSSortDescriptor sortDescriptorWithKey:#"name" ascending:YES]]];
// Update Table View
[[NSNotificationCenter defaultCenter]postNotificationName:kNotifyReloadList object:mutArrServices];
}
}
-(void)netServiceBrowserDidStopSearch:(NSNetServiceBrowser *)aNetServiceBrowser{
NSLog(#"Search browser Did STOP search..");
[self stopBrowsing];
}
-(void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didNotSearch:(NSDictionary *)errorDict{
NSLog(#"Search browser Did not search..");
[self stopBrowsing];
}
#pragma mark - NetService Delegate
-(void)startPublishing{
socketPub = [[GCDAsyncSocket alloc]initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
NSError *aError;
if([socketPub acceptOnPort:0 error:&aError]){
netServiceToPublish = [[NSNetService alloc]initWithDomain:#"local." type:#"_mrug._tcp" name:#"" port:socketPub.localPort];
netServiceToPublish.delegate =self;
[netServiceToPublish publish];
}else{
NSLog(#"Unable To Create Socket..");
}
}
//NetService Delegates
-(void)netService:(NSNetService *)sender didNotPublish:(NSDictionary *)errorDict{
NSLog(#"Failed To Publish : Domain=%# type=%# name=%# info=%#",sender.domain,sender.type,sender.name,errorDict);
}
-(void)netServiceDidPublish:(NSNetService *)sender{
NSLog(#"Service Published : Domain=%# type=%# name=%# port=%li",sender.domain,sender.type,sender.name,(long)sender.port);
}
//Resolving Address
- (void)netService:(NSNetService *)service didNotResolve:(NSDictionary *)errorDict {
[service setDelegate:nil];
}
- (void)netServiceDidResolveAddress:(NSNetService *)service {
// Connect With Service
if ([self connectWithService:service]){
NSLog(#"Did Connect with Service: domain(%#) type(%#) name(%#) port(%i)", [service domain], [service type], [service name], (int)[service port]);
} else {
NSLog(#"Unable to Connect with Service: domain(%#) type(%#) name(%#) port(%i)", [service domain], [service type], [service name], (int)[service port]);
}
}
#pragma mark - GCDSocket delegates
-(void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket{
NSLog(#"Accepted new Socket: HOST : %# , CONNECTION PORT :%li",newSocket.connectedHost,(long)newSocket.connectedPort);
}
-(void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err{
NSLog(#"Socket DisConnected %s,%#,%#",__PRETTY_FUNCTION__, sock,err);
if(socketPub == sock){
socketPub.delegate = nil;
socketPub = nil;
}else if (socketConnected == sock){
socketConnected.delegate=nil;
socketConnected = nil;
}
}
- (void)socket:(GCDAsyncSocket *)socket didConnectToHost:(NSString *)host port:(UInt16)port {
NSLog(#"Socket Did Connect to Host: %# Port: %hu", host, port);
// Start Reading
[socket readDataToLength:sizeof(uint64_t) withTimeout:-1.0 tag:0];
}
#pragma mark - Connection Methods
-(void)disconnectWithCurrent{
if(socketConnected){
[socketConnected disconnect];
socketConnected.delegate = nil;
socketConnected = nil;
}
}
-(void)initConnectionWithService:(NSNetService*)netServiceToConnect{
// Resolve Service
[netServiceToConnect setDelegate:self];
[netServiceToConnect resolveWithTimeout:30.0];
}
- (BOOL)connectWithService:(NSNetService *)service {
BOOL _isConnected = NO;
// Copy Service Addresses
NSArray *addresses = [[service addresses] mutableCopy];
if (!socketConnected || ![socketConnected isConnected]) {
// Initialize Socket
socketConnected = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
// Connect
while (!_isConnected && [addresses count]) {
NSData *address = [addresses objectAtIndex:0];
NSError *error = nil;
if ([socketConnected connectToAddress:address error:&error]) {
_isConnected = YES;
} else if (error) {
NSLog(#"Unable to connect to address. Error %# with user info %#.", error, [error userInfo]);
}
}
} else {
_isConnected = [socketConnected isConnected];
}
return _isConnected;
}
#end
But, On execution of above things very unexpected things happending, Device which is acting as Client is getting callback in didConnectedToHost and immediatly, another Callback is coming that is in didDisconnected
Logs on Client Device
2014-12-11 15:16:32.512 GCDSocketDemo[1419:71238] Did Connect with Service: domain(local.) type(_mrug._tcp.) name(ind506Bonjour) port(52026)
2014-12-11 15:16:32.659 GCDSocketDemo[1419:71238] Socket Did Connect to Host: 10.2.4.130 Port: 52026
2014-12-11 15:16:32.660 GCDSocketDemo[1419:71238] -[AppDelegate socketDidDisconnect:withError:],<GCDAsyncSocket: 0x7fa0a3533b90>,Error Domain=GCDAsyncSocketErrorDomain Code=7 "Socket closed by remote peer" UserInfo=0x7fa0a3532f70 {NSLocalizedDescription=Socket closed by remote peer}
Logs On Server Device
2014-12-11 15:15:48.546 GCDSockrtMacDemo[1397:70851] Service Published : Domain=local. type=_mrug._tcp. name=ind506Bonjour port=52026
2014-12-11 15:16:32.585 GCDSockrtMacDemo[1397:70851] Accepted new Socket: HOST : 10.2.4.130 , CONNECTION PORT :52029
2014-12-11 15:16:32.613 GCDSockrtMacDemo[1397:70851] -[BonjourUtilClass socketDidDisconnect:withError:],(null),(null)
Comment of Paulw11 Helped me to find out the Solution. Actually I stored Socket on client side, but forgot to Store reference of new Socket getting in callback method "didAcceptNewSocket".
So the Method didAcceptNewSocket should be as below:
-(void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket{
NSLog(#"Accepted new Socket: HOST : %# , CONNECTION PORT :%li",newSocket.connectedHost,(long)newSocket.connectedPort);
socketConnected = newSocket;
}
So that newSocket received in this method can be persist for further communication. In earlier case it was releasing at end of method.

How to retrieve Facebook response using Facebook iOS SDK

I am using the Facebook iOS SDK for iPhone. I initialize the Facebook instance
facebook = [[Facebook alloc] initWithAppId:kAppId];
And then I do login:
[facebook authorize:permissions delegate:self];
After I logged in to Facebook I am doing the following to get the user profile information:
[facebook requestWithGraphPath:#"me" andDelegate:self];
NSMutableData *response = [fbRequest responseText];
unsigned char *firstBuffer = [response mutableBytes];
NSLog(#"Got Facebook Profile: : \"%s\"\n", (char *)firstBuffer);
But I get the following on my console:
Got Facebook Profile: "(null)"
What am I doing wrong, also I believe that Facebook response is a json string and I am looking to get a hold of that json string.
I thought may be I should make it a wiki and tell the people how I am doing it. because lot of people are facing similar problem.
The first thing that I did was.
In Facebook.m class I added the following statement in the following method
(void)authorizeWithFBAppAuth:(BOOL)tryFBAppAuth
safariAuth:(BOOL)trySafariAuth
trySafariAuth = NO;
This prevents a safari page to get open for the facebook login, but it pops up a screen in app itself. Then i created a helper class for Facebook, the header file code is here.
#import <UIKit/UIKit.h>
#import "FBConnect.h"
#interface FaceBookHelper : UIViewController
<FBRequestDelegate,
FBDialogDelegate,
FBSessionDelegate>{
Facebook *facebook;
NSArray *permissions;
}
#property(readonly) Facebook *facebook;
- (void)login;
-(void)getUserInfo:(id)sender;
- (void)getUserFriendList:(id)sender;
-(void)postToFriendsWall;
The .m file.
static NSString* kAppId = #"xxx";
#define ACCESS_TOKEN_KEY #"fb_access_token"
#define EXPIRATION_DATE_KEY #"fb_expiration_date"
#implementation FaceBookHelper
#synthesize facebook;
//////////////////////////////////////////////////////////////////////////////////////////////////
// UIViewController
/**
* initialization
*/
- (id)init {
if (self = [super init]) {
facebook = [[Facebook alloc] initWithAppId:kAppId];
facebook.sessionDelegate = self;
permissions = [[NSArray arrayWithObjects:
#"email", #"read_stream", #"user_birthday",
#"user_about_me", #"publish_stream", #"offline_access", nil] retain];
[self login];
}
return self;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// NSObject
- (void)dealloc {
[facebook release];
[permissions release];
[super dealloc];
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// private
/**
* Login.
*/
- (void)login {
// only authorize if the access token isn't valid
// if it *is* valid, no need to authenticate. just move on
if (![facebook isSessionValid]) {
[facebook authorize:permissions delegate:self];
}
}
/**
* This is the place only where you will get the hold on the accessToken
*
**/
- (void)fbDidLogin {
NSLog(#"Did Log In");
NSLog(#"Access Token is %#", facebook.accessToken );
NSLog(#"Expiration Date is %#", facebook.expirationDate );
// Store the value in the NSUserDefaults
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:facebook.accessToken forKey:ACCESS_TOKEN_KEY];
[defaults setObject:facebook.expirationDate forKey:EXPIRATION_DATE_KEY];
[defaults synchronize];
// This is the best place to login because here we know that user has already logged in
[self getUserInfo:self];
//[self getUserFriendList:self];
//[self postToFriendsWall];
}
- (void)fbDidNotLogin:(BOOL)cancelled {
NSLog(#"Failed to log in");
}
- (void)getUserInfo:(id)sender {
[facebook requestWithGraphPath:#"me" andDelegate:self];
}
- (void)getUserFriendList:(id)sender {
[facebook requestWithGraphPath:#"me/friends" andDelegate:self];
}
////////////////////////////////////////////////////////////////////////////////
// FBRequestDelegate
/**
* Called when the Facebook API request has returned a response. This callback
* gives you access to the raw response. It's called before
* (void)request:(FBRequest *)request didLoad:(id)result,
* which is passed the parsed response object.
*/
- (void)request:(FBRequest *)request didReceiveResponse:(NSURLResponse *)response {
NSLog(#"Inside didReceiveResponse: received response");
//NSLog(#"Status Code #", [response statusCode]);
NSLog(#"URL #", [response URL]);
}
/**
* Called when a request returns and its response has been parsed into
* an object. The resulting object may be a dictionary, an array, a string,
* or a number, depending on the format of the API response. If you need access
* to the raw response, use:
*
* (void)request:(FBRequest *)request
* didReceiveResponse:(NSURLResponse *)response
*/
- (void)request:(FBRequest *)request didLoad:(id)result {
NSLog(#"Inside didLoad");
if ([result isKindOfClass:[NSArray class]]) {
result = [result objectAtIndex:0];
}
// When we ask for user infor this will happen.
if ([result isKindOfClass:[NSDictionary class]]){
//NSDictionary *hash = result;
NSLog(#"Birthday: %#", [result objectForKey:#"birthday"]);
NSLog(#"Name: %#", [result objectForKey:#"name"]);
}
if ([result isKindOfClass:[NSData class]])
{
NSLog(#"Profile Picture");
//[profilePicture release];
//profilePicture = [[UIImage alloc] initWithData: result];
}
NSLog(#"request returns %#",result);
//if ([result objectForKey:#"owner"]) {}
};
/**
* Called when an error prevents the Facebook API request from completing
* successfully.
*/
- (void)request:(FBRequest *)request didFailWithError:(NSError *)error {
//[self.label setText:[error localizedDescription]];
};
////////////////////////////////////////////////////////////////////////////////
// FBDialogDelegate
/**
* Called when a UIServer Dialog successfully return.
*/
- (void)dialogDidComplete:(FBDialog *)dialog {
//[self.label setText:#"publish successfully"];
}
#end
Thanks for this hint Yogesh!
In facebook.m you can also set the safariAuth param in the authorize method.
- (void)authorize:(NSArray *)permissions
delegate:(id<FBSessionDelegate>)delegate {
...
[self authorizeWithFBAppAuth:YES safariAuth:NO];
}

Facebook connect from iPhone app

I am trying to integrate Facebook connect to my iPhone app but I have an error (code 10000):
did fail: The operation couldn’t be completed. (facebookErrDomain error 10000.)
When I try to update my wall. The code seems pretty simple (I had to struggle to find some doc though).
- (void)viewDidLoad {
[super viewDidLoad];
// Permissions
NSArray *permissions = [[NSArray arrayWithObjects:#"publish_stream",#"read_stream",#"offline_access",nil] retain];
// Connection
Facebook *facebook = [[Facebook alloc] init];
[facebook authorize:#"MY_APP_ID" permissions:permissions delegate:self];
// Update my wall
NSMutableDictionary * params = [NSMutableDictionary dictionaryWithObjectsAndKeys:#"MY_API_KEY", #"api_key", #"test", #"message", nil];
[facebook requestWithGraphPath:#"me/home" andParams:params andHttpMethod:#"POST" andDelegate:self];
}
// FBRequestDelegate
- (void)request:(FBRequest*)request didLoad:(id)result {
NSArray* users = result;
NSDictionary* user = [users objectAtIndex:0];
NSString* name = [user objectForKey:#"name"];
NSLog(#"Query returned %#", name);
}
- (void)request:(FBRequest*)request didFailWithError:(NSError*)error {
NSLog(#"did fail: %#", [error localizedDescription]);
}
- (void)request:(FBRequest*)request didReceiveResponse:(NSURLResponse*)response {
NSLog(#"did r response");
}
Cannot really figure out what is wrong.
Thanks a lot,
Luc
I think I figured it out, I used to have the same issue. Your issue should be solved if you authenticate first with the right permissions and make sure you actually get to accept the needed permissions (publish_stream). Make sure you actually get to press the "allow" button. In your current code you won't see it, because you immediately try to post a message after authenticating, yet authentication isn't yet completed. As a result you most likely don't have a valid accessToken, preventing you to post messages to the wall.
// you perform authorization, but you don't wait for the user to accept the publish permission
[facebook authorize:#"MY_APP_ID" permissions:permissions delegate:self];
// you attempt to publish, but you don't have the permission to publish yet ...
NSMutableDictionary * params = [NSMutableDictionary dictionaryWithObjectsAndKeys:#"MY_API_KEY", #"api_key", #"test", #"message", nil];
[facebook requestWithGraphPath:#"me/home" andParams:params andHttpMethod:#"POST" andDelegate:self];
How to fix this issue?
This is the way I fixed it (please note DLog() is a macro for NSLog()):
/* The operationQueue array is used to keep track of operations that need to be
completed in order (e.g. if we aren't logged in when we want to post, first
log in, then post - this way we'll make sure we always have a valid
accessToken. */
- (id)initWithDelegate:(id <ServiceDelegate>)serviceDelegate
{
self = [super init];
if (self)
{
[self setDelegate:serviceDelegate];
userId = nil;
operationQueue = [[NSMutableArray alloc] init];
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
facebook = appDelegate.facebook;
}
return self;
}
- (id)init
{
return [self initWithDelegate:nil];
}
- (void)dealloc
{
[operationQueue release];
[super dealloc];
}
#pragma mark - Instance methods
- (void)login
{
if (![facebook isSessionValid]) {
SEL authorizationSelector = #selector(performAuthorization);
NSValue *selector = [NSValue valueWithPointer:authorizationSelector];
NSDictionary *dictionary = [NSDictionary dictionaryWithObject:selector forKey:#"selector"];
[operationQueue addObject:dictionary];
[self runOperations];
}
}
- (void)logout
{
SEL logoutSelector = #selector(performLogout);
NSValue *selector = [NSValue valueWithPointer:logoutSelector];
NSDictionary *dictionary = [NSDictionary dictionaryWithObject:selector forKey:#"selector"];
[operationQueue addObject:dictionary];
[self runOperations];
}
- (void)postMessage:(NSString *)message
{
NSArray *objects = [NSArray arrayWithObjects:message, nil];
NSArray *keys = [NSArray arrayWithObjects:#"message", nil];
NSMutableDictionary *parameters = [NSMutableDictionary dictionaryWithObjects:objects forKeys:keys];
NSDictionary *dictionary = [NSDictionary dictionaryWithObject:parameters forKey:#"parameters"];
SEL postMessageSelector = #selector(performPostMessageWithDictionary:);
NSValue *selector = [NSValue valueWithPointer:postMessageSelector];
NSDictionary *operationDictionary = [NSDictionary dictionaryWithObjectsAndKeys:selector, #"selector", dictionary, #"parameters", nil];
[operationQueue addObject:operationDictionary];
if (![facebook isSessionValid]) {
[self performSelectorOnMainThread:#selector(performAuthorization) withObject:nil waitUntilDone:NO];
} else {
[self runOperations];
}
}
#pragma mark - Private methods
- (void)runOperations
{
DLog(#"running operations ...");
for (NSDictionary *operationDictionary in operationQueue) {
NSValue *value = [operationDictionary objectForKey:#"selector"];
SEL selector = [value pointerValue];
NSDictionary *parameters = [operationDictionary objectForKey:#"parameters"];
[self performSelectorOnMainThread:selector withObject:parameters waitUntilDone:YES];
}
[operationQueue removeAllObjects];
}
- (void)performLogout {
[facebook logout:self];
}
- (void)performAuthorization {
NSArray *permissions = [NSArray arrayWithObject:#"publish_stream"];
[facebook authorize:permissions delegate:self];
}
- (void)performPostMessageWithDictionary:(NSDictionary *)dictionary {
NSMutableDictionary *parameters = [dictionary objectForKey:#"parameters"];
NSString *encodedToken = [facebook.accessToken stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *graphPath = [NSString stringWithFormat:#"me/feed?access_token=%#", encodedToken];
FBRequest *request = [facebook requestWithGraphPath:graphPath
andParams:parameters
andHttpMethod:#"POST"
andDelegate:self];
if (!request) {
DLog(#"error occured when trying to create FBRequest object with graph path : %#", graphPath);
}
}
/* make sure your interface conforms to the FBRequestDelegate protocol for
extra debug information, but this is not required */
#pragma mark - Facebook request delegate
- (void)requestLoading:(FBRequest *)request
{
DLog(#"requestLoading:");
}
- (void)request:(FBRequest *)request didReceiveResponse:(NSURLResponse *)response
{
DLog(#"request:didReceiveResponse:");
}
- (void)request:(FBRequest *)request didFailWithError:(NSError *)error
{
DLog(#"error occured when trying to perform request to Facebook : %#", error);
}
- (void)request:(FBRequest *)request didLoad:(id)result
{
DLog(#"request:didLoad: %#", result);
}
- (void)request:(FBRequest *)request didLoadRawResponse:(NSData *)data
{
DLog(#"request:didLoadRawResponse");
}
/* make sure your interface conforms to the FBSessionDelegate protocol! */
#pragma mark - Facebook session delegate
/* if there are still operations in the queue that need to be completed,
continue executing the operations, otherwise inform out delegate that login
is completed ... */
- (void)fbDidLogin
{
if ([operationQueue count] > 0) {
[self runOperations];
}
if ([self.delegate respondsToSelector:#selector(serviceDidLogin:)])
{
[self.delegate serviceDidLogin:self];
}
}
- (void)fbDidNotLogin:(BOOL)cancelled
{
if ([self.delegate respondsToSelector:#selector(serviceLoginFailed:)])
{
[self.delegate serviceLoginFailed:self];
}
}
- (void)fbDidLogout
{
if ([self.delegate respondsToSelector:#selector(serviceDidLogout:)])
{
[self.delegate serviceDidLogout:self];
}
}
Make sure you have declared your app's API key.

Resources