EXC_BAD_ACCESS when trying to deserialize a subclass object from AFHTTPClient - objective-c

I have a subclass of AFHTTPClient with NSCoding protocol methods implemented:
- (id)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (!self)
return nil;
self.isLoggedIn = [aDecoder decodeBoolForKey:#"isLoggedIn"];
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder {
[super encodeWithCoder:aCoder];
[aCoder encodeBool:self.isLoggedIn forKey:#"isLoggedIn"];
}
I also implemented the method for setting default header for the token & there I archive the client:
- (void)setAuthorizationHeaderWithToken:(NSString *)token {
[self setDefaultHeader:#"Authorization" value:[NSString stringWithFormat:#"OAuth %#", token]];
[self setIsLoggedIn:YES];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self];
[[NSUserDefaults standardUserDefaults] setObject:data forKey:kGCClient];
[[NSUserDefaults standardUserDefaults] synchronize];
}
And I deserialize the client in the - (id)initWithBaseURL:(NSURL *)url implementation in my subclass:
- (id)initWithBaseURL:(NSURL *)url {
NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:kGCClient];
GCClient *client = [NSKeyedUnarchiver unarchiveObjectWithData:data];
if (client)
return self = client;
self = [super initWithBaseURL:url];
if (!self) {
return nil;
}
[self setIsLoggedIn:NO];
return self;
}
The issue is that once I'm logged in, the next time I open the app it crushes on the deserialization of the client, in the AFHTTPClient class - (id)initWithCoder:(NSCoder *)aDecoder method, on the first try to decode a object & in debugger it says that the value returned is not an Objective-C object.
NSURL *baseURL = [aDecoder decodeObjectForKey:#"baseURL"];

Two things:
Use the Keychain, rather than NSUserDefaults, to store credentials.
Instead of messing with NSCoding, simply override -initWithBaseURL, (making sure to call super, of course), and set the Authorization header based on the value stored in the keychain (if it exists). The isLoggedIn property could (and should) be defined as a derived readonly property, which returns YES when the Authorization header is present, and NO otherwise.

Related

Loading data once the data is in array

[array addObject:textdata.text];
NSUserDefaults *save = [NSUserDefaults standardUserDefaults];
[save setObject:array forKey:#"success" ];
[save synchronize];
-(void) viewDidLoad
NSUserDefaults *viewdata1 = [NSUserDefaults standardUserDefaults];
[viewdata1 objectForKey:#"success"];
[viewdata1 synchronize];
[tabledata reloadData];
Once the data is saved in the array, how do I upload it once the app runs again? I want the data to load back in the table once.
The first step is to retrieve it from user defaults. The second step is not to drop it on the floor.
[viewdata1 objectForKey:#"success"];
This does one, but not the other: You retrieve it, but then you drop it on the floor.
You need to store the object as the value of a property (which means you will need to declare a property for that purpose), then, in your table view's data source, return the count of that array as your number of rows and objects in the array (or properties of those objects) as the row values.
Also, you shouldn't need to call synchronize, especially after retrieving the value.
You should make like this:
TSTableViewController.h:
#property(nonatomic, readwrite, retain) NSMutableArray* dataSource;
TSTableViewController.m:
- (id) init
{
if ((self = [super init]))
{
[[NSNotificationCenter defaultCenter] addObserver: self selector: #selector(applicationDidEnterBackground:)
name: UIApplicationDidEnterBackgroundNotification
object: nil];
}
return self;
}
- (void) applicationDidEnterBackground: (NSNotification*) notification
{
[[NSUserDefaults standardUserDefaults] setObject: self.dataSource
forKey: #"success" ];
}
- (void) viewDidLoad
{
[super viewDidLoad];
NSArray* array = [[NSUserDefaults standardUserDefaults] objectForKey: #"success"];
if (array)
{
self.dataSource = [NSMutableArray arrayWithArray: array];
}
else
{
self.dataSource = [[[NSMutableArray alloc] init] autorelease];
}
[tableView reloadData];
}
- (void) addDataToDataSource
{
[self.dataSource addObject: textdata.text];
[tabledata reloadData];
}
- (void) dealloc
{
[dataSource release];
dataSource = nil;
[super dealloc];
}

NSUserDefaults unable to save and read my custom objects

I have a class Notification that implements the NSCoding protocol.
I have an array of notifications.I am trying to save the notifications with NSUserDefaults.In my app delegate notifications is a NSMutableArray that contains the Notification objects.That's my app delegate:
+ (void) initialize
{
NSUserDefaults* defaults=[NSUserDefaults standardUserDefaults];
[defaults registerDefaults: [NSDictionary dictionaryWithObject: [NSKeyedArchiver archivedDataWithRootObject: [NSArray array]] forKey: #"notificationsData"]];
}
- (id) init
{
self=[super init];
if(self)
{
NSUserDefaults* defaults=[NSUserDefaults standardUserDefaults];
NSData* notificationsData=[defaults objectForKey: #"notificationsData"];
notifications= [[NSKeyedUnarchiver unarchiveObjectWithData: notificationsData]mutableCopy];
}
return self;
}
- (void) applicationWillTerminate:(NSNotification *)notification
{
NSUserDefaults* defaults=[NSUserDefaults standardUserDefaults];
NSData* notificationsData=[NSKeyedArchiver archivedDataWithRootObject: notifications];
[defaults setObject: notificationsData forKey: #"notificationsData"];
}
In the Notification class text and title are of type NSString (both readwrite), and date is of type NSDate (also this has readwrite property).This is how I implement the NSCoding protocol:
- (void) encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeObject: date forKey: #"date"];
[aCoder encodeObject: title forKey: #"title"];
[aCoder encodeObject: text forKey: #"text"];
}
- (id) initWithCoder:(NSCoder *)aDecoder
{
self=[super init];
if(self)
{
date=[aDecoder decodeObjectForKey: #"data"];
title=[aDecoder decodeObjectForKey: #"title"];
text=[aDecoder decodeObjectForKey: #"text"];
}
return self;
}
So I have these problems:
When the application terminates I get EXC_BAD_ACCESS in the
Notification class, when I try to encode text with NSKeyedArchiver;
The notifications aren't saved and the array is always long zero
when the application starts.
Update: With more debug I discovered where the application crashes.There is more code to see (I'm using a table view to display the data):
- (NSInteger) numberOfRowsInTableView:(NSTableView *)tableView
{
return [notifications count];
}
- (id) tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
// Debug
id obj=[[notifications objectAtIndex: row] valueForKey: [tableColumn identifier]];
Class class=[obj class];
// What you see above is just for debug purposes
return [[notifications objectAtIndex: row] valueForKey: [tableColumn identifier]];
}
- (void) tableViewSelectionDidChange:(NSNotification *)notification
{
NSInteger row=[tableView selectedRow];
if(row >= 0 && row< [notifications count])
[removeButton setEnabled: YES];
else
[removeButton setEnabled: NO];
}
The last method called is this:
- (id) tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row;
Probably the problem is that the data is somehow corrupted and the value returned by this method is not valid.Anyway the app doesn't crash in this method, but after this method.
If I load two objects from user defaults, only one object gets loaded before crashing (so the method gets called once).
However I'm still unable to get the real reason of the crash.
More code:
- (IBAction) addNotification :(id)sender
{
Notification* notification=[[Notification alloc]init];
[notification setDate: [datePicker dateValue]];
[notification setText: [textView string]];
[notifications addObject: notification];
[tableView reloadData];
}
- (IBAction)removeNotification:(id)sender
{
[notifications removeObjectAtIndex: [tableView selectedRow]];
[tableView reloadData];
}
addNotification and removeNotification are both triggered by buttons.
EDIT: I discovered that I wasn't using ARC, but even if I turn it on the app crashes.
In the line:
date=[aDecoder decodeObjectForKey: #"data"];
#"data" doesn't match the encoder key. You really want:
date=[aDecoder decodeObjectForKey: #"date"];
You might need to call [NSUserDefaults synchronize] since it will not happen automatically when the application suddenly exits:
- (void) applicationWillTerminate:(NSNotification *)notification
{
NSUserDefaults* defaults=[NSUserDefaults standardUserDefaults];
NSData* notificationsData=[NSKeyedArchiver archivedDataWithRootObject: notifications];
[defaults setObject: notificationsData forKey: #"notificationsData"];
[defaults synchronize];
}
You couldn't guess what was wrong: my bad, I forgot to enable ARC and some objects were released when they shouldn't.

How to store CCSprite in NSUserDefault

I have a strange problem while working with CCSprite subclass Creature.
Lets,my object is Creature* creature;
The class Creature declaration-
#interface Creature : CCSprite <NSCoding>{
int creatureAge;
NSString *creatureName;
}
Implementation
+(id)initializeCreatureWithType:(int)type
{
Creature *creature = nil;
creature = [[[super alloc] initWithFile:[NSString stringWithFormat:#"ch%i_default.png",type]]autorelease];
return creature;
}
The problem is when i store my Creature class object 'creature' in NSUserDefault using-
- (void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:self.creatureName forKey:#"creatureName"];
[encoder encodeInt:self.creatureAge forKey:#"creatureAge"];
}
And the decode it with-
- (id)initWithCoder:(NSCoder *)decoder {
if((self = [super init])) {
self.creatureName = [decoder decodeObjectForKey:#"creatureName"];
self.creatureAge= [decoder decodeIntForKey:#"creatureAge"];
}
Then save the creature object using-
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *myEncodedObject = [NSKeyedArchiver archivedDataWithRootObject:creature];
[defaults setObject:myEncodedObject forKey:#"my_pet"];
And the load-
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *myEncodedObject = [defaults objectForKey:#"my_pet"];
Creature* newcreature = (Creature *)[NSKeyedUnarchiver unarchiveObjectWithData: myEncodedObject];
The problem is that when I load this i get the property value of previously stored creature, but the image that is assigned to previous creature perhaps does not copied. Because if i add the newcreature to any CCLayer it does not display any image, though it get the property value of previous creature.
What can I do now to get the newcreature with image? is it needed to add image name as a separate property???
You could simply store the type as well and then do it like this:
#interface Creature : CCSprite {
int creatureType;
int creatureAge;
NSString *creatureName;
}
+ (id)creatureWithType:(int)type;
- (id)initWithCreatureType:(int)type;
#end
#implementation Creature
+ (id)creatureWithType:(int)type
{
return [[[[self class] alloc] initWithCreatureType:type] autorelease];
}
- (id)initWithCreatureType:(int)type
{
self = [super initWithFile:[NSString stringWithFormat:#"ch%i_default.png", type]];
if (!self) return nil;
creatureType = type;
return self;
}
- (id)initWithCoder:(NSCoder *)decoder {
int type = [decoder decodeIntForKey:#"creatureType"];
self = [self initWithCreatureType:type];
if (!self) return nil;
self.creatureName = [decoder decodeObjectForKey:#"creatureName"];
self.creatureAge= [decoder decodeIntForKey:#"creatureAge"];
return self;
}
- (void)encodeWithCoder:(NSCoder *)encoder
{
[encoder encodeInt:creatureType forKey:#"creatureType"];
[encoder encodeObject:self.creatureName forKey:#"creatureName"];
[encoder encodeInt:self.creatureAge forKey:#"creatureAge"];
}
#end
You might want to expose creatureType via a property as well. Note that instead of initializeCreatureWithType: it's "more Cocoa" to use the name creatureWithType:.

Facebook Connect Class with Singleton : Access token issue

I have created a singleton class called "LoginFacebook" which is meant to connect user to Facebook and to perform the different request. The problem is that I get an error about the access_token. Here it is :
3 : <CFString 0x4c552f0 [0xe50400]>{contents = "message"} = <CFString 0x4c55250 [0xe50400]>{contents = "An active access token must be used to query information about the current user."}
First I connect to Facebook by making the following request from another View Controller :
[[LoginFacebook loginFacebook] launchFacebook:self]
Then I make that second request from the same other View Controller but from another method :
[[LoginFacebook loginFacebook] requireName:self]
Here is my singleton class "LoginFacebook" :
LoginFacebook.h :
#import <UIKit/UIKit.h>
#import "LoginFacebook.h"
#interface FirstViewController : UIViewController {
}
-(IBAction)performConnect:(id)sender;
-(IBAction)performName:(id)sender;
#end
LoginFacebook.m :
#import "LoginFacebook.h"
static LoginFacebook *loginFacebook = nil;
#implementation LoginFacebook
#synthesize name;
#synthesize facebook;
-(void)launchFacebook:(id)sender
{
permissions = [[NSArray arrayWithObjects:
#"read_stream", #"publish_stream", #"offline_access",nil] retain];
Facebook* facebookbis = [[Facebook alloc] initWithAppId:#"168938499825684"];
facebook = facebookbis;
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if ([defaults objectForKey:#"FBAccessTokenKey"]
&& [defaults objectForKey:#"FBExpirationDateKey"]) {
facebook.accessToken = [defaults objectForKey:#"FBAccessTokenKey"];
facebook.expirationDate = [defaults objectForKey:#"FBExpirationDateKey"];
}
if (![facebook isSessionValid]) {
[facebook authorize:nil delegate:self];
}
}
-(NSString *)requireName:(id)sender
{
NSLog(#"requireName asked");
[facebook requestWithGraphPath:#"me" andDelegate:self];
return name;
NSLog(#"%#",[facebook accessToken]);
}
+ (LoginFacebook *)loginFacebook
{
if (loginFacebook == nil) {
loginFacebook = [[super allocWithZone:NULL] init];
}
return loginFacebook;
}
+ (id)allocWithZone:(NSZone *)zone {
return [[self loginFacebook] retain];
}
- (id)copyWithZone:(NSZone *)zone {
return self;
}
- (id)retain {
return self;
}
- (NSUInteger)retainCount {
return NSUIntegerMax; //denotes an object that cannot be released
}
- (void)release {
//do nothing
}
- (id)autorelease {
return self;
}
// FBRequestDelegate
/**
* Called when the Facebook API request has returned a response. This callback
* gives you access to the raw response. It's called before
* (void)request:(FBRequest *)request didLoad:(id)result,
* which is passed the parsed response object.
*/
- (void)request:(FBRequest *)request didReceiveResponse:(NSURLResponse *)response {
NSLog(#"received response");
}
/**
* Called when a request returns and its response has been parsed into
* an object. The resulting object may be a dictionary, an array, a string,
* or a number, depending on the format of the API response. If you need access
* to the raw response, use:
*
* (void)request:(FBRequest *)request
* didReceiveResponse:(NSURLResponse *)response
*/
- (void)request:(FBRequest *)request didLoad:(id)result {
if ([result isKindOfClass:[NSArray class]]) {
result = [result objectAtIndex:0];
}
name = [result objectForKey:#"name"];
NSLog(#"request didLoad");
};
/**
* Called when an error prevents the Facebook API request from completing
* successfully.
*/
- (void)request:(FBRequest *)request didFailWithError:(NSError *)error {
name = [error localizedDescription];
NSLog(#"----request didFailWithError");
NSLog(#"%#", [error localizedDescription]);
NSLog(#"%#", [error description]);
};
////////////////////////////////////////////////////////////////////////////////
// FBDialogDelegate
/**
* Called when a UIServer Dialog successfully return.
*/
- (void)dialogDidComplete:(FBDialog *)dialog {
name = #"publish successfully";
}
#end
Please also note that I added the following method (with the corresponding FacebookLogin *facebook in the .h) to my App Delegate :
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
return [facebook handleOpenURL:url];
}
Does one of you know what is going wrong there ? I have been struggling with the code for 2 days now...
From the error message it seems your access token isn't valid anymore or you didn't even have an access token yet. Does your app actually open a web browser the first time a user is trying to access Facebook? If not, then you probably failed to configure the project properly.
Perhaps it'd be a good idea to share the code of my Facebook singleton - I believe the code is pretty clean and easy to understand & expand. Since my needs are currently very modest I only have a method to authorize (login) and another method to post to wall. I'm using a stack so I can perform some operations in the correct order (for example login before posting message to wall, if user isn't logged in yet).
SDFacebookController.h
#import <Foundation/Foundation.h>
#import "FBConnect.h"
#interface SDFacebookController : NSObject
<FBSessionDelegate,
FBRequestDelegate>
#property (nonatomic, retain) Facebook *facebook;
+ (SDFacebookController *)sharedController;
- (void)authorize;
- (void)postMessageToWall:(NSString *)message;
#end
SDFacebookController.m
#import "SDFacebookController.h"
#import "Constants+Macros.h"
#import "SDOperationStack.h"
#interface SDFacebookController ()
#property (nonatomic, retain) SDOperationStack *operationStack;
- (void)performAuthorization;
- (void)performPostMessageToWall:(NSString *)message;
- (void)runOperation;
#end
#implementation SDFacebookController
#synthesize facebook, operationStack;
#pragma mark - Instance methods
- (void)authorize
{
NSInvocationOperation *operation = [[[NSInvocationOperation alloc] initWithTarget:self selector:#selector(performAuthorization) object:nil] autorelease];
[operationStack push:operation];
[self runOperation];
}
- (void)postMessageToWall:(NSString *)message
{
NSInvocationOperation *operation = [[[NSInvocationOperation alloc] initWithTarget:self selector:#selector(performPostMessageToWall:) object:message] autorelease];
[operationStack push:operation];
if (![facebook isSessionValid])
{
NSInvocationOperation *operation = [[[NSInvocationOperation alloc] initWithTarget:self selector:#selector(performAuthorization) object:nil] autorelease];
[operationStack push:operation];
}
[self runOperation];
}
#pragma mark - Private methods
- (void)runOperation
{
NSOperation *operation = [operationStack pop];
[[NSOperationQueue currentQueue] addOperation:operation];
}
- (void)performAuthorization
{
if (![facebook isSessionValid])
{
NSArray *permissions = [NSArray arrayWithObject:#"publish_stream"];
[facebook authorize:permissions delegate:self];
}
}
- (void)performPostMessageToWall:(NSString *)message
{
NSMutableDictionary *params = [NSMutableDictionary dictionaryWithObjectsAndKeys:message, #"message", nil];
[facebook requestWithGraphPath:#"me/feed" andParams:params andHttpMethod:#"POST" andDelegate:self];
}
#pragma mark - FBRequestDelegate
/**
* Called just before the request is sent to the server.
*/
- (void)requestLoading:(FBRequest *)request
{
DLog(#"%#", request);
}
/**
* Called when the server responds and begins to send back data.
*/
- (void)request:(FBRequest *)request didReceiveResponse:(NSURLResponse *)response
{
DLog(#"%# %#", request, response);
}
/**
* Called when an error prevents the request from completing successfully.
*/
- (void)request:(FBRequest *)request didFailWithError:(NSError *)error
{
DLog(#"%# %#", request, error);
[[[[UIAlertView alloc] initWithTitle:NSLocalizedString(#"Error", nil)
message:[error localizedDescription]
delegate:nil
cancelButtonTitle:NSLocalizedString(#"OK", nil)
otherButtonTitles:nil]
autorelease] show];
[operationStack empty];
}
/**
* Called when a request returns and its response has been parsed into
* an object.
*
* The resulting object may be a dictionary, an array, a string, or a number,
* depending on thee format of the API response.
*/
- (void)request:(FBRequest *)request didLoad:(id)result
{
DLog(#"%# %#", request, result);
if ([operationStack isEmpty] == NO)
[self runOperation];
else if ([operationStack.lastOperation.invocation selector] == #selector(performPostMessageToWall:))
[[[[UIAlertView alloc] initWithTitle:NSLocalizedString(#"MessagePosted", nil)
message:NSLocalizedString(#"Successfully posted message on Facebook.", nil)
delegate:nil
cancelButtonTitle:NSLocalizedString(#"OK", nil)
otherButtonTitles:nil]
autorelease] show];
}
/**
* Called when a request returns a response.
*
* The result object is the raw response from the server of type NSData
*/
- (void)request:(FBRequest *)request didLoadRawResponse:(NSData *)data
{
DLog(#"%# %#", request, data);
}
#pragma mark - FBSessionDelegate
/**
* Called when the user successfully logged in.
*/
- (void)fbDidLogin
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:[facebook accessToken] forKey:#"FBAccessTokenKey"];
[defaults setObject:[facebook expirationDate] forKey:#"FBExpirationDateKey"];
[defaults synchronize];
}
/**
* Called when the user dismissed the dialog without logging in.
*/
- (void)fbDidNotLogin:(BOOL)cancelled
{
}
/**
* Called when the user logged out.
*/
- (void)fbDidLogout
{
}
#pragma mark - Memory management
- (id)init
{
self = [super init];
if (self)
{
facebook = [[Facebook alloc] initWithAppId:kFacebookAppIdentifier];
operationStack = [[SDOperationStack alloc] init];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if ([defaults objectForKey:#"FBAccessTokenKey"] && [defaults objectForKey:#"FBExpirationDateKey"])
{
facebook.accessToken = [defaults objectForKey:#"FBAccessTokenKey"];
facebook.expirationDate = [defaults objectForKey:#"FBExpirationDateKey"];
}
}
return self;
}
- (void)dealloc
{
[operationStack release];
[facebook release];
[super dealloc];
}
#pragma mark - Singleton
+ (SDFacebookController *)sharedController
{
static SDFacebookController *controller = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
controller = [[self alloc] init];
});
return controller;
}
#end
SDOperationStack.h
#import <Foundation/Foundation.h>
#interface SDOperationStack : NSObject
#property (nonatomic, retain) NSInvocationOperation *lastOperation;
- (void)push:(NSOperation *)operation;
- (NSOperation *)pop;
- (BOOL)isEmpty;
- (void)empty;
#end
SDOperationStack.m
#import "SDOperationStack.h"
#interface SDOperationStack ()
#property (nonatomic, retain) NSMutableArray *array;
#end
#implementation SDOperationStack
#synthesize array, lastOperation;
- (void)dealloc
{
[lastOperation release];
[array release];
[super dealloc];
}
- (id)init
{
self = [super init];
if (self)
{
array = [[NSMutableArray alloc] init];
}
return self;
}
- (void)push:(NSInvocationOperation *)operation
{
[array addObject:operation];
}
- (NSInvocationOperation *)pop
{
if ([self isEmpty])
return nil;
self.lastOperation = (NSInvocationOperation *)[array lastObject];
[array removeLastObject];
return lastOperation;
}
- (BOOL)isEmpty
{
return [array count] == 0;
}
- (void)empty
{
[array removeAllObjects];
}
#end

Objective C: How to release delegates in this situation

I am using custom delegate objects to do some cleanup tasks after a request finishes. ASIHTTPRequest doesn't retain delegates so I can't autorelease them. Right now this is how I am allocating and releasing the delegates.
App Delegate
MyDelegate *delegate = [[MyDelegate alloc] init];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setDelegate:delegate];
MyDelegate.m
- (void)requestFinished:(ASIHTTPRequest *)request
{
[self release];
}
- (void)requestFailed:(ASIHTTPRequest *)request
{
[self release];
}
Is there a better way to do this? Having the delegates release themselves seems ugly and Xcode's build and analyze feels uncomfortable with what I'm doing.
A simple approach would be to maintain a mutable set of delgates for each active request in your main controller (the app delegate, in this case):
#interface MyAppController
{
NSMutableSet * activeDelegates;
}
#end
#implementation MyAppController
- (id)init
{
if ((self = [super init]) == nil) { return nil; }
activeDelegates = [[NSMutableSet alloc] initWithCapacity:0];
return self;
}
- (void)dealloc
{
[activeDelegates release];
}
- (void)createRequest
{
MyDelegate *delegate = [[MyDelegate alloc] init];
[activeDelegates addObject:delegate];
[delegate release];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setDelegate:self];
...
}
- (void)requestFinished:(ASIHTTPRequest *)request
{
MyDelegate *delegate = [request delegate];
[delegate doSomething];
[activeDelegates removeObject:delegate];
{
- (void)requestFailed:(ASIHTTPRequest *)request
{
[activeDelegates removeObject:[request delegate]];
}
#end
Why do you have a separate class purely to be a delegate? That's not how delegate objects typically work. Normally the controller that created the ASIHTTPRequest becomes the delegate, at which point you don't have to worry about releasing it because it will outlive the ASIHTTPRequest already (and if your controller gets dealloced before the ASIHTTPRequest is done, you need to cancel the request).
If You don't want to create a "controller" class for all your delegate instances, i would still at least follow the memory convention rules, and release the delegate immediately after setting it to asihhtprequest. Then i would include a propery in the delegate, something with a name managesItsOwnLifetime (BOOL) and on setting this to YES i would do a [self retain] ...