我正在为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
会调用它的委托方法,但委托(UIAlertView
)已经解除分配,因此会导致BAD_ACCESS(委托人) assign
被声明为weak
,而非MYAlertView
)。我希望UIAlertView
与myAlertView
一样易于使用,所以我不想让用户在某处存储强引用(这很不方便)。< / p>
所以,只要alertView
以某种方式显示,我就必须保持MyAlertView
活着。问题是,除了在self
内创建强引用,将其分配给alertView
,当我显示nil
并将其分配给{{1}时,我无法想到任何其他方式当我解雇它时。
像这样(只改变了位):
@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
实际上是now deprecated UIAlertView
和新UIAlertController
(iOS 8+)周围的抽象层,所以子类化UIAlertView
不是一个选项。
答案 0 :(得分:9)
是的,你的对象应该对自己有很强的参考价值。这样做并不邪恶。
自我引用(或者,通常,任何参考周期)本身并不是邪恶的。邪恶来自于无意中创造一个它永远不会被打破,从而泄漏物体。你不是那样做的。
答案 1 :(得分:1)
我觉得这里的答案是实际将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
填写空白以进行设置。
答案 2 :(得分:0)
在我看来,这是一个糟糕设计的指标。
如果您要为两个iOS版本创建一个包装器,那么最好公开一个反映相关解雇操作的MYAlertView
代理(否则您将无法对回调进行操作,而不是这个包装器。)
如果你保持对自己的强引用而不向你要包装的类添加任何实际值,那么编写一个在完成时接受一个块来回调的包装器会更好吗?至少通过这种方式,您可以监控用户的操作,并让呼叫者指示警报的相关时间。
毕竟,如果你传递委托,那么问题就会以可读的方式解决?