in app purchase response never comes - iphone

In my iPhone app, i've set up an in app purchase. I start the request like this:
SKProductsRequest *request= [[SKProductsRequest alloc] initWithProductIdentifiers: [NSSet setWithObject: #"com.nicknoble.tiprounder.upgrade"]];
request.delegate = self;
[request start];
And I use this method to get the response:
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
NSLog(#"response recieved");
}
And this one to catch an error:
-(void)request:(SKRequest *)request didFailWithError:(NSError *)error
{
NSLog(#"%#",error.description);
}
But neither ever get called. My project has no warnings or errors, and I am running this on my device (iPhone). Any suggestions?
EDIT:
So it works on my window's root view controller, but not on modal view controllers i present. Here is the code from my main view controller:
TestViewController *testView = [[TestViewController alloc] initWithNibName:#"TestViewController" bundle:nil];
[self presentModalViewController:testView animated:YES];
Here is the .h file for TestViewController:
#import <UIKit/UIKit.h>
#import <StoreKit/StoreKit.h>
#interface TestViewController : UIViewController <SKProductsRequestDelegate>
#end
Here is the code for my .m file:
#import "TestViewController.h"
#implementation TestViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
SKProductsRequest *request= [[SKProductsRequest alloc] initWithProductIdentifiers: [NSSet setWithObject: #"com.nicknoble.tiprounder.upgrade"]];
request.delegate = self;
[request start];
}
-(void)request:(SKRequest *)request didFailWithError:(NSError *)error
{
NSLog(#"%#",error.description);
}
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
NSLog(#"response recieved");
}
#end
Im desperate. Any help would be great! Thanks!

The SKProductsRequest instance need to be retained for the duration of the request. If it's not, it will die silently (without informing its delegate) because nothing else is retaining it.
Right now, ARC will get rid of your SKProductsRequest as soon as the code exits the scope where you allocate it.
A solution would be to keep your SKProductsRequest in an ivar and set it to nil when the request completes/fails. This is also handy to prevent starting a request while there's already one in progress:
// Define _productsRequest as an ivar of type SKProductsRequest in your class
- (void)someMethodThatInitiatesTheProductsRequest
{
if( _productsRequest != nil )
return; // There's already a request in progress. Don't start another one.
SKProductsRequest *request= [[SKProductsRequest alloc] initWithProductIdentifiers: [NSSet setWithObject: #"com.nicknoble.tiprounder.upgrade"]];
request.delegate = self;
[request start];
_productsRequest = request; // <<<--- This will retain the request object
}
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
NSLog(#"response recieved");
_productsRequest = nil; // <<<--- This will release the request object
}
-(void)request:(SKRequest *)request didFailWithError:(NSError *)error
{
NSLog(#"%#",error.description);
_productsRequest = nil; // <<<--- This will release the request object
}

check your product identifier first.
also check if the class in which these methods are implemented is not released somehow. (might be autoreleased and got released automatically while you are waiting for response)

Related

I can't receive XML file from Weather Underground service

I'm trying to write a weather app that use wunderground api...
I've got an apiKey and I used it in the code below, but I can't see any result in debug area...
Xcode show me a warning in a line "EXPRESSION RESULT UNUSED"...Is this the problem?
Can anybody help me please?
#import "WeatherForecast.h"
#import "MainViewController.h"
#implementation WeatherForecast
- (void) queryServiceWithState:(NSString *)state
andCity:(NSString *)city
withParent:(UIViewController *)controller {
viewController = (MainViewController *)controller;
responseData = [NSMutableData data];
apiKey = #"c5f79118382c6e91";
NSString *url =
[NSString stringWithFormat:
#"http://api.wunderground.com/api/%#/conditions/q/%#//%#.xml",
apiKey, state, city];
theURL = [NSURL URLWithString:url];
NSURLRequest *request = [NSURLRequest requestWithURL:theURL];
[[NSURLConnection alloc] initWithRequest:request delegate:self];//EXPRESSION RESULT UNUSED
}
#pragma mark NSURLConnection Delegate Methods
- (NSURLRequest *)connection:(NSURLConnection *)connection
willSendRequest:(NSURLRequest *)request
redirectResponse:(NSURLResponse *)response{
#autoreleasepool {
theURL = [request URL];
}
return request;
}
- (void)connection:(NSURLConnection *)connection
didReceiveResponse:(NSURLResponse *)response {
[responseData setLength:0];
}
-(void)connection:(NSURLConnection *)connection
didReceiveData:(NSData *)data {
[responseData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSLog(#"Error = %#",error);
}
- (void)connectionDidFinishiLoading: (NSURLConnection *)connection {
NSString *content =
[[NSString alloc]initWithBytes:[responseData bytes]
length:[responseData length]
encoding:NSUTF8StringEncoding];
NSLog ( #"Data = %#",content);
//...Insert code to parse the content here...
[viewController updateView];
}
#end
I've got another 2 .m files for my app, maybe the error is in one of this
#import "MainViewController.h"
#import "WeatherForecast.h"
#interface MainViewController ()
#end
#implementation MainViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[self refreshView:self];
}
- (IBAction)refreshView:(id)sender {
[loadingActivityIndicator startAnimating];
[self.forecast queryServiceWithState:#"UK" andCity:#"London" withParent:self];
}
- (void)updateView {
//...
[loadingActivityIndicator stopAnimating];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Flipside View
- (void)flipsideViewControllerDidFinish:(FlipsideViewController *)controller
{
[self dismissViewControllerAnimated:YES completion:nil];
}
- (IBAction)showInfo:(id)sender
{
FlipsideViewController *controller = [[FlipsideViewController alloc]
initWithNibName:#"FlipsideViewController" bundle:nil];
controller.delegate = self;
controller.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentViewController:controller animated:YES completion:nil];
}
#end
And
#import "AppDelegate.h"
#import "WeatherForecast.h"
#import "MainViewController.h"
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:
(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.mainViewController = [[MainViewController alloc]
initWithNibName:#"MainViewController" bundle:nil];
WeatherForecast *forecast = [[WeatherForecast alloc] init];
self.mainViewController.forecast = forecast;
self.window.rootViewController = self.mainViewController;
[self.window makeKeyAndVisible];
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application
{
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
}
- (void)applicationWillTerminate:(UIApplication *)application
{
}
#end
If I try to turn off internet connection I can see in the debug area the "Error message", but if I turn on internet connection, so I only see the Activity Indicator spinning forever...
Thank you for your response....I feel lost...
Where you get EXPRESSION RESULT UNUSED is the connection object. You should usually be storing that into a property so you ensure that it isn't destroyed while you're still using it.

How do you get the NSURLConnection delegate methods to trigger?

I can't seem to get the delegate methods to call, when I load the view associated with this class.. none of them fire. I'm sure it's something that I've overlooked but I can't for the life of me figure out why.
DownloadUpdates.h
#import <UIKit/UIKit.h>
#interface DownloadUpdates : UIViewController
#property (strong, nonatomic) NSMutableData *responseData;
#property (strong, nonatomic) NSURLConnection *connection;
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response;
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data;
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error;
- (void)connectionDidFinishLoading:(NSURLConnection *)connection;
#end
DownloadUpdates.m
The URL has been removed for privacy purposes, but it's just making a call to an API which will be returning JSON data. This URL functions as expected so it's an issue with the code.
#import "DownloadUpdates.h"
#interface DownloadUpdates ()
#end
#implementation DownloadUpdates
- (void)connection:(NSURLConnection *)_connection didReceiveResponse:(NSURLResponse *)response
{
_responseData = [[NSMutableData alloc] init];
NSLog(#"Response received");
}
- (void)connection:(NSURLConnection *)_connection didReceiveData:(NSData *)data
{
[_responseData appendData:data];
NSLog(#"Data received");
}
- (void)connection:(NSURLConnection *)_connection didFailWithError:(NSError *)error
{
NSLog(#"Unable to fetch data");
}
- (void)connectionDidFinishLoading:(NSURLConnection *)_connection
{
NSLog(#"Succeeded! Received %d bytes of data",[_responseData
length]);
// NSString *txt = [[NSString alloc] initWithData:_responseData encoding: NSASCIIStringEncoding];
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
NSURL *myURL = [NSURL URLWithString:#"URL HERE"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:myURL cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:60];
_connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
I'd appreciate any help / advice you can offer.
Use the properties to apply the strong modifier:
self.responsedata = [[NSMutableData alloc] init];
(.....)
self.connection = [[NSURLConnection alloc] initWithRequest: ....etc...
I'd suggest putting a NSLog or breakpoint in viewDidLoad to make sure this is getting called at all. For example, this might happen if you neglected to specify DownloadUpdates as the class for your storyboard scene.

iOS: foursquare request fails

I am assigned to work with foursquare just recently. I have an app that needs to be authenticated and access the foursquare environment. I am having trouble with the following code to access checkins. I had already successfully made the authentication but the thing is that when I made a check in request, an errorType invalid_auth code 401 appears. I just don't know what's wrong with this.
Here is my full code; I am using fsq wrapper I found in github:
#import "FSQViewController.h"
#define kClientID #"XXXXXXXXXXXXXXXXXXXXXXX"
#define kCallbackURL #"invitation://foursquare"
#interface FSQViewController()
#property(nonatomic,readwrite,strong) BZFoursquare *foursquare;
#property(nonatomic,strong) BZFoursquareRequest *request;
#property(nonatomic,copy) NSDictionary *meta;
#property(nonatomic,copy) NSArray *notifications;
#property(nonatomic,copy) NSDictionary *response;
#end
#implementation FSQViewController
#synthesize foursquare = foursquare_;
#synthesize request = request_;
#synthesize meta = meta_;
#synthesize notifications = notifications_;
#synthesize response = response_;
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#pragma mark - View lifecycle
- (id) initWithCoder:(NSCoder *)aDecoder{
self = [super initWithCoder:aDecoder];
if(self){
self.foursquare = [[BZFoursquare alloc]initWithClientID:kClientID callbackURL:kCallbackURL];
foursquare_.version = #"20120206";
foursquare_.locale = [[NSLocale currentLocale]objectForKey:NSLocaleLanguageCode];
foursquare_.sessionDelegate = (id<BZFoursquareSessionDelegate>) self;
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)viewDidUnload
{
[super viewDidUnload];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
#pragma mark -
#pragma mark BZFoursquareRequestDelegate
- (void)requestDidFinishLoading:(BZFoursquareRequest *)request {
NSLog(#"test");
self.meta = request.meta;
self.notifications = request.notifications;
self.response = request.response;
self.request = nil;
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}
- (void)request:(BZFoursquareRequest *)request didFailWithError:(NSError *)error {
NSLog(#"HERE > %s: %#", __PRETTY_FUNCTION__, error);
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:nil message:[[error userInfo] objectForKey:#"errorDetail"] delegate:nil cancelButtonTitle:NSLocalizedString(#"OK", #"") otherButtonTitles:nil];
[alertView show];
self.meta = request.meta;
self.notifications = request.notifications;
self.response = request.response;
self.request = nil;
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}
#pragma mark -
#pragma mark BZFoursquareSessionDelegate
- (void)foursquareDidAuthorize:(BZFoursquare *)foursquare {
NSLog(#"authorized!");
}
- (void)foursquareDidNotAuthorize:(BZFoursquare *)foursquare error:(NSDictionary *)errorInfo {
NSLog(#"not authorized! %s: %#", __PRETTY_FUNCTION__, errorInfo);
}
- (IBAction)click:(id)sender {
if (![foursquare_ isSessionValid]){
NSLog(#"here");
[foursquare_ startAuthorization];
} else {
[foursquare_ invalidateSession];
}
}
- (IBAction)checkin:(id)sender {
NSDictionary *parameters = [NSDictionary dictionaryWithObjectsAndKeys:#"4d341a00306160fcf0fc6a88", #"venueId", #"public", #"broadcast", kClientID, #"oauth_token", nil];
self.request = [foursquare_ requestWithPath:#"checkins/add" HTTPMethod:#"POST" parameters:parameters delegate:self];
[request_ start];
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
}
#end
can you help me guys? any help will highly be appreciated.
https://developer.foursquare.com/overview/responses
401 (Unauthorized) The OAuth token was provided but was invalid.
Might you have somehow corrupted your oauth token?
I am using the code below & it is working for me :
NSDictionary *parameters = #{#"venueId": #"4a0c6465f964a5202a751fe3", #"broadcast": #"public",#"oauth_token":kClientID};

NSArray with multiple nested requests

I have an app that uses a segmentedControl. First item is an "All" item, where the rest is created from an array based on result from webservice. When "All" is selected I want to request all the request.
How can I go about this,
NSArray *urls = [NSArray arrayWithObjects:#"http://service/group/1/",
#"http://service/group/2/", nil];
I want to collect all result from the calls into a collection and display it in a UITableView when the "All" item is selected and probably in viewDidLoad.
For the other segments only one of the request is issued and callback with an array that then is used in:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
I have tried to look at this example for making the request from the array MultipleDownloads
Thanks,
The method in my viewController to initiate the multiple download:
- (void)requestChildrenInBackground {
queue = [[NSOperationQueue alloc] init];
//Todo remove hard coded and get from previous request respons
NSArray *urls = [NSArray arrayWithObjects: #"http://service/1/children",
#"http://service/2/children",
#"http://service/3/children", nil];
NSLog(#"%#", urls);
for (NSString * url in urls)
{
GetSchedule *operation =
[GetSchedule urlDownloaderWithUrlString:url];
[queue addOperation:operation];
}
}
This is how the multiple request gets handled:
#import "GetSchedule.h"
#import "JSON.h"
#import "Authentication.h"
#import "AttendanceReportViewController.h"
#interface GetSchedule ()
- (void)finish;
#end
#implementation GetSchedule
#synthesize appDelegate;
#synthesize username;
#synthesize password;
#synthesize authenticationString;
#synthesize encodedLoginData;
#synthesize schedulesArray;
#synthesize url = _url;
#synthesize statusCode = _statusCode;
#synthesize data = _data;
#synthesize error = _error;
#synthesize isExecuting = _isExecuting;
#synthesize isFinished = _isFinished;
+ (id)urlDownloaderWithUrlString:(NSString *)urlString {
NSURL * url = [NSURL URLWithString:urlString];
GetSchedule *operation = [[self alloc] initWithUrl:url];
return [operation autorelease];
}
- (id)initWithUrl:(NSURL *)url {
self = [super init];
if (self == nil)
return nil;
_url = [url copy];
_isExecuting = NO;
_isFinished = NO;
return self;
}
- (void)dealloc
{
[username release];
[password release];
[encodedLoginData release];
[_url release];
[_connection release];
[_data release];
[_error release];
[super dealloc];
}
- (BOOL)isConcurrent
{
return YES;
}
- (void)start
{
if (![NSThread isMainThread])
{
[self performSelectorOnMainThread:#selector(start) withObject:nil waitUntilDone:NO];
return;
}
self.username = appDelegate.username;
self.password = appDelegate.password;
Authentication *auth = [[Authentication alloc] init];
authenticationString = (NSMutableString*)[#"" stringByAppendingFormat:#"%#:%#", username, password];
self.encodedLoginData = [auth encodedAuthentication:authenticationString];
[auth release];
NSLog(#"operation for <%#> started.", _url);
[self willChangeValueForKey:#"isExecuting"];
_isExecuting = YES;
[self didChangeValueForKey:#"isExecuting"];
// Setup up the request with the url
NSMutableURLRequest *request = [[NSMutableURLRequest alloc]
initWithURL:_url];
[request setHTTPMethod:#"GET"];
[request setValue:[NSString stringWithFormat:#"Basic %#", encodedLoginData] forHTTPHeaderField:#"Authorization"];
_connection = [[NSURLConnection alloc] initWithRequest:request
delegate:self];
if (_connection == nil)
[self finish];
else {
_data = [[NSMutableData alloc] init];
}
}
- (void)finish
{
NSLog(#"operation for <%#> finished. "
#"status code: %d, error: %#, data size: %u",
_url, _statusCode, _error, [_data length]);
[_connection release];
_connection = nil;
[self willChangeValueForKey:#"isExecuting"];
[self willChangeValueForKey:#"isFinished"];
_isExecuting = NO;
_isFinished = YES;
[self didChangeValueForKey:#"isExecuting"];
[self didChangeValueForKey:#"isFinished"];
}
#pragma mark -
#pragma mark NSURLConnection delegate
- (void)connection:(NSURLConnection *)connection
didReceiveResponse:(NSURLResponse *)response
{
//[_data release];
//_data = [[NSMutableData alloc] init];
[_data setLength:0];
NSHTTPURLResponse * httpResponse = (NSHTTPURLResponse *)response;
_statusCode = [httpResponse statusCode];
}
- (void)connection:(NSURLConnection *)connection
didReceiveData:(NSData *)data
{
[_data appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// Parse the responseData of json objects retrieved from the service
SBJSON *parser = [[SBJSON alloc] init];
NSString *jsonString = [[NSString alloc] initWithData:_data encoding:NSUTF8StringEncoding];
NSDictionary *jsonData = [parser objectWithString:jsonString error:nil];
NSMutableArray *array = [jsonData objectForKey:#"Children"];
schedulesArray = [NSMutableArray array];
[schedulesArray addObject:array];
// Callback to AttendanceReportViewController that the responseData finished loading
[attendanceReportViewController loadSchedule];
[self finish];
}
- (void)connection:(NSURLConnection *)connection
didFailWithError:(NSError *)error
{
_error = [error copy];
[self finish];
}
#end
When all data is received I want to call back to my ViewController and get an array with all data from all request made.
Create a downloader
Create a downloader class using NSURLConnection.
Keep a member variable called downloaderObjectId.
Write a delegate method for this object. This method will pass the downloaded data and downloaderObjectId back to the delegate.
In the delegate.
Create multiple downloader objects(As per your ncessity) with unique value for the downloaderObjectId.
Store these objects in a NSMutableDictionary
Key for each object will be downloaderObjectId. so that when the delegate method is called after download you take the exact object back from the NSMutableDictionary using this key.
Main point.
Each time delegate is called. You should remove the object from dictionary(The object who is done with the download and called his delgate. You can identify this object by the key downloaderObjectId he holds. )
Then check the count of dictionary. If it is zero you can make sure that your downloads are completed. So you can call your viewcontroller.

Help...didReceiveResponse is not called

Grettings to you everybody!
Here me still finding problem with implementing storekit framework.
When i run the code on my device, it sends the request but the didReceiveResponse is not getting called.am i doing wrong in my code?
Please guide me up...Thanks for any help
- (void)viewDidLoad
{
NSLog(#"View is loaded");
[self requestProductData];
if ([SKPaymentQueue canMakePayments])
{
NSLog(#"can make payments");
}
else
{
NSLog(#"cannot make payments");
}
[super viewDidLoad];
}
- (void) requestProductData
{
NSSet *productIDs = [NSSet setWithObjects:#"com.mycompany.inapppurchasetesting.productid", nil];
SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:productIDs];
request.delegate = self;
NSLog(#"Requesting");
[request start];
}
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
NSArray *myProduct = response.products;
NSArray *myInvalidProducts = response.invalidProductIdentifiers;
NSLog(#"Did recieve response");
NSLog(#"Response count is %d",response.products.count);
NSLog(#"Invalid response count is %d",response.invalidProductIdentifiers.count);
for (int i = 0; i<myProduct.count; i++)
{
NSLog(#"t:%#",[[myProduct objectAtIndex:i] localizedTitle]);
}
for(int i = 0; i < myInvalidProducts.count; i++)
{
NSLog(#"Invalid products:%#",[myInvalidProducts objectAtIndex:i]);
}
// populate UI
[request autorelease];
}
You seem to have some memory management bugs in this code, but I don't see a problem with it that would prevent the delegate from being called.
If I recall correctly, StoreKit may not fully work on the simulator. Have you tried this on the device?
Also, per this SO question, you can add a callback for errors to help diagnose your issue, like so:
- (void) request:(SKRequest *)request didFailWithError:(NSError *)error {
NSString *errorMessage = [error localizedDescription];
[self notifyUserInterfaceOfError:errorMessage];
}