ARC自定义委托奇怪的问题

Posted

技术标签:

【中文标题】ARC自定义委托奇怪的问题【英文标题】:ARC custom delegate strange issue 【发布时间】:2013-01-18 15:35:44 【问题描述】:

好的,所以我有一个奇怪的问题,过去几个小时我一直在尝试解决:

我有一个用于 iPad 的简单故事板应用程序,它有两个视图控制器,FirstViewController 是主视图控制器,ModalViewController 出现在 Modal segue 上,它有一个名为 Done 的按钮。 我正在使用 ARC,并且视图控制器被指定用于 iPad。

我还有一个自定义委托UIModalViewControllerDelegate,正如您猜想的那样,它是关闭模式并将数据传递回第一个视图控制器。

UIModalViewControllerDelegate.h

@protocol UIModalViewControllerDelegate <NSObject>
@required
-(void)btnDonePressed:(id)sender Values:(NSArray *)values;
@end

FirstViewController.h

@interface FirstViewController : UIViewController <UIModalViewControllerDelegate>     
@private
    ModalViewController *mvc;

@end

FirstViewController.m

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil

    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) 
// Custom initialization
    
    return self;


- (void)viewDidLoad

    [super viewDidLoad];
    // Do any additional setup after loading the view.


-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender 
    mvc = [segue destinationViewController];
    mvc.delegate = self;


- (void)didReceiveMemoryWarning

    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.


#pragma UIModalViewControllerDelegate

-(void)btnDonePressed:(id)sender Values:(NSArray *)values 
        ...

ModalViewController.h

@interface ModalViewController : UIViewController 
    __weak id<UIModalViewControllerDelegate> delegate;


@property (weak, nonatomic) id<UIModalViewControllerDelegate> delegate;

ModalViewController.m

@implementation ModalViewController

@synthesize delegate;

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil

    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) 
        // Custom initialization
    
    return self;


- (void)viewDidLoad

    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(buttonPressed:)];


-(void) buttonPressed:(id) sender 
    [delegate btnDonePressed:sender Values:values];

现在,有几个非常有趣的问题:

1- 在为 segue 做准备时,在我设置 self.mvc.delegate = self; 后,调试器显示委托仍然为零(!)但是,当我使用 NSLog(@"%@", self.mvc.delegate); 时,我得到的指针地址不是零。

2- 上面的代码不起作用,因为在ModalViewController 中,委托始终为零。因此,[delegate btnDonePressed:sender Values:values]; 永远不会执行。我尝试了所有我知道的可能会导致此问题的方法,但似乎没有任何效果。

3- 我想对委托进行强引用可能会解决此问题,但我不想违反模式并导致保留周期问题。 FirstViewController 中的私有变量ModalViewController *mvc; 是否存在生命周期问题?私有变量何时被取消?顺便说一句,我也尝试用@property (strong, nonatomic) ModalViewController *mvc; 替换它,但没有任何改变。

【问题讨论】:

如果您将委托 ivar 更改为声明为“__weak id delegate;”会发生什么和“@property (weak, nonatomic) id delegate;”?我对委托在 ios 中的工作方式有点生疏,但我相信您必须在为类中的一个属性创建属性时声明您期望的委托类型。 我复制了你的代码,它对我有用(我唯一添加的是 FirstViewController.h 中用于 mvc 的属性——我假设你有这个,因为你使用了 self.mvc)。跨度> @Paul,没有必要添加 ,尽管我认为这样做是个好习惯。 @Paul 是的,你是对的。我最初有id&lt;UIModalViewControllerDelegate&gt;delegate,但由于我在过去几个小时内更改了很多代码,所以我只是在这里复制了错误的版本。但是,这并不能解决问题。 (我更新了上面的代码) @rdelmar 是的,你是对的。我实际上更喜欢使用私有变量(我更新了上面的代码)。因为我不想从我们这边访问它。就生命周期而言,它应该没有任何区别,对吧?我的意思是私有变量与财产 【参考方案1】:

“我只是在这里复制了错误的版本。但是,这并不能解决问题。(我更新了上面的代码)”

既然你提到了复制粘贴。确保原始代码中有一个@synthesize。这个问题看起来像是合成属性与私有变量名称不匹配。

@property (weak, nonatomic) id<UIModalViewControllerDelegate>delegate;

@synthesize 结合声明的属性将使用名为delegate 的私有变量。如果您不小心遗漏了@synthesize,将自动创建一个名为_delegate 的私有变量(注意下划线)。

在您的buttonPressed: 方法中,您可以直接访问私有变量delegate。所以这可能总是返回 nil,因为访问器实际上使用下划线版本。

只是为了确保,要么删除手动声明的变量 delegate,要么在您的 buttonPressed: 方法中使用 self.delegate。看看会发生什么。

【讨论】:

感谢您的回答。这是深思熟虑的。我没有在原始代码中遗漏@synthesize,但它仍然不起作用。如果我删除 __weak id 委托怎么办; ???会有什么不同吗? 无论如何你都可以删除它,它应该是自动生成的。如果删除后出现编译器错误,确实是我的回答中描述的问题,你应该开始在buttonPressed:中使用_delegate【参考方案2】:

感谢大家的回答。我终于找到了解决这个问题的方法。

实际上,代码是完全正确的。问题在于 UINavigationController,其中嵌入了模态视图控制器。

代替

myModalWindowViewController = [segue destinationViewController];
myModalWindowViewController.delegate = self;

我愿意

UINavigationController *navigationController = [segue destinationViewController];
myModalWindowViewController = (MyModalWindowViewController *)[navigationController.viewControllers objectAtIndex:0];
myModalWindowViewController.delegate = self;

我不知道当您选择嵌入在 NavigationController 中的 ViewController 时,DestinationViewController 是 NavigationController 而不是 ViewController。我的错!

【讨论】:

以上是关于ARC自定义委托奇怪的问题的主要内容,如果未能解决你的问题,请参考以下文章

如何处理自定义 UIViewController 委托 (ARC)?

自定义协议委托为零

ARC奇怪的双重释放?

在 ARC 中使用 Blocks 和以某种方式复制的奇怪内存泄漏

为啥委托方法需要将自定义类托管对象上下文的内容保存在委托类托管对象上下文中?

NSMenuItem、自定义视图和 mouseUp 的奇怪问题: