ber*_*dom 180 cocoa-touch objective-c uiviewcontroller uiview ios
是否有内置的方式从a UIView
到它UIViewController
?我知道你可以从UIViewController
它UIView
通过它,[self view]
但我想知道是否有反向参考?
Phi*_*l M 200
使用Brock发布的示例,我对它进行了修改,使其成为UIView的一个类,而不是UIViewController并使其递归,以便任何子视图都可以(希望)找到父UIViewController.
@interface UIView (FindUIViewController)
- (UIViewController *) firstAvailableUIViewController;
- (id) traverseResponderChainForUIViewController;
@end
@implementation UIView (FindUIViewController)
- (UIViewController *) firstAvailableUIViewController {
// convenience function for casting and to "mask" the recursive function
return (UIViewController *)[self traverseResponderChainForUIViewController];
}
- (id) traverseResponderChainForUIViewController {
id nextResponder = [self nextResponder];
if ([nextResponder isKindOfClass:[UIViewController class]]) {
return nextResponder;
} else if ([nextResponder isKindOfClass:[UIView class]]) {
return [nextResponder traverseResponderChainForUIViewController];
} else {
return nil;
}
}
@end
Run Code Online (Sandbox Code Playgroud)
要使用此代码,请将其添加到新的类文件中(我将其命名为"UIKitCategories")并删除类数据...将@interface复制到标头中,并将@implementation复制到.m文件中.然后在你的项目中,#import"UIKitCategories.h"并在UIView代码中使用:
// from a UIView subclass... returns nil if UIViewController not available
UIViewController * myController = [self firstAvailableUIViewController];
Run Code Online (Sandbox Code Playgroud)
小智 112
UIView
是.的子类UIResponder
.UIResponder
勾画出方法-nextResponder
与返回的实现nil
.UIView
覆盖此方法,如UIResponder
(由于某种原因而不是in UIView
)中所述:如果视图具有视图控制器,则返回该方法-nextResponder
.如果没有视图控制器,该方法将返回超级视图.
将其添加到您的项目中,您就可以开始滚动了.
@interface UIView (APIFix)
- (UIViewController *)viewController;
@end
@implementation UIView (APIFix)
- (UIViewController *)viewController {
if ([self.nextResponder isKindOfClass:UIViewController.class])
return (UIViewController *)self.nextResponder;
else
return nil;
}
@end
Run Code Online (Sandbox Code Playgroud)
现在UIView
有一个返回视图控制器的工作方法.
pgb*_*pgb 44
由于长期以来一直是公认的答案,我觉得我需要用更好的答案来纠正它.
关于需求的一些评论:
以下是如何实现它的示例:
@protocol MyViewDelegate < NSObject >
- (void)viewActionHappened;
@end
@interface MyView : UIView
@property (nonatomic, assign) MyViewDelegate delegate;
@end
@interface MyViewController < MyViewDelegate >
@end
Run Code Online (Sandbox Code Playgroud)
视图与其委托接口(UITableView
例如),并不关心它是在视图控制器中实现还是在最终使用的任何其他类中实现.
我的原始答案如下:我不推荐这个,也不建议直接访问视图控制器的其他答案
没有内置的方法来做到这一点.虽然你可以通过添加避过它IBOutlet
的UIView
和在Interface Builder连接这些,不建议这样做.视图不应该知道视图控制器.相反,您应该按照@Phil M建议并创建一个用作委托的协议.
de.*_*de. 33
我建议使用更轻量级的方法来遍历完整的响应者链,而无需在UIView上添加类别:
@implementation MyUIViewSubclass
- (UIViewController *)viewController {
UIResponder *responder = self;
while (![responder isKindOfClass:[UIViewController class]]) {
responder = [responder nextResponder];
if (nil == responder) {
break;
}
}
return (UIViewController *)responder;
}
@end
Run Code Online (Sandbox Code Playgroud)
Con*_*has 22
结合几个已经给出的答案,我正在发布我的实现:
@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
Run Code Online (Sandbox Code Playgroud)
该类别是我在我创建的每个应用程序上发布的支持ARC的静态库的一部分.它已经过多次测试,我没有发现任何问题或泄漏.
PS:如果相关视图是您的子类,则不需要像我一样使用类别.在后一种情况下,只需将方法放在子类中,就可以了.
Ush*_*hox 12
虽然这可以在技术上解决,因为pgb建议,恕我直言,这是一个设计缺陷.视图不需要知道控制器.
Var*_*ria 12
我修改了de answer所以我可以传递任何视图,按钮,标签等来获取它的父级UIViewController
.这是我的代码.
+(UIViewController *)viewController:(id)view {
UIResponder *responder = view;
while (![responder isKindOfClass:[UIViewController class]]) {
responder = [responder nextResponder];
if (nil == responder) {
break;
}
}
return (UIViewController *)responder;
}
Run Code Online (Sandbox Code Playgroud)
编辑Swift 3版本
class func viewController(_ view: UIView) -> UIViewController {
var responder: UIResponder? = view
while !(responder is UIViewController) {
responder = responder?.next
if nil == responder {
break
}
}
return (responder as? UIViewController)!
}
Run Code Online (Sandbox Code Playgroud)
编辑2: - 快速延伸
extension UIView
{
//Get Parent View Controller from any view
func parentViewController() -> UIViewController {
var responder: UIResponder? = self
while !(responder is UIViewController) {
responder = responder?.next
if nil == responder {
break
}
}
return (responder as? UIViewController)!
}
}
Run Code Online (Sandbox Code Playgroud)
不要忘记,您可以访问视图是其子视图的窗口的根视图控制器.从那里,如果您正在使用导航视图控制器并想要将新视图推送到它:
[[[[self window] rootViewController] navigationController] pushViewController:newController animated:YES];
Run Code Online (Sandbox Code Playgroud)
但是,您需要首先正确设置窗口的rootViewController属性.首次创建控制器时执行此操作,例如在您的app委托中:
-(void) applicationDidFinishLaunching:(UIApplication *)application {
window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
RootViewController *controller = [[YourRootViewController] alloc] init];
[window setRootViewController: controller];
navigationController = [[UINavigationController alloc] initWithRootViewController:rootViewController];
[controller release];
[window addSubview:[[self navigationController] view]];
[window makeKeyAndVisible];
}
Run Code Online (Sandbox Code Playgroud)
小智 6
虽然这些答案在技术上是正确的,包括Ushox,但我认为批准的方法是实施新协议或重用现有协议.协议使观察者与被观察者隔离,就像在他们之间放置一个邮件槽一样.实际上,这就是Gabriel通过pushViewController方法调用所做的事情; 视图"知道"礼貌地请求您的navigationController推送视图是正确的协议,因为viewController符合navigationController协议.虽然您可以创建自己的协议,但只需使用Gabriel的示例并重新使用UINavigationController协议即可.
我偶然发现了一个我想要重用的小组件的情况,并在可重用的视图中添加了一些代码(它实际上只不过是一个打开的按钮PopoverController
).
虽然这在iPad中运行良好(UIPopoverController
礼物本身,因此不需要参考a UIViewController
),使相同的代码工作意味着突然引用你presentViewController
的UIViewController
.有点不一致吧?
如前所述,在你的UIView中使用逻辑并不是最好的方法.但是在单独的控制器中包含所需的几行代码感觉真的没用.
无论哪种方式,这是一个快速的解决方案,它为任何UIView添加一个新属性:
extension UIView {
var viewController: UIViewController? {
var responder: UIResponder? = self
while responder != nil {
if let responder = responder as? UIViewController {
return responder
}
responder = responder?.nextResponder()
}
return nil
}
}
Run Code Online (Sandbox Code Playgroud)
return
现在不需要关键字解决方案一:
extension UIView {
var parentViewController: UIViewController? {
sequence(first: self) { $0.next }
.first(where: { $0 is UIViewController })
.flatMap { $0 as? UIViewController }
}
}
Run Code Online (Sandbox Code Playgroud)
解决方案2:
extension UIView {
var parentViewController: UIViewController? {
sequence(first: self) { $0.next }
.compactMap{ $0 as? UIViewController }
.first
}
}
Run Code Online (Sandbox Code Playgroud)
我不认为在某些情况下找出谁是视图控制器是"坏"的想法.可能不错的主意是保存对该控制器的引用,因为它可能会随着超级视图的变化而改变.在我的例子中,我有一个遍历响应者链的getter.
//.H
@property (nonatomic, readonly) UIViewController * viewController;
Run Code Online (Sandbox Code Playgroud)
//.m
- (UIViewController *)viewController
{
for (UIResponder * nextResponder = self.nextResponder;
nextResponder;
nextResponder = nextResponder.nextResponder)
{
if ([nextResponder isKindOfClass:[UIViewController class]])
return (UIViewController *)nextResponder;
}
// Not found
NSLog(@"%@ doesn't seem to have a viewController". self);
return nil;
}
Run Code Online (Sandbox Code Playgroud)
(比其他答案更简洁)
fileprivate extension UIView {
var firstViewController: UIViewController? {
let firstViewController = sequence(first: self, next: { $0.next }).first(where: { $0 is UIViewController })
return firstViewController as? UIViewController
}
}
Run Code Online (Sandbox Code Playgroud)
我需要首先访问视图的用例UIViewController
:我有一个围绕AVPlayer
/的对象AVPlayerViewController
,我想提供一个show(in view: UIView)
嵌入AVPlayerViewController
到view
. 为此,我需要访问view
's UIViewController
。
归档时间: |
|
查看次数: |
136620 次 |
最近记录: |