productsRequest response method is not calling - iphone

I am implementing an in app purchase and I am sending the request to apple store through
- (void) requestProductData
{
SKProductsRequest *request= [[SKProductsRequest alloc] initWithProductIdentifiers:
[NSSet setWithObjects: featureAId,featureBId,nil]]; // add any other product here
request.delegate = self;
[request start];
}
the response method
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
[purchasableObjects addObjectsFromArray:response.products];
}
is not getting called at all. Only once did it call out of ten attempts I tried.

Try to implement also - (void)request:(SKRequest *)request didFailWithError:(NSError *)error method - may be there're some errors in processing of your requests.

I faced the same problem, but in my case the cause was that I was using Automatic Reference Counting and I forgot to retain the request.
My code was like:
- (void) requestProductData
{
SKProductsRequest *request= [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObject:ProductIdentifier]];
request.delegate = self;
[request start];
}
But delegate's productsRequest:didReceiveResponse: never got called.
A fix would be:
#property (strong, nonatomic) SKProductsRequest *request;
- (void) requestProductData
{
self.request= [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObject:ProductIdentifier]];
self.request.delegate = self;
[self.request start];
// you can nil request property in request:didFailWithError: and requestDidFinish:
}

I had the same problem. I had created a helper class to handle the IAP and check for the products. What I finally found was the instance of the class I created was being released before the response came back, thus the delegate methods never got called because they did not exist anymore.
I solved my problem by retaining the instance of the helper class in the class I called it from using #proprty(strong, nonatomic)...
If you are not using a helper class and coding it into an existing class then the answer above will work by retaining your SKProductRequest.

I've had a similar problem (error: Cannot connect to iTunes Store). After upgrading iTunes Beta to the latest version it started working again.

Related

EXC_BAD_ACCESS error with RestKit in didReceiveResponse method

I can't get rid of a EXC_BAD_ACCESS error in RestKit. I suspect its because I have an ARC project and may be releasing the request or response variable too many times, but I've spent hours on this and am not sure.
My problem sounds similar to this post, but I'm not sure where in my code to make a similar change.
My implementation file has a straightforward method to post the new object to the server. All the mapping logic is down within the implementation file for the NSObject below:
-(void) createMeeting
{
NSString* baseUrl = #"https://myapp.appspot.com/api/meeting/?format=json&username=testuser#test.com&api_key=f8s9df8as8df9s8d97";
RKObjectManager* rkoManager = [RKObjectManager objectManagerWithBaseURLString:baseUrl]; [NewMeetingRK initMap:rkoManager];
NewMeetingRK *newmtg = [NewMeetingRK alloc];
newmtg.leader = self.leaderEmail.text;
newmtg.startdate = [sqliteformatter stringFromDate:bdate];
newmtg.enddate = [sqliteformatter stringFromDate:edate];
[[RKObjectManager sharedManager] postObject:newmtg delegate:self];
And it successfully begins requestDidStartLoad:(RKRequest *)request
However it then crashes in RKResponse.m on the second to last line below (if ([[_request delegate] respondsToSelector:... with a EXC_BAD_ACCESS error.
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse *)response {
RKResponseIgnoreDelegateIfCancelled();
RKLogDebug(#"NSHTTPURLResponse Status Code: %ld", (long) [response statusCode]);
RKLogDebug(#"Headers: %#", [response allHeaderFields]);
_httpURLResponse = [response retain];
[_request invalidateTimeoutTimer];
if ([[_request delegate] respondsToSelector:#selector(request:didReceiveResponse:)]) {
[[_request delegate] request:_request didReceiveResponse:self];
}
}
Any ideas to help me? Thanks much.
EXC_BAD_ACCESS happens when a message is sent to an object that has been released.
You should pay attention to _request delegate object. NSZombieEnabled break point might help you too. How to enable zombie objects

StoreKit delegate functions are not getting called

I wanted help from you guys. I have implemented the storekit code in my iPhone/iPad app and I am testing the application on iPad 1 with iOS 3.2.
I tried to test the application after performing all the steps like adding the products in for an application in iTunes connect and using provisioning profile to run that app on my iPad but when i run the application Storekit delegate functions are never called neither it gives any error and it never crashes. I can't figure out what is the problem.
Please help me to resolve this.
Below is the code which i have used
- (void) requestProductData
{
SKProductsRequest *request= [[SKProductsRequest alloc]
initWithProductIdentifiers: [NSSet setWithObject:#"myproductid"]];
request.delegate = self;
[request start];
}
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:
(SKProductsResponse *)response
{
NSArray *myProduct = response.products;
// populate UI
[request autorelease];
}
- (void) request:(SKRequest *)request didFailWithError:(NSError *)error {
NSString *errorMessage = [error localizedDescription];
NSLog(#"%#",errorMessage);
}
- (void)requestDidFinish:(SKRequest *)request{
NSLog(#"%#",#"inside request finish");
}
I call the requestProductData but none of the delegate function is called.
Thanks so much in advance!
I figure this is a bit late and you would of solved it by now, but I am trying to resolve another issue, came across your question and was wondering if you had the delegates in your interface file.
#import <UIKit/UIKit.h>
#import <StoreKit/StoreKit.h>
#interface ViewController : UIViewController<SKProductsRequestDelegate, SKRequestDelegate, SKPaymentTransactionObserver>
#end
I suspect you did have the above code and as said solve it, but just in case someone else has the same issue and has forgotten to include the delegates in the h file.

Realising object dynamically

I have a connection class that uses NSURLConnection to connect to the server. While in main class I call a class method of this class, the class method then allocates instance of itself and when the delegate ConnectionDidFinish is received, I release same class from within. Is this approach correct or this will lead to some problem.
Main Class :
[ConnectionClass connectToServer];
Connection Class :
#implementation ConnectionClass
+(void)connectToServer{
connectionClass = [[ConnectionClass alloc] init];
[connectionClass createConnection];
}
-(void)createConnection{
NSURLConnection *connection = [[NSURLConnection alloc] initWithDelegate:self];
// create asynchronous connection
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection{
[self release];
}
#end
Is it good to release self within its own method ?
What if I do it something this way;
Main Class :
[connectionClass setDelegate:self];
[connectionClass connectToServer];
Connection Class :
#implementation ConnectionClass
-(void)connectToServer{
[connectionClass createConnection];
}
-(void)createConnection{
NSURLConnection *connection = [[NSURLConnection alloc] initWithDelegate:self];
// create asynchronous connection
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection{
[self.delegate finishedConnection:self]; // added delegate and then called to the main class and pass the self object for main to release it
}
#end
And in the main class delegate we, release the object,
-(void)finishedConnection:(ConnectionClass*)connection
{
[connection release];
}
IS there any problem in releasing the object this way ?
[self release] & [self retain] sound totally crazy to me. It makes no sense at all IMHO.
And I don't see the point of making (void)connectToServer a class method !
Your second way is the way to go. You could also make one step of the two, creating a method like :
[connectionClass connectToServerWithDelegate:self];
I would do this:
#implementation ConnectionClass
+ (void)connectToServer {
connectionClass = [[ConnectionClass alloc] init];
[connectionClass createConnection];
[connectionClass release];
}
- (void)createConnection {
[self retain];
NSURLConnection *connection = [[NSURLConnection alloc] initWithDelegate:self];
// create asynchronous connection
[connection release];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[self release];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
[self release];
}
#end
That way the ConnectionClass object is self retaining, and you're not putting the retain/release responsibility in different places of code, that are not tightly related.
Edit: As Rabskatran points out, if you're just learning about retain/release, then this is not the optimal solution.
Your second example with the delegate is better. I'd let the connectionClass object be an instance variable, so you can message the connection object to cancel the operation when the main class (which would be the connection's delegate) gets deallocated.

How to make NSURLConnection file download work?

I have a ViewController declared as:
#interface DownloadViewController : UIViewController
<UITableViewDataSource, UITableViewDelegate>
and I want to use NSURLConnection to download files. NSURLConnection simply "doesn't start", the delegate methods don't work (for example connection:didReceiveResponse is never called) . I noticed in some sample code that the class was subclassing NSObject instead of UIViewController.
How do I combine it? I want to use ViewController methods but then I can't use NSURLConnection.
It's not so easy to find a fully explained example how to download file with NSURLConnection. Everyone only concentrates on the easy methods like didReceiveResponse.
Using a UIViewController instead of an NSObject should not be your problem here !
I'm using a NSURLConnection in an UIViewController with no issue !
Here is a part of my code (not sure it will compile as it is) :
//
// MyViewController.h
//
#import <Foundation/Foundation.h>
#interface MyViewController : UIViewController {
#protected
NSMutableURLRequest* req;
NSMutableData* _responseData;
NSURLConnection* nzbConnection;
}
- (void)loadFileAtURL:(NSURL *)url;
#end
-
//
// MyViewController.m
//
#import "MyViewController.h"
#implementation MyViewController
- (void)loadView {
// create your view here
}
- (void) dealloc {
[_responseData release];
[super dealloc];
}
#pragma mark -
- (void)loadFileAtURL:(NSURL *)url {
// allocate data buffer
_responseData = [[NSMutableData alloc] init];
// create URLRequest
req = [[NSMutableURLRequest alloc] init];
[req setURL:_urlToHandle];
nzbConnection = [[NSURLConnection alloc] initWithRequest:req delegate:self startImmediately:YES];
[req release];
req = nil;
}
#pragma mark -
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
// Append data in the reception buffer
if (connection == nzbConnection)
[_responseData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
if (connection == nzbConnection) {
[nzbConnection release];
nzbConnection = nil;
// Print received data
NSLog(#"%#",_responseData);
[_responseData release];
}
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
// Something went wrong ...
if (connection == nzbConnection) {
[nzbConnection release];
[_responseData release];
}
}
#end
If you plan to download large files, consider storing the received packets in a file instead of storing it in memory !
If you're having problems, you could consider using the well regarded ASIHTTPRequest library to manage your download. It takes care of everything for you.
For example, just 2 lines will do it.
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setDownloadDestinationPath:fullPathOfWhereToStoreFile];
Use "NSURLConnection asynchronously" search for the term and you'll find source. Or just NSURLConnection.
For example:
NSURLConnection NSURLRequest proxy for asynchronous web service calls
Using NSURLConnection from apple with example code
Objective-C Programming Tutorial – Creating A Twitter Client Part 1

How to return an object from a class that uses NSURLConnection and it's delegate classes?

I'm in the process of trying to move code from a UITableViewController class to a "helper" class.
The code utilizes NSURLConnection to grab and parse JSON and then populate an NSMutableArray.
What I'd like to do is call a method in my helper class that returns a NSMutableArray. What I don't understand is how to return the array from the connectionDidFinishLoading delegate class of NSURLConnection (where the array is actually built) as though it was from the originally called method that started the connection. In other words, how does the method that calls NSURLConnection get control back so it can return a value from the whole operation?
Here are the relevant methods from the helper class. How do I get the getMovies method to return the listOfMovies that is built in the connectionDidFinishLoading delegate class?
-(NSMutableArray)getMovies:(NSURL*)url {
responseData = [[NSMutableData data] retain];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
//NSURLRequest* request = [NSURLRequest requestWithURL: url cachePolicy: NSURLRequestUseProtocolCachePolicy timeoutInterval: 30.0];
connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
}
- (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 {
//TODO error handling for connection
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
//---initialize the array---
listOfMovies = [[NSMutableArray alloc] init];
tmdbMovies = [[NSArray alloc] init];
posters = [[NSArray alloc] init];
thumbs = [[NSDictionary alloc] init];
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
SBJsonParser *json = [[SBJsonParser new] autorelease];
tmdbMovies = [json objectWithString:responseString];
// loop through all the top level elements in JSON
for (id movie in tmdbMovies) {
// 0 - Name
// 1 - Meta
// 2 - Url
if ((NSNull *)[movie objectForKey:#"name"] != [NSNull null]) {
if (![[movie objectForKey:#"name"] isEqualToString:#""]) {
name = [movie objectForKey:#"name"];
}
}
if ((NSNull *)[movie objectForKey:#"info"] != [NSNull null]) {
if (![[movie objectForKey:#"info"] isEqualToString:#""]) {
meta = [movie objectForKey:#"info"];
}
}
if ((NSNull *)[movie objectForKey:#"thumb"] != [NSNull null]) {
if (![[movie objectForKey:#"thumb"] isEqualToString:#""]) {
thumbUrl = [movie objectForKey:#"thumb"];
}
}
NSLog(#"Name: %#", name);
NSLog(#"Info: %#", meta);
NSLog(#"Thumb: %#", thumbUrl);
NSMutableArray *movieData = [[NSMutableArray alloc] initWithObjects:name,meta,thumbUrl,nil];
// add movieData array to listOfJMovies array
[listOfMovies addObject:movieData];
[movieData release];
}
//FIXME: Connection warning
if (connection!=nil) {
[connection release];
}
[responseData release];
[responseString release];
}
What you really need to do here is create a #protocol that creates a delegate for your helper class. Then change -(NSMutableArray)getMovies:(NSURL*)url to -(void)getMovies:(NSURL*)url
The class that is calling your helper method needs to implement your helper method's delegate.
Then - (void)connectionDidFinishLoading:(NSURLConnection *)connection calls the delegate method(s). It's best to have a one for success and one for failure.
=Update Begin=
You will need to also define an id delegate in your helper file which the calling class sets to self after init but before calling -(void)getMovies:(NSURL*)url. That way the helper file knows where to call back to.
getMovies *movieListCall = [[getMovies alloc] init];
movieListCall.delegate = self;
[movieListCall getMovies:<your NSURL goes here>];
You will see some additional lines for the inclusion of a delegate in both the getMovies.h and getMovies.m files.
=Update End=
in your getMovies.h file add:
#protocol getMoviesDelegate
#required
- (void)getMoviesSucceeded:(NSMutableArray *)movieArray;
- (void)getMoviesFailed:(NSString *)failedMessage;
#end
#interface getMovies : NSOBject {
id delegate;
}
#property (nonatomic, assign) id delegate;
in your getMovies.m file add:
#synthesize delegate;
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
//TODO error handling for connection
if ([delegate respondsToSelector:#selector(getMoviesFailed:)]) {
[delegate getMoviesFailed:[error localizedDescription]];
}
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
//finishes with
if ([delegate respondsToSelector:#selector(getMoviesSucceeded:)]) {
[delegate getMoviesSucceeded:listOfMovies];
}
}
update your calling class .h file to use getMoviesDelegate:
#interface MoviesView : UIViewController <getMoviesDelegate>{
.
.
.
}
add the getMoviesDelegate methods to your calling class .m file
- (void)getMoviesSucceeded:(NSMutableArray *)movieArray {
//deal with movieArray here
}
- (void)getMoviesFailed:(NSString *)failedMessage {
//deal with failure here
}
This is not tested but hopefully gives you a road map to work with.
Protocols are nice because you can make both required and optional delegate methods and it helps in refining your helper methods to become very reusable across projects. The compiler will also warn you if you have implemented a protocol but not implemented the protocol's required delegate methods. If you follow this path be sure to use conformsToProtocol: and respondsToSelector:
Fundamentally, what's happening is that you're starting an asynchronous network load (asynchronous is the right way to do this, almost assuredly), and then you need some way to resume whatever operation you were doing before the load began. You have a few options:
Create your own delegate protocol. Your UITableViewController would then set itself as the helper's delegate, and the helper would call helperDidLoad or whatever you named that method. There's more information on writing delegates in the Cocoa Programming Guide.
Use blocks and continuation passing style. This is a bit more advanced but I like it. In your UITableViewController you'd write something like this:
[helper doSomething:^ (id loaded) {
[modelObject refresh:loaded]; // or whatever you need to do
}];
And then in your helper you'd write:
- (void)doSomething:(void ^ (id))continuation {
_continuation = continuation;
//kick off network load
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
_continuation(_data);
}
Use notifications. Read the NSNotificationCenter docs.
Use KVO. The KVO programming guide has a lot of good info on Key-Value Observing.
How to i get the getMovies method to return the listOfMovies that is built in the connectionDidFinishLoading delegate class?
I'm going to argue that you should not do that.
Network requests should be made asynchronously. If your getMovies were to make a synchronous request and return only when it had data you would block that entire thread while you waiting for a network connection to finish. This is a bad idea in general and a terrible idea if your main thread is calling getMovies. Blocking the main thread will prevent you from responding to touches or updating the UI, your app will appear frozen, and the OS will terminate it if your users don't quit in frustration first.
Instead have the helper class notify the caller when data is available (or when it failed to retrieve data) through a delegate call back, notification, KVO, or whatever mechanism you prefer.
Here are the steps, pseudocode like style:
[helperInstance setDelegate:self]; // where self is your UITableViewController class
in your helper class, in the connectionDidFinishLoading do something like this:
[delegate finishedLoadingData:JSONData];
Also you can define a protocol for your delegate, and the declare the delegate like this in your helper class:
#property (nonatomic, assign) id<YourProtocol> delegate;
Hope this helps,
Moszi