I'm creating a wrapper for UIAlertView
(I know about UIAlertController
and about several already existing wrappers, it's also for educational purposes).
Suppose it looks like this (very shortened version):
@interface MYAlertView : NSObject
-(void)show;
@end
@interface MYAlertView()<UIAlertViewDelegate>
@end
@implementation MYAlertView
-(void)show {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Some title"
message:@"Some message"
delegate:self
cancelButtonTitle:@"Cancel"
otherButtonTitles:nil];
[alertView show]
}
#pragma mark UIAlertViewDelegate implementation
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
//Do something.
}
@end
And, for instance, I use it like this:
// USAGE (inside some ViewController)
-(void)showMyAlert {
dispatch_async(dispatch_get_main_queue(), ^{
MYAlertView *myAlertView = [[MYAlertView alloc] init];
[myAlertView show];
});
}
The problem I have is the following:
[myAlertView show]
causes the alertView
to appear. myAlertView
is set as a delegate of the alertView
.myAlertView
: inside the block in the showMyAlert
method. When it's finished, myAlertView
is deallocated.alertView
, the alertView
calls it's delegate method, but the delegate (myAlertView
) is deallocated already, so it causes BAD_ACCESS (the delegate in UIAlertView
is declared as assign
, not weak
).I want to make MYAlertView
as easy to use as it is with UIAlertView
, so I don't want to make the user store a strong reference to it somewhere (it is inconvenient).
So, I have to keep the myAlertView
alive as long as the alertView
is shown somehow. The problem is I can't think of any way other than creating a strong reference inside MyAlertView
, assigning it to self
, when I show the alertView
, and assigning it to nil
, when I dismiss it.
Like so (only the changed bits):
@interface MYAlertView()<UIAlertViewDelegate>
//ADDED:
@property (nonatomic, strong) id strongSelfReference;
@end
@implementation MYAlertView
-(void)show {
UIAlertView *alertView = [[UIAlertView alloc] init /*shortened*/];
[alertView show]
//ADDED:
self.strongSelfReference = self;
}
#pragma mark UIAlertViewDelegate implementation
//ADDED:
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
self.strongSelfReference = nil;
}
@end
It should work: the moment the alertView
is dismissed, the strongSelfReference
will be set to nil
, there will be no strong references left to the myAlertView
, and it will get deallocated (in theory).
But keeping a strong reference to self
like this looks evil to me. Is there a better way?
UPDATE: The MYAlertView
in reality is an abstraction layer around the now deprecated UIAlertView
and a new UIAlertController
(iOS 8+), so subclassing UIAlertView
is not an option.
Yes, your object should keep a strong reference to itself. It's not evil to do so.
A self-reference (or, in general, any reference cycle) is not inherently evil. The evil comes in creating one unintentionally such that it is never broken, and thus leaks objects. You're not doing that.