Bhaskar
Bhaskar

Reputation: 5

[AppCommons respondsToSelector:]: message sent to deallocated instance

AppCommons.h

#import <Foundation/Foundation.h>
#import <StoreKit/StoreKit.h>

@interface AppCommons : NSObject <SKProductsRequestDelegate,SKRequestDelegate>
- (void) getInAppPrice : (NSString *) inAppIdentifier;
@end

AppCommons.m

#import "Config.h"
#import "AppCommons.h"
#import "AppDelegate.h"
#import "ASIHTTPRequest.h"
#import "ASIFormDataRequest.h"


@implementation AppCommons
SKProductsRequest *productsRequest;


- (void) getInAppPrice : (NSString *) inAppIdentifier {
    NSSet *productIdentifiers = [NSSet setWithObject:inAppIdentifier ];
    productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers];
    productsRequest.delegate = self;
    [productsRequest start];

    // we will release the request object in the delegate callback
}

#pragma mark -
#pragma mark SKProductsRequestDelegate methods

- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
    for(SKProduct *product in response.products)
    {
        NSLog(@"Product Price : %@",product.price);
                NSLog(@"Product Price Locale : %@",product.priceLocale);
    }
}

@end

This is my class to get the cost of an in app purchase. I am calling getInAppPrice method from another class using the below lines

AppCommons *appCommon = [[AppCommons alloc] init];
[appCommon getInAppPrice:inAppProductIdentifier];

I am getting following error when response is received

"* -[AppCommons respondsToSelector:]: message sent to deallocated instance 0xd4f0580

Please help .. Thank you.

Upvotes: 0

Views: 804

Answers (2)

Putz1103
Putz1103

Reputation: 6211

This is not an answer per se, but an explanation of the reason of the error. The answer given by trojanfoe is absolutely correct, but doesn't exactly explain the situation.

You are calling some function that does:

- (void)myMethod {
    AppCommons *appCommon = [[AppCommons alloc] init];
    [appCommon getInAppPrice:inAppProductIdentifier];
}

Inside this function you call getInAppPrice which creates a new object and set's that new object's delegate as your appCommon. Then that object waits in the background.

Therein lies your problem. While that second object is waiting in the background, your appCommon object gets released because the code gets to the end of the function and releases appCommon. If your SKProductsRequest delegate property were not weak then your appCommon would still have a retain count of 1, but since it is not then your appCommon has a retain count of 0 after your function ends, therefore ARC sees the memory as re-usable and frees the object.

Then you get your response in the background from your SKProductsRequest object. It check's it's delegate pointer (The pointer is still a valid pointer, but it now points to a freed object (or worse, a completely different object)) to see if it responds to the delegate functions. That is when there is a call to a freed object.

So trojanfoe's answer of make the appCommons object a class variable so that it is retianed past the end of your function is the proper answer.retained

Upvotes: 1

trojanfoe
trojanfoe

Reputation: 122401

I suspect you are doing that within the scope of a method, like this:

- (void)myMethod {
    AppCommons *appCommon = [[AppCommons alloc] init];
    [appCommon getInAppPrice:inAppProductIdentifier];
}

which means that appCommon will be destroyed when the method returns.

Instead make an instance variable or property so that the lifetime of the AppCommons object lives past this method call.

MyClass.h:

@class AppCommons;
@interface MyClass : NSObject {
    AppCommons *_appCommons;
}
...
@end

MyClass.m:

#import "MyClass.h"
#import "AppCommons.h"

@implementation MyClass

- (id)init {
    self = [super init];
    if (self) {
        _appCommons = [[AppCommons alloc] init];
    }
    return self;
}

- (void)myMethod {
    [_appCommons getInAppPrice:inAppProductIdentifier];
}

@end

Upvotes: 2

Related Questions