I have added the announcement app and added few items to it, now i want to fetch the items from my announcement list so I have used the below code
token_Obtained_During_first_time_Login: This is the token that i get when i login for the first time using the acquireTokenWithResource method of ADAuthenticationContext class
- (void)getClientList {
NSString *appToken = [[NSUserDefaults standardUserDefaults]
valueForKey:#"token_Obtained_During_first_time_Login"];
NSString* hostName = #"https://myTenant.sharepoint.com/sites/myApp";
OAuthentication *credentials = [[OAuthentication alloc] initWith:appToken];
ListClient *client = [[ListClient alloc]
initWithUrl:hostName
credentials:credentials];
NSURLSessionTask* task = [client getListItems:#"MyAnnouncements"
callback:^(NSMutableArray *listItems, NSError *error) {
if (error==nil) {
NSLog(#"%#",listItems);
}
}];
[task resume];
}
I have even debugged the 365 code and it provides me the below URL for getListItems: callback method
https://myTenant.sharepoint.com/sites/myApp/_api/lists/GetByTitle('MyAnnouncements')/Items
I have even tried the same using getTokenWith method which comes with the sample code
- (void)getAnnouncementList:(void (^)(ListClient *))callback{
NSString* hostName = #"https://myTenant.sharepoint.com";
[self getTokenWith:hostName :true completionHandler:^(NSString *token) {
OAuthentication *credentials = [[OAuthentication alloc] initWith:token];
callback([[ListClient alloc]initWithUrl:hostName credentials:credentials]);
}];
}
But still no luck i get the list as nil
Please guide on how this can be resolved, I have even verified the rights in the Azure Directory everything seems fine am able to fetch data of one drive, mails and calendar but list is a place where i am stuck.
Every time i call the above code i get the response nil not sure what am passing wrong, my guess is the token.
I resolved this issue by making a change in the apiUrl present in the ListClient.m file of Office 365.
All i did was changed it to
const NSString *apiUrl = #"/sites/mobileApp/_api/web/Lists";
Making the above change did the trick and now i can access all the list data.
I'm working with an app that requests data from an OAuth2.0 protected server. When I use the GTM OAuth Library to retrieve data, the program continues to run while the data is being downloaded in the background. I need some sort of mechanism to either force my application to wait until the didFinishWithData selector is called,or I need a way to notify my ViewController of the download's completion, so I can then utilize the data immediately.
I've tried conditional blocks, but those aren't doing it for me. I've also tried polling the object whose data I'm interested in, but if I do that, the data never seems to download. I've heard I can somehow utilize the Notification Center to accomplish this task, so I'll look more into that while I'm waiting for replies here.
Here is basically what is going on:
-(void) getAlert{
// Define the URL of the API module we'd like to utilize.
NSURL *url = [[NSURL alloc] initWithString:#"https://access.active911.com/interface/open_api/api/alerts"];
// Constructs a an HTTP request object to send to the server in order to obtain data.
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
[request setValue:#"1" forHTTPHeaderField:#"alert_days"];
// This fetcher sends the request along with the authentication header in a recognizable manner.
GTMHTTPFetcher *fetcher = [[GTMHTTPFetcher alloc] initWithRequest:request];
// Attach the OAuth credentials for the fetcher's use.
[fetcher setAuthorizer:auth];
// Execute the operation.
[fetcher waitForCompletionWithTimeout:10];
NSLog(#"About to get alert");
[fetcher beginFetchWithDelegate:self didFinishSelector:#selector(responseHandler:finishedWithData:finishedWithError:)];
NSLog(#"got alert");
}
-(void)responseHandler:(id)valueNotUsed finishedWithData:(NSData *)data finishedWithError:(NSError *)error{
// Retrieve the server data in a usable object
// All that's being done here is conversion to an NSDictionary
// followed by the creation of subdictionaries from that dictionary
// until our final value can be picked directly out of the resulting dict
NSData *jsonData = [[NSData alloc] initWithData:data];
NSError *dictError;
NSDictionary* json = [NSJSONSerialization
JSONObjectWithData:jsonData //1
options:kNilOptions
error:&dictError];
NSDictionary *token = [json objectForKeyedSubscript:#"message"];
NSArray *alerts = [token objectForKeyedSubscript:#"alerts"];
NSDictionary *alertData = alerts[0];
mapCode = [alertData objectForKeyedSubscript:#"map_code"];
NSString *city = [alertData objectForKeyedSubscript:#"city"];
NSLog(#"Map code: '%#' with city '%#' and access token %#", mapCode, city, accessToken);
}
And I need to pass the mapCode to my view controller.
Thanks for the help!
First off, please rethink about having the UI halt while you fetch results from the server. This can create an extremely bad UX for the app and only should be done if absolutely necessary.
Second, does your responseHandler method work? And do you only need mapCode in the VC that responseHandler is in?
If so, you don't even need to use Notifications. Simply do:
-(void)responseHandler:(id)valueNotUsed finishedWithData:(NSData *)data finishedWithError:(NSError *)error{
...
...
mapCode = [alertData objectForKeyedSubscript:#"map_code"];
[self updateVCWithMapCode:mapCode];
}
That will call the method after the response has been received. Passing it explicitly too so you don't need to have mapCode be a property as well.
My app displays a short list of tweets based on a given TV hashtag with the additional ability to post a tweet.
But now twitter has gone oauth for all requests, my tweet list doesnt appear as it was using the old search.atom API.
Therefore, how do I access the search api and pass in OAuth credentials using Sharekit so user authenticates just the once for viewing tweets and posting between sessions.
I have tried using SHKRequest, hoping, that as ShareKit has already authorised it will pass this information through; with no joy, is there some other way of doing this or am I just using it badly/wrong.
request = [[[SHKRequest alloc] initWithURL:[NSURL URLWithString:#"https://api.twitter.com/1.1/search/tweets.json?q=twitter&result_type=recent"]
delegate:self
isFinishedSelector:#selector(sendFinishedSearch:)
params:nil
method:#"GET"
autostart:YES] autorelease];
I do need to maintain compatibility with 4.3 API so I cant just use iOS5 Twitter API.
Disclaimer: I am inheriting project from someone so my XCode/ObjC knowledge is being learnt whilst I modify project (I come from C/C++ background), so please ignore my ignorance.
ShareKit contains an SHKTwitter class. It is a subclass of SHKOAuthSharer. As such, you can ask it to perform authorisations / refreshes and get the resulting token.
Create an instance of SHKTwitter and register as it's delegate. Implement the - (void)sharerAuthDidFinish:(SHKSharer *)sharer success:(BOOL)success delegate method. Then call tokenRequest. When the delegate method is called, if success is YES you can get the accessToken.
SHKTwitter *twitter = [[SHKTwitter alloc] init];
twitter.shareDelegate = self;
[twitter tokenRequest];
- (void)sharerAuthDidFinish:(SHKSharer *)sharer success:(BOOL)success
{
SHKTwitter *twitter = (SHKTwitter *)sharer;
if (twitter.accessToken != nil) {
NSLog(#"session: %#, %#", twitterSharer.accessToken.key, twitterSharer.accessToken.secret);
} else {
[twitter tokenAccess];
}
}
IN SHKOAuthSharer.m class You will get access Token in method:
- (void)tokenAccessTicket:(OAServiceTicket *)ticket didFinishWithData:(NSData *)data
{
if (SHKDebugShowLogs) // check so we don't have to alloc the string with the data if we aren't logging
SHKLog(#"tokenAccessTicket Response Body: %#", [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]);
///[[SHKActivityIndicator currentIndicator] hide];
if (ticket.didSucceed)
{
NSString *responseBody = [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
//piyush Added
NSArray *strArray = [responseBody componentsSeparatedByString:#"="];
[[NSUserDefaults standardUserDefaults]setObject:[strArray objectAtIndex:([strArray count]-1)] forKey:#"TwitterUsername"];
**self.accessToken** = [[OAToken alloc] initWithHTTPResponseBody:responseBody];
[responseBody release];
[self storeAccessToken];
//[self tryPendingAction];
[[NSNotificationCenter defaultCenter] postNotificationName:#"TwitterDidLogin" object:nil];
}
else
// TODO - better error handling here
[self tokenAccessTicket:ticket didFailWithError:[SHK error:SHKLocalizedString(#"There was a problem requesting access from %#", [self sharerTitle])]];
}
I am trying to make a basic iphone app that shows nearby tweets. I was using the TWRequest object to accomplish this with the twitter search api. Unfortunately, I would actually like to mark the tweets on a map using their GPS coordinates and the search api doesn't seem to return the actual location that a tweet was made with any better accuracy than the city name.
As such, I think I need to switch to the streaming api. I am wondering if it is possible to continue using the TWRequest object in this case or if I need to actually switch over to using NSURLConnection? Thanks in advance!
Avtar
Yes, you can use a TWRequest object. Create your TWRequest object using the appropriate URL and parameters from the Twitter API doco, and set the TWRequest.account property to the ACAccount object for the Twitter account.
You can then use the signedURLRequest method of TWRequest to get an NSURLRequest which can be used to create an asynchronous NSURLConnection using connectionWithRequest:delegate:.
Once this is done, the delegate's connection:didReceiveData: method will be called whenever data is received from Twitter. Note that each NSData object received may contain more than one JSON object. You will need to split these up (separated by "\r\n") before converting each one from JSON using NSJSONSerialization.
It took me a bit of time to get this up and running, So I thought I aught to post my code for others. In my case I was trying to get tweets close to a certain location, so you will see that I used a locations parameter and a location struct I had in scope. You can add whatever params you want to the params dictionary.
Also note that this is bare bones, and you will want to do things such as notify the user that an account was not found and allow the user to select the twitter account they would like to use if multiple accounts exist.
Happy Streaming!
//First, we need to obtain the account instance for the user's Twitter account
ACAccountStore *store = [[ACAccountStore alloc] init];
ACAccountType *twitterAccountType = [store accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];
// Request permission from the user to access the available Twitter accounts
[store requestAccessToAccountsWithType:twitterAccountType
withCompletionHandler:^(BOOL granted, NSError *error) {
if (!granted) {
// The user rejected your request
NSLog(#"User rejected access to the account.");
}
else {
// Grab the available accounts
NSArray *twitterAccounts = [store accountsWithAccountType:twitterAccountType];
if ([twitterAccounts count] > 0) {
// Use the first account for simplicity
ACAccount *account = [twitterAccounts objectAtIndex:0];
NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
[params setObject:#"1" forKey:#"include_entities"];
[params setObject:location forKey:#"locations"];
[params setObject:#"true" forKey:#"stall_warnings"];
//set any other criteria to track
//params setObject:#"words, to, track" forKey#"track"];
// The endpoint that we wish to call
NSURL *url = [NSURL URLWithString:#"https://stream.twitter.com/1.1/statuses/filter.json"];
// Build the request with our parameter
TWRequest *request = [[TWRequest alloc] initWithURL:url
parameters:params
requestMethod:TWRequestMethodPOST];
// Attach the account object to this request
[request setAccount:account];
NSURLRequest *signedReq = request.signedURLRequest;
// make the connection, ensuring that it is made on the main runloop
self.twitterConnection = [[NSURLConnection alloc] initWithRequest:signedReq delegate:self startImmediately: NO];
[self.twitterConnection scheduleInRunLoop:[NSRunLoop mainRunLoop]
forMode:NSDefaultRunLoopMode];
[self.twitterConnection start];
} // if ([twitterAccounts count] > 0)
} // if (granted)
}];
I occasionally need to cancel a FaceBook graph request, but there seems to be no cancel or similar method in their API to do so. At the moment, crashes sometimes occur as the delegate I assigned to the request has been deallocated. Is there any way to cancel a graph request once submitted please?
I'm assuming you're talking about the facebook-ios-sdk project, and the lack of a cancel method in Facebook.h. I noticed this as well, and eventually decided to add my own cancel method. Just to note, the delegate you assign to the request shouldn't ever be dealloc'd and then referenced, because the request retains the delegate. See this similar question. Now, if you find yourself really needing a cancel method for some other reason...
Adding a cancel method:
Facebook requests are made in an opaque manner. You never see them, and only hear about results via the Facebook class. Under the hood, the Facebook class makes Graph API requests with the (not for public use) FBRequest class. This class is is basically a fancy NSURLConnection delegate. So to cancel the request, the member NSURLConnection just has to be told to cancel. Adding this method to FBRequest:
// Add to FBRequest.h
- (void)cancel;
And...
// Add to FBRequest.m
- (void)cancel {
[_connection cancel];
[_connection release], _connection = nil;
}
Now, to expose an interface in the Facebook class to make use of the new method...
// Add to Facebook.h
- (void)cancelPendingRequest;
And...
// Add to Facebook.m
- (void)cancelPendingRequest {
[_request cancel];
[_request release], _request = nil;
}
That's all there is to it. The method above will cancel the most recent request, and you'll never hear from it again.
I've followed Matt Wilding's approach listed here, which was very useful, thanks Matt. Unfortunately it didnt quite work for me, so I made some tweaks and now it works... also this revised approach keeps out of the core facebook classes...
//in .h define an FBRequest property
#property (nonatomic, retain) FBRequest * pendingFBRequest;
//in .m when making your request, store it in your FBRequest property
pendingFBRequest = [facebook requestWithGraphPath:#"me/feed"
andParams:params
andHttpMethod:#"POST"
andDelegate:self];
//create a timer for your timeout
pendingFacebookActionTimer = [NSTimer scheduledTimerWithTimeInterval:15.0 target:self selector:#selector(onPendingFacebookActionTimeout) userInfo:nil repeats:NO];
//cancel the action on the timeout's selector method
-(void)onPendingFacebookActionTimeout {
[pendingFBRequest.connection cancel];
}
Updated on 22/April/2012
I update Matt's version with the most up-to-date Facebook iOS SDK. My Project is using ARC, but I include the non-ARC Facebook sources so that I can modify the codes. (Of Course, we need to set the "-fno-objc-arc" flag for Facebook source files). The tricky part is to prevent the memory leak, and I think I am doing it correctly. But When I test it in the instrument, I still see very small amount of memory leak. Fortunately, the details show that they are not related to these codes, so I just assume they are related to the app resource handling.
Here is the code I implemented:
// Add to Facebook.h
- (void)cancelPendingRequest:(FBRequest *)releasingRequest;
And...
// Add to Facebook.m
- (void)cancelPendingRequest:(FBRequest *) releasingRequest{
[releasingRequest.connection cancel];
[releasingRequest removeObserver:self forKeyPath:requestFinishedKeyPath];
[_requests removeObject:releasingRequest];
}
And in your project which uses FBRequestDelegate
// Declare this member or property to the .h file
FBRequest * currentFbRequest;
// Declare this method
-(void)cancelFBRequest;
And ...
// In .m file
AppDelegate * appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
// prepare your necessary request data and parameter ...
currentFbRequest = [appDelegate.facebook requestWithGraphPath:#"/me/photos"
andParams:params
andHttpMethod:#"POST"
andDelegate:self];
// Then in the method where you want to cancel
AppDelegate * appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate.facebook cancelPendingRequest:currentFbRequest];
currentFbRequest=nil;
For those of us who build the static library and are unable to access the implementation files, a category would be the best way to go.
For those of us who did not build the static library, using a category would be optimal as well because you don't need to modify the existing files.
Here is said category.
// Facebook+Cancel.h
#import "Facebook.h"
#interface Facebook (Facebook_cancel)
- (void)cancelPendingRequest:(FBRequest *)releasingRequest;
- (void)cancelAllRequests;
#end
And then the .m file
// Facebook+Cancel.m
#import "Facebook+Facebook_cancel.h"
#implementation Facebook (Facebook_cancel)
- (void)cancelPendingRequest:(FBRequest *)releasingRequest{
[releasingRequest.connection cancel];
if ([_requests containsObject:releasingRequest]) {
[_requests removeObject:releasingRequest];
[releasingRequest removeObserver:self forKeyPath:#"state"];
}
}
- (void)cancelAllRequests {
for (FBRequest *req in [_requests mutableCopy]) {
[_requests removeObject:req];
[req.connection cancel];
[req removeObserver:self forKeyPath:#"state"];
}
}
#end
For those using any other answer, you are causing a memory leak. The Facebook SDK will warn you through NSLog that you have not removed an observer. The fourth line in the cancelAllRequests method fixes this problem.
Try this instead of using NSTimer:
FBRequest *fbRequest = [facebook requestWithGraphPath:#"me" andDelegate:self];
[self performSelector:#selector(fbRequestTimeout:) withObject:fbRequest afterDelay:30];
- (void)fbRequestTimeout:(FBRequest *)fbRequest
{
[fbRequest.connection cancel];
[fbRequest setDelegate:nil];
}
Since SDK 3.1, it's very easy, as startWithCompletionHandler: returns a FBRequestConnection object, which has a -(void)cancel; method.
For example:
// In interface or .h definitions:
#property (strong, nonatomic) FBRequest *fBRequest;
#property (strong, nonatomic) FBRequestConnection *fbConnection;
// when needed in class (params should be set elsewhere, this is just an example):
self.fBRequest = [[FBRequest alloc] initWithSession:[FBSession activeSession] graphPath:#"me/photos" parameters:params HTTPMethod:#"POST"];
self.fbConnection = [self.fBRequest startWithCompletionHandler:^(FBRequestConnection *connection, id result, NSError *error){
NSLog(#"Publish complete, error: %d", error.code);
}];
// now, to cancel anywhere in the class, just call:
[self.fbConnection cancel];
In FBRequest.h, I've had to add _delegate = nil; because in my case, the request delegate no longer existed (it was dismissed) which caused a crash.
I was having a crash with the previous iOS Facebook SDK which was valid in August 2012 whenever I navigated to another view. My solution is based on #staticfiction response:
Added BOOL viewWillDisappear flag in .h. In -(void) viewWillDisappear: set the flag to YES. Reset flag to NO in -(void) viewDidAppear:
//in .h define an FBRequest property
#property (nonatomic, retain) FBRequest * pendingFBRequest;
/*
* Graph API: Search query to get nearby location.
*/
- (void)apiGraphSearchPlace:(CLLocation *)location {
currentAPICall = kAPIGraphSearchPlace;
NSString *centerLocation = [[NSString alloc] initWithFormat:#"%f,%f",
location.coordinate.latitude,
location.coordinate.longitude];
JMYAppDelegate *delegate = (JMYAppDelegate *)[[UIApplication sharedApplication] delegate];
NSMutableDictionary *params = [NSMutableDictionary dictionaryWithObjectsAndKeys:
#"place", #"type",
centerLocation, #"center",
#"1000", #"distance",
nil];
[centerLocation release];
pendingFBRequest = [[delegate facebook] requestWithGraphPath:#"search" andParams:params andDelegate:self];
if (viewWillDisappear) {
[pendingFBRequest.connection cancel];
[pendingFBRequest setDelegate:nil];
[self hideActivityIndicator];
}
}
Make a CURL call to this URL
https://graph.facebook.com/REQUEST_ID?method=delete