@implementation UIView (AppNameAdditions)
- (UIViewController *)appName_viewController {
/// Finds the view's view controller.
// Take the view controller class object here and avoid sending the same message iteratively unnecessarily.
Class vcc = [UIViewController class];
// Traverse responder chain. Return first found view controller, which will be the view's view controller.
UIResponder *responder = self;
while ((responder = [responder nextResponder]))
if ([responder isKindOfClass: vcc])
return (UIViewController *)responder;
// If the view controller isn't found, return nil.
return nil;
}
@end
该类别是我在我创建的每个应用程序上发布的 ARC-enabled 静态库的一部分 . 它's been tested several times and I didn'吨发现任何问题或泄漏 .
25 回答
我的解决方案可能被认为是一种虚假的但我有类似mayoneez的情况(我想切换视图以响应EAGLView中的手势),我以这种方式获得了EAGL的视图控制器:
虽然这些答案在技术上是正确的,包括Ushox,但我认为批准的方法是实施新协议或重用现有协议 . 协议使观察者与被观察者隔离,就像在他们之间放置一个邮件槽一样 . 实际上,这就是Gabriel通过pushViewController方法调用所做的事情;视图"knows",礼貌地请求您的navigationController推送视图是合适的协议,因为viewController符合navigationController协议 . 虽然您可以创建自己的协议,但只需使用Gabriel的示例并重新使用UINavigationController协议即可 .
由于长期以来一直是公认的答案,我觉得我需要用更好的答案来纠正它 .
关于需求的一些评论:
您的视图不需要直接访问视图控制器 .
视图应该独立于视图控制器,并且能够在不同的上下文中工作 .
您是否需要视图以与视图控制器的方式接口,推荐的方式以及Apple在Cocoa中的作用是使用委托模式 .
以下是如何实现它的示例:
视图与其委托接口(例如
UITableView
),并不关心它是在视图控制器中实现还是在最终使用的任何其他类中实现 .我的原始答案如下:我不推荐这个,也不建议直接访问视图控制器的其他答案
没有内置的方法来做到这一点 . 虽然您可以通过在
UIView
上添加IBOutlet
并在Interface Builder中连接它们来绕过它,但不建议这样做 . 视图不应该知道视图控制器 . 相反,您应该按照@Phil M建议并创建一个用作委托的协议 .使用Brock发布的示例,我对它进行了修改,使其成为UIView的一个类,而不是UIViewController并使其递归,以便任何子视图都可以(希望)找到父UIViewController .
要使用此代码,请将其添加到新的类文件中(我将其命名为“UIKitCategories”)并删除类数据...将@interface复制到标头中,并将@implementation复制到.m文件中 . 然后在你的项目中,#import“UIKitCategories.h”并在UIView代码中使用:
UIView
是UIResponder
的子类 .UIResponder
使用返回nil
的实现布局方法-nextResponder
.UIView
覆盖此方法,如UIResponder
中所述(由于某种原因而不是UIView
),如下所示:如果视图具有视图控制器,则由-nextResponder
返回 . 如果没有视图控制器,该方法将返回超级视图 .将其添加到您的项目中,您就可以开始滚动了 .
现在
UIView
有一个返回视图控制器的工作方法 .我建议使用更轻量级的方法来遍历完整的响应者链,而无需在UIView上添加类别:
结合几个已经给出的答案,我正在发布我的实现:
该类别是我在我创建的每个应用程序上发布的 ARC-enabled 静态库的一部分 . 它's been tested several times and I didn'吨发现任何问题或泄漏 .
P.S . :如果相关视图是您的子类,则不需要像我一样使用类别 . 在后一种情况下,只需将方法放在子类中,就可以了 .
虽然这可以在技术上解决,因为pgb建议,恕我直言,这是一个设计缺陷 . 视图不需要知道控制器 .
我修改了de答案,所以我可以通过任何视图,按钮,标签等来获取它的父级
UIViewController
. 这是我的代码 .Edit Swift 3 Version
Edit 2:- Swift Extention
不要忘记,您可以访问视图是其子视图的窗口的根视图控制器 . 从那里,如果你是使用导航视图控制器并想要将新视图推送到它上面:
但是,您需要首先正确设置窗口的rootViewController属性 . 首次创建控制器时执行此操作,例如在你的app委托中:
Swift 4 version
用法示例
我不认为在某些情况下找出谁是视图控制器是“坏”的想法 . 可能不错的主意是保存对该控制器的引用,因为它可能会随着超级视图的变化而改变 . 在我的例子中,我有一个遍历响应者链的getter .
// . H
//.m
我偶然发现了一个我想要重用的小组件的情况,并在可重用的视图中添加了一些代码(它实际上只不过是一个打开
PopoverController
的按钮) .虽然这在iPad中工作正常(
UIPopoverController
本身,因此不需要引用UIViewController
),但是使用相同的代码工作意味着突然引用UIViewController
中的presentViewController
. 有点不一致吧?如前所述,在你的UIView中使用逻辑并不是最好的方法 . 但是在单独的控制器中包含所需的几行代码感觉真的没用 .
无论哪种方式,这是一个快速的解决方案,它为任何UIView添加一个新属性:
用于查找viewController的最简单的while while循环 .
这不直接回答问题,而是对问题的意图做出假设 .
如果您有视图并且在该视图中需要在另一个对象上调用方法,例如视图控制器,则可以使用NSNotificationCenter .
首先在头文件中创建通知字符串
在您的视图中调用postNotificationName:
然后在视图控制器中添加一个观察者 . 我在viewDidLoad中这样做
现在(也在同一个视图控制器中)实现你的方法copyString:如上面的@selector所示 .
我不是说这是正确的方法,它只是比运行第一个响应链更清晰 . 我使用此代码在UITableView上实现UIMenuController并将事件传递回UIViewController,以便我可以对数据执行某些操作 .
这肯定是一个坏主意和错误的设计,但我相信我们都可以享受由@Phil_M提出的最佳答案的Swift解决方案:
如果您的目的是做简单的事情,如显示模态对话框或跟踪数据,则不能证明使用协议 . 我个人将此函数存储在实用程序对象中,您可以从实现UIResponder协议的任何内容中使用它:
全部归功于@Phil_M
也许我迟到了 . 但在这种情况下,我不喜欢类别(污染) . 我喜欢这样:
致菲尔的回答:
在行:
id nextResponder = [self nextResponder];
如果self(UIView)不是ViewController视图的子视图,如果您知道self(UIView)的层次结构,您也可以使用:id nextResponder = [[self superview] nextResponder];
...swift 4的更新版本:感谢@Phil_M和@ paul-slm
更快捷的解决方案
我认为有观察到需要通知观察者的情况 .
我看到一个类似的问题,其中UIViewController中的UIView响应一种情况,它需要首先告诉其父视图控制器隐藏后退按钮,然后在完成时告诉父视图控制器它需要从堆栈中弹出自己 .
我一直在与代表们一起努力,但没有成功 .
我不明白为什么这应该是一个坏主意?
另一种简单的方法是拥有自己的视图类,并在视图类中添加视图控制器的属性 . 通常视图控制器创建视图,控制器可以将其自身设置为属性 . 基本上它不是为控制器搜索(有点黑客攻击),而是让控制器将自己设置为视图 - 这很简单但有意义,因为它是“控制”视图的控制器 .
斯威夫特4
(比其他答案更简洁)
我需要首先访问视图的用例
UIViewController
:我有一个包围AVPlayer
/AVPlayerViewController
的对象,我想提供一个简单的show(in view: UIView)
方法,将AVPlayerViewController
嵌入view
. 为此,我需要访问view
的UIViewController
.如果你的rootViewController是UINavigationViewController,它是在中设置的然后是AppDelegate类
其中c需要查看控制器类 .
用法:
没有办法 .
我所做的是将UIViewController指针传递给UIView(或适当的继承) . 对不起,我无法帮助解决问题的IB方法,因为我不相信IB .
回答第一个评论者:有时你需要知道是谁打电话给你,因为它决定了你能做什么 . 例如,对于数据库,您可能只有读访问权限或读/写...