FBSession open a new session with Page Access Token - facebook-ios-sdk

I have successfully obtained a valid Page Access Token (PAT) using [FBRequest requestWithGraphPath:parameters:HTTPMethod]; ( double checked with Access Token Debugger ).
The PAT contains the following permissions of my Facebook Page , which I am the Admin :
create_note manage_pages photo_upload publish_actions publish_stream share_item status_update video_upload
though I only requested manage_pages and publish_stream ...
Now, I want to publish story on behalf of the page ( not "post by others" ). I use this code:
NSMutableDictionary *params = [NSMutableDictionary dictionaryWithObjectsAndKeys:
#"http://www.google.com", #"link",
#"Test Name", #"name",
#"Test Message", #"message",
page_access_token, #"access_token",
nil];
FBRequest *req = [FBRequest requestWithGraphPath:#"{MY_PAGE_ID}/feed" parameters:params HTTPMethod:#"POST"];
[req startWithCompletionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"Result: %#", result);
});
}];
I am able to issue the post , but the post is issued as others, not the page admin. Therefore, I am thinking of creating a new FBSession with the PAT. Am I going to correct direction ? or did I miss something ?

Related

How to retrieve spotify playlist in iphone application

I have downloaded IOS Cocoa library of Spotify, which have sample project for playing songs in spotify.
I need to fetch the playlist of a Spotify particular user in an iPhone application??
You can try this -
[SPAsyncLoading waitUntilLoaded:[SPSession sharedSession] timeout:kSPAsyncLoadingDefaultTimeout then:^(NSArray *loadedession, NSArray *notLoadedSession)
{
// The session is logged in and loaded — now wait for the userPlaylists to load.
[SPAsyncLoading waitUntilLoaded:[SPSession sharedSession].userPlaylists timeout:kSPAsyncLoadingDefaultTimeout then:^(NSArray *loadedContainers, NSArray *notLoadedContainers)
{
// User playlists are loaded — wait for playlists to load their metadata.
NSMutableArray *playlists = [NSMutableArray array];
[playlists addObject:[SPSession sharedSession].starredPlaylist];
[playlists addObject:[SPSession sharedSession].inboxPlaylist];
[playlists addObjectsFromArray:[SPSession sharedSession].userPlaylists.flattenedPlaylists];
[SPAsyncLoading waitUntilLoaded:playlists timeout:kSPAsyncLoadingDefaultTimeout then:^(NSArray *loadedPlaylists, NSArray *notLoadedPlaylists)
{
// All of our playlists have loaded their metadata — wait for all tracks to load their metadata.
arrPlaylist = [[NSMutableArray alloc] initWithArray:loadedPlaylists];
NSLog(#"arrPlaylist %#",arrPlaylist);
}];
}];
}];

Hard CoreData + iCloud scenario

i'm having a very hard issue to solve. I've got this scenario:
My app uses CoreData to storing objects, I want to implement iCloud sync between devices... and my app requires an initial populated database.
The first time I launch my app, it's going to populate my database on the cloud and marks to YES some db'fields as "databaseInstalled". These fields are synced in the cloud too.
Now when another device launch the app for the first time, I was hoping to retrieve the field "databaseInstalled" to check whether inject or not some data but it's wrong...
If databaseInstalled is false, we inject data, if databaseInstalled it's true, we wait for iCloud sync.
The problem is that I retrieve the persistentStoreCoordinator asynchronically because of I don't want to block the app that is waiting to download data from iCloud...
So how can I know a priori if i need to populate the database or it has been filled on another device and I've just to download from iCloud the populated one?
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if((__persistentStoreCoordinator != nil)) {
return __persistentStoreCoordinator;
}
__persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];
NSPersistentStoreCoordinator *psc = __persistentStoreCoordinator;
// Set up iCloud in another thread:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// ** Note: if you adapt this code for your own use, you MUST change this variable:
NSString *iCloudEnabledAppID = #"this is a secret!";
// ** Note: if you adapt this code for your own use, you should change this variable:
NSString *dataFileName = #"you do not have to know.sqlite";
// ** Note: For basic usage you shouldn't need to change anything else
NSString *iCloudDataDirectoryName = #"Data.nosync";
NSString *iCloudLogsDirectoryName = #"Logs";
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *localStore = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:dataFileName];
NSURL *iCloud = [fileManager URLForUbiquityContainerIdentifier:nil];
if (iCloud) {
NSLog(#"iCloud is working");
NSURL *iCloudLogsPath = [NSURL fileURLWithPath:[[iCloud path] stringByAppendingPathComponent:iCloudLogsDirectoryName]];
NSLog(#"iCloudEnabledAppID = %#",iCloudEnabledAppID);
NSLog(#"dataFileName = %#", dataFileName);
NSLog(#"iCloudDataDirectoryName = %#", iCloudDataDirectoryName);
NSLog(#"iCloudLogsDirectoryName = %#", iCloudLogsDirectoryName);
NSLog(#"iCloud = %#", iCloud);
NSLog(#"iCloudLogsPath = %#", iCloudLogsPath);
// da rimuovere
//[fileManager removeItemAtURL:iCloudLogsPath error:nil];
#warning to remove
if([fileManager fileExistsAtPath:[[iCloud path] stringByAppendingPathComponent:iCloudDataDirectoryName]] == NO) {
NSError *fileSystemError;
[fileManager createDirectoryAtPath:[[iCloud path] stringByAppendingPathComponent:iCloudDataDirectoryName]
withIntermediateDirectories:YES
attributes:nil
error:&fileSystemError];
if(fileSystemError != nil) {
NSLog(#"Error creating database directory %#", fileSystemError);
}
}
NSString *iCloudData = [[[iCloud path]
stringByAppendingPathComponent:iCloudDataDirectoryName]
stringByAppendingPathComponent:dataFileName];
//[fileManager removeItemAtPath:iCloudData error:nil];
#warning to remove
NSLog(#"iCloudData = %#", iCloudData);
NSMutableDictionary *options = [NSMutableDictionary dictionary];
[options setObject:[NSNumber numberWithBool:YES] forKey:NSMigratePersistentStoresAutomaticallyOption];
[options setObject:[NSNumber numberWithBool:YES] forKey:NSInferMappingModelAutomaticallyOption];
[options setObject:iCloudEnabledAppID forKey:NSPersistentStoreUbiquitousContentNameKey];
[options setObject:iCloudLogsPath forKey:NSPersistentStoreUbiquitousContentURLKey];
[psc lock];
[psc addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:[NSURL fileURLWithPath:iCloudData]
options:options
error:nil];
[psc unlock];
}
else {
NSLog(#"iCloud is NOT working - using a local store");
NSLog(#"Local store: %#", localStore.path);
NSMutableDictionary *options = [NSMutableDictionary dictionary];
[options setObject:[NSNumber numberWithBool:YES] forKey:NSMigratePersistentStoresAutomaticallyOption];
[options setObject:[NSNumber numberWithBool:YES] forKey:NSInferMappingModelAutomaticallyOption];
[psc lock];
[psc addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:localStore
options:options
error:nil];
[psc unlock];
}
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"iCloud routine completed.");
Setup *install = [[Setup alloc] init];
if([install shouldMigrate]) {
HUD = [[MBProgressHUD alloc] initWithView:self.window.rootViewController.view];
HUD.delegate = self;
HUD.labelText = NSLocalizedString(#"Sincronizzazione del database", nil);
[self.window.rootViewController.view addSubview:HUD];
[HUD showWhileExecuting:#selector(installDatabase) onTarget:install withObject:nil animated:YES];
}
else {
[[NSNotificationCenter defaultCenter] postNotificationName:#"setupCompleted" object:self];
}
//[[NSNotificationCenter defaultCenter] postNotificationName:#"icloudCompleted" object:self userInfo:nil];
[[NSNotificationCenter defaultCenter] postNotificationName:#"setupCompleted" object:self];
});
});
return __persistentStoreCoordinator;
}
You can't know whether or not there's going to be data available in iCloud until you finish syncing with iCloud. That means that you've got two options:
Make the user wait until the sync is done.
Start up with your default database and merge changes from iCloud when possible.
With iCloud, you need some strategy for resolving conflicts between local data and cloud data because you have to deal with the fact that users might change data on more than one device at the same time. Once you have that in place, it seems pretty clear that the second option above is the better one: users get to start using your app right away, and data from the cloud is merged when it's available.
I had exactly same problem.
Check out my question & my answer to it iCloud + CoreData - how to avoid pre-filled data duplication?
Actually it doesn't work 100% ok. If you dare to try it I can explain you how you might make it work 100% correctly (I haven't tried yet, though).
Taking into account that you have a lot of data to pre-populate my solution might now work out for you.
There is no way to determine whether a data store is being opened for the first time. At least not on iCloud Core Data store. Think of it, iCloud should also work off-line – that is, all changes should be buffered when the user is disconnected from the Internet and then uploaded when the connection is restored. There is no way to check whether a data store was initialized without potentially making the user wait for a few minutes (or even indefinitely if the device is off-line) to ask iCloud's copy of the data sore.
To solve this, you'll need to follow these four simple guidelines:
Have a way to de-duplicate pre-populated records.
Have a way to identify pre-populated records and differentiate it from user-entered ones.
Run the de-duplication process every time new transaction records came in from iCloud.
Only seed data records once per device/account combination.
You can read more details here: http://cutecoder.org/programming/seeding-icloud-core-data/

Custom Graph API request on iPhone SDK

Is it possible to make a custom Graph API call using FBConnect?
For example,
[facebook requestWithGraphPath:#"me" andDelegate:self];
With this call, I can see my own details.
[facebook requestWithGraphPath:#"me/friends" andDelegate:self];
With this I can see my friends.
[facebook requestWithGraphPath:#"FRIEND_ID/picture" andDelegate:self];
With this I can see a picture from a friend with id=FRIEND_ID.
Is there a possibility to make a custom Graph API call, to take id, picture, name and for example email, of all my facebook friends, in just one call?
Problem that I have is, when I call:
[facebook requestWithGraphPath:#"me/friends" andDelegate:self];
In:
- (void)request:(FBRequest *)request didLoad:(id)result;
I take the IDs of my friends, and then, in a for loop I want to do this:
[[self appDelegate].facebook requestWithGraphPath:[NSString stringWithFormat:#"%#/picture",[[party.attendantsDictionary allKeys] objectAtIndex:i]] andDelegate:self];
Afterwards, in
- (void)request:(FBRequest *)request didLoad:(id)result;
I have:
if ([result isKindOfClass:[NSData class]]) {
[party.attendantsPictures addObject:[[UIImage alloc] initWithData:result]];
}
Problem is that pictures and names of my friends are all mixed up.
Anyone has a solution?
You could try NSRunLoop.
In my case, I wanna load user's name, status, profile picture at once. However, requestWithGraphPath and its delegate didload: result definitely only can handle each request at a time. So what I did is:
1/ Setup a tag number
2/ After each request, wait for the request to be completed, increase tag number by 1
So in my button action,
tagNo = 0;
[facebook requestWithGraphPath:graphPathZero // For user's name
andDelegate:detailVC];
while ( tagNo == 0) && [theRL runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]);
[facebook requestWithGraphPath:graphPathOne // For user's status
andDelegate:detailVC];
while ( tagNo == 1) && [theRL runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]);
[facebook requestWithGraphPath:graphPathTwo // For user's profile picture
andDelegate:detailVC];
while ( tagNo == 2) && [theRL runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]);
And in the delegate,
switch (tagNo) {
case 0:
// Do something with result
break;
case 1:
// Do something with result
break;
case 2:
// Do something with result
break;
default:
break;
}
++tagNo;
I may not cover "Do something with result" here since it's in somewhere else in stackoverflow. This might not be the solution, but I found it approachable. Look for more contributions from others ;)
Hmmm, I've never used NSRunLoop. Could you give me a hint what it is? (Apple's Docs are little confusing...).
In your case, I would do something like this:
NSString *fql = #"SELECT name, uid, pic_square, status FROM user WHERE uid = me() OR uid IN (SELECT uid2 FROM friend WHERE uid1 = me())";
NSMutableDictionary *params = [NSMutableDictionary dictionaryWithObjectsAndKeys:fql, #"query", nil];
[facebook requestWithMethodName:#"fql.query" andParams:params andHttpMethod:#"POST" andDelegate:self];
This way, you would get everything from the users, that you want.

Setting up basic relationship with Fetch Requests

I am wanting to set up a basic relationship with two entities in Core Data, but the relationship is either not saving, or is not working properly and I'm not sure why.
The two entities are Character and Avatar, its a one-to-one relationship. A character can have 1 avatar. Technically, it should be a "one avatar can be owned by many characters", but I'll deal with that later.
I want to add characters and assign them an avatar.
There are already 10 avatars in Core Data and 1 character, both of which I've verified via the Terminal and SQLite.
The problem is, I'm having troubling "finding an avatar by a name and then saving the relationship to a character".
So far,
I set up a fetch request called: "frqAvatarWithName" where the Predicate has the following structure:
[quote]
name == $AVATAR_NAME
[/quote]
This is so: I can find an avatar with a certain name; and then I can create a relationship with a character.
Issue 1: It gets to execute the query but then never displays how many records there are.
I get a EXC_BAD_ACCESS error in debug mode and I have traced it back to the fetch request template handling -- so, this must be in error or I have done it wrong.
Issue 2: I am not sure if I am even setting up this "basic" relationship up properly.
[code]
// This code is meant to find an avatar with a certain name and then save the relationship
// between a character and said avatar.
// This is my app delegate file for the moment
// All the files are present, and I have deleted/recreated the app various times
-(void)characterMaker
{
NSLog(#"Inside characterMaker...");
NSError *error = nil;
NSManagedObjectContext *context = [self managedObjectContext];
NSManagedObjectModel *model = [self managedObjectModel];
// Find an avatar with a specific name
NSString *nameToFind = #"avt_player_1";
// Use a Fetch request template
NSDictionary *subs = [NSDictionary dictionaryWithObjectsAndKeys:nameToFind, #"AVATAR_NAME", nil];
NSFetchRequest *fetchRequest = [model fetchRequestFromTemplateWithName:#"frqAvatarWithName"
substitutionVariables:subs];
// Set the entity to use
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Avatar"
inManagedObjectContext:context];
[fetchRequest setEntity:entity];
// Execute the query (it never even reaches this point)
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
if (fetchedObjects == nil) {
// Handle the error
NSLog(#"Error -- %#", [error localizedDescription]);
abort();
}
NSLog(#"Found %# records", [fetchedObjects count]);
// Print out avatar names
for (Avatar *a in fetchedObjects)
{
NSLog(#"Name = %#", [a valueForKey:#"name"]);
}
// This is where I would use `a` and store it in a character entity, and thus create the relationship
[/code]
I gave up on this and did the whole project with the FMDatabase project and SQLite; I've been able to resolve the problem this way.
Thread closed.

How to serialize a NSPredicate object?

Is there a way to inspect a NSPredicate object for the purposes of serializing it into a URL? I am trying to retrieve the data remotely and need to translate the predicate object into a URL with querystring parameters that the server understands.
This was inspired by a talk given in WWDC 2010 called "Building a Server Driven User EXperience" where the speakers talk about using Core-Data and with a server backend. I have followed the session video and slides, but am stuck on the serializing point. For example, there is a Person object, and I'm trying to fetch all people whose first name is "John". I am using a subclass of NSManagedObjectContext called RemoteManagedObjectContext, which overrides the executeFetchRequest method, and is supposed to send the call to the server instead. The fetch request is being created as (ellipsed non-essential parts):
#implementation PeopleViewController
- (NSArray *)getPeople {
RemoteFetchRequest *fetchRequest = [[RemoteFetchRequest alloc] init];
NSEntityDescription *entity = ...
NSPredicate *template = [NSPredicate predicateWithFormat:
#"name == $NAME AND endpoint = $ENDPOINT"];
NSPredicate *predicate = [template predicateWithSubstitutionVariables:...];
[fetchRequest setEntity:entity];
[fetchRequest setPredicate:predicate];
NSError *error = nil;
// the custom subclass of NSManagedObjectContext executes this
return [remoteMOC executeFetchRequest:fetchRequest error:&error];
}
#end
Now inside the custom subclass of NSManagedObjectContext, how can I serialize the fetch request into querystring parameters suitable for the server. So given the above fetch request, the corresponding URL would be:
http://example.com/people?name=John
It is possible to get a string representation of the predicate which returns,
name == "John" AND endpoint == "people"
that I can parse to get the parameters name, and endpoint. However, is it possible to do it without parsing the string? Here's a partial implementation of the RemoteManagedObjectContext class.
#implementation RemoteManagedObjectContext
- (NSArray *)executeFetchRequest:(NSFetchRequest *)request error:(NSError **)error {
// this gives name == "John" AND endpoint == "people"
// don't know how else to retrieve the predicate data
NSLog(#"%#", [[request predicate] predicateFormat]);
...
}
#end
Even better than a string representation is an object-oriented representation! And it's done automatically!
First, check the class of the NSPredicate. It will be an NSCompoundPredicate. Cast it to an appropriate variable.
You'll then see that it's compoundPredicateType is NSAndPredicateType, just like you'd expect.
You can also see that the array returned by -subpredicates reveals 2 NSComparisonPredicates.
The first subpredicate has a left expression of type NSKeyPathExpressionType and a -keyPath of #"name", the operator is NSEqualToPredicateOperatorType. The right expression will be an NSExpression of type NSConstantValueExpressionType, and the -constantValue will be #"John".
The second subpredicate will be similar, except that the left expression's keyPath will be #"endpoint", and the right expression's constantValue will be #"people".
If you want more in-depth information on turning NSPredicates into an HTTP Get request, check out my StackOverflow framework, "StackKit", which does just that. It's basically a framework that behaves similarly to CoreData, but uses StackOverflow.com (or any other stack exchange site) to retrieve information. Underneath, it's doing a lot to convert NSPredicate objects into a URL. You're also welcome to email me any specific questions you have.

Resources