我正在为UIAlertView
创建一个包装器(我知道UIAlertController
和几个已经存在的包装器,这也是出于教育目的(。
假设它看起来像这样(非常缩短的版本(:
@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
例如,我像这样使用它:
// USAGE (inside some ViewController)
-(void)showMyAlert {
dispatch_async(dispatch_get_main_queue(), ^{
MYAlertView *myAlertView = [[MYAlertView alloc] init];
[myAlertView show];
});
}
我遇到的问题如下:
-
[myAlertView show]
会导致出现alertView
。myAlertView
设置为alertView
的委托。 - 唯一强引用
myAlertView
:在showMyAlert
方法中的块内。完成后,myAlertView
被解除分配。 - 当用户单击
alertView
上的按钮时,alertView
调用它的委托方法,但委托(myAlertView
(已经被释放,所以它会导致BAD_ACCESS(UIAlertView
中的委托被声明为assign
,而不是weak
(。
我想使MYAlertView
像UIAlertView
一样易于使用,所以我不想让用户在某处存储对它的强烈引用(这很不方便(。
所以,只要以某种方式显示alertView
,我就必须保持myAlertView
的活力。问题是除了在MyAlertView
内部创建一个强大的引用,当我显示alertView
时将其分配给self
,并在我关闭它时将其分配给nil
之外,我想不出任何其他方法。
像这样(只有更改的位(:
@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
它应该有效:当alertView
被关闭时,strongSelfReference
将被设置为nil
,将没有对myAlertView
的强引用,并且它将被释放(理论上(。
但是,像这样强烈地提及self
对我来说是邪恶的。有没有更好的方法?
更新:实际上MYAlertView
是围绕现已弃用的UIAlertView
和新UIAlertController
(iOS 8+(的抽象层,因此无法选择UIAlertView
子类化。
是的,您的对象应该保持对自身的强引用。这样做并不邪恶。
自我参照(或者,一般来说,任何参照循环(本质上并不是邪恶的。 邪恶在于无意中创造一个,以至于它永远不会被破坏,从而泄漏物体。 你没有那样做。
我觉得这里的答案是将MYAlertView
实际实现为UIAlertView
的子类,而不是漂浮在以太中的对象。只要您的内部UIAlertView
经常停留,它就会一直存在。
@interface MYAlertView : UIAlertView
@end
@implementation MYAlertView
- (instancetype)init {
if (self = [super initWithTitle:@"Some title"
message:@"Some message"
delegate:self
cancelButtonTitle:@"Cancel"
otherButtonTitles:nil]) {
// Other setup?
}
return self;
}
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
// Respond.
}
@end
更新:您应该改为为UIAlertViewController
创建一个iOS7类比。
@interface MyAlertViewController : UIViewController <UIAlertViewDelegate>
+ (id)makeMeOne;
@end
@implementation MyAlertViewController
- (void)viewDidAppear:(BOOL)animated {
UIAlertView *alert = [[UIAlertView alloc] init..];
[alert show];
}
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
// Respond.
[self.navigationController popViewControllerAnimated:NO];
}
+ (id)makeMeOne {
if (iOS7) {
return [[self alloc] init];
} else {
return [[UIAlertViewController alloc] init];
}
}
@end
填写设置的空白。
在我看来,这是设计不佳的指标。
如果您正在为两个iOS版本创建一个包装器,则最好为镜像相关消除操作的MYAlertView
公开一个委托(否则您将无法对回调和比此包装器更进一步的操作(。
如果你保留了对自己的强引用,而没有向你包装的类添加任何实际值,也许最好写一个包装器,接受一个块在完成时回调?至少通过这种方式,您可以监视用户的操作,并让调用方指定警报的相关时间。
毕竟,如果您通过授权,那么问题就会以可读的方式解决吗?