iOS - 关于调用者 viewController 的引用

3

我正在一个名为vcA的视图控制器中,现在我需要调用另外一个视图控制器vcB,使用以下代码:

[self presentModalViewController:vcB animated:YES];

一旦vcB被加载,有没有办法获取对vcA的引用?
是的,我知道我可以子类化vcB并向其中添加一个属性。我只是想知道是否有一些本地iOS方法/属性/其他已经做到了这一点。
我在一个导航控制器应用程序上。
谢谢。

你在哪个视图控制器中?是B还是A? - user529758
我在B中,想要一个指向A的引用。 - Duck
最好在这里使用委托,presentModalViewController将指向您的导航控制器。 - alexandresoli
这正是我怀疑的,因为当我尝试访问presentingViewController属性时,我得到了另一个viewController。但是为什么不在B上创建一个类型为id的属性,来存储调用者vc呢? - Duck
一个反对在B上创建属性的论点是它会在A和B之间产生非常紧密的耦合。如果你将该属性创建为id类型,那么你如何在不知道A的类的情况下向其传递信息呢? - Paul Hunter
3个回答

5

如果只是单一的使用且没有太多的协作,我倾向于使用块而不是委托,因为它看起来更整洁。

例如,如果只是在使用secondViewController后回调,我会:

添加一个块属性到SecondViewController中

@property (nonatomic, strong) void (^onCompletion)(void);

然后,在第一个视图控制器中创建第二个视图控制器时,

- (void)showSecondViewController;
{
  SecondViewController *viewController = [[SecondViewController alloc] init];
  viewController.onCompletion = ^{
    [self dismissViewControllerAnimated:YES completion:nil];
  };

  [self presentViewController:viewController
                 animated:YES
               completion:nil];
}

然后,在 secondViewController 中完成后

- (IBAction)doneTapped;
{
  if (self.onCompletion) {
    self.onCompletion();
  }
}

如果您需要返回一个值,只需修改该块以接受一个参数。

哇,你的解释让我大脑短路了...那个 block 属性真是太神奇了。Block 属性?我从来没有意识到我可以将 blocks 用作属性...在 iOS >= 4.3 中我能这样做吗?我正在努力消化你的答案,但由于它来自不同的能量层级,需要一些时间... - Duck
第二个视图控制器(secondVC)在哪里获取对第一个视图控制器(firstVC)的引用? - Duck
在上面的第二个代码块中,我们位于firstViewController中,这是我们创建block的地方。我建议你了解一下blocks,因为听起来你以前没有使用过?在上面的示例中,我通过在block中调用dismissViewControllerAnimated:completion:并且self指向当前对象(即firstViewController)来引用firstViewController。 - Paul.s
是的,我使用块,但这个块作为属性的东西听起来很玄学。 - Duck
让我感到奇怪的是,属性声明通常具有格式@ property(...,...)Class propertyName,而这个块属性违背了这种逻辑... - Duck

2
如果您的部署目标是iOS 5或更高版本,则可能会使用 presentingViewController 属性来实现您的需求。 如果您的部署目标是iOS 4,则可以从 parentViewController 属性中获取所需内容。 否则,您需要定义自己的属性。

是的,parentViewController 是你的好朋友。只需小心:该属性在 iOS5 中仍然存在,但行为不同。请参阅:http://developer.apple.com/library/ios/#documentation/uikit/reference/UIViewController_Class/Reference/Reference.html - Krumelur
这很奇怪,如果我为iOS 6编译并使用presentingViewController,则会给我另一个viewController,而不是呈现该控制器的viewController;如果我为iOS 5编译并使用parentViewController,则会得到nil... - Duck
这就是为什么我使用了“或许”和“可能”等含糊词汇。 :) 听起来你需要定义自己的属性。 - rob mayoff

1
我建议使用委托。您在vcB上声明一个属性,并将vcA设置为代理。这样,您就可以向呈现的UIViewController通信各种状态更改。
首先,进行协议声明并声明一个代理属性。
// ViewControllerB.h

@class ViewControllerB;

@protocol ViewControllerBDelegate <NSObject>
- (void)viewControllerDidClose:(ViewControllerB *)viewController;
@end

@property (unsafe_unretained, nonatomic) id<ViewControllerBDelegate> delegate;

当特定事件发生时,请调用委托。请确保检查接收对象是否实现了该协议。
// ViewControllerB.m

- (IBAction)closeButtonTapped:(id)sender 
{
    if ([self.delegate respondsToSelector:@selector(viewControllerDidClose:)]) {
        [self.delegate viewControllerDidClose:self];
    }
}

然后在vcA中实现该协议。

// ViewControllerA.h

@interface ViewControllerA : UIViewController <ViewControllerBDelegate>

将vcA设置为vcB的代理。

// ViewControllerA.m

- (void)presentVcB {
    vcB = [[ViewControllerB alloc] initWithNibName:nil bundle:nil];
    vcB.delegate = self;
    [self presentModalViewController:vcB animated:YES];
}

当方法被调用时,相应地做出响应。

// Implementing ViewControllerBDelegate
- viewControllerDidClose:(ViewControllerB *)viewController {
    [self dismissModalViewControllerAnimated:YES];
}

请注意,这种模式不仅可以用于关闭模态视图,还可以用于各种其他目的。

+1 感谢您的努力和出色的解决方案,但对于我的情况,Paul的更简单。 - Duck
1
他的确是一个聪明的解决方案。 - Paul Hunter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接