当前UIViewController
在屏幕上需要应对推通知从的APN,通过设置一些徽章的看法。 但是,我怎么能得到UIViewController
的方法application:didReceiveRemoteNotification
:中AppDelegate.m
?
我试图用self.window.rootViewController
让显示当前UIViewController
,它可能是一个UINavigationViewController
或一些其他类型的视图控制器。 而且我发现,在visibleViewController
财产UINavigationViewController
可用于获取UIViewController
在屏幕上。 但我能做什么,如果它不是一个UINavigationViewController
?
任何帮助表示赞赏! 相关代码如下。
AppDelegate.m
...
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
//I would like to find out which view controller is on the screen here.
UIViewController *vc = [(UINavigationViewController *)self.window.rootViewController visibleViewController];
[vc performSelector:@selector(handleThePushNotification:) withObject:userInfo];
}
...
ViewControllerA.m
- (void)handleThePushNotification:(NSDictionary *)userInfo{
//set some badge view here
}
Answer 1:
您可以使用rootViewController
还当你的控制器不是UINavigationController
:
UIViewController *vc = self.window.rootViewController;
一旦你知道的根视图控制器,那就要看你如何建立你的用户界面,但你都不可能找到一个方式,通过控制器的层次结构进行导航。
如果你给你定义你的应用程序的方式一些更多的细节,那么我可能给一些提示。
编辑:
如果你想在最上面的视图 (不视图控制器),您可以检查
[[[[UIApplication sharedApplication] keyWindow] subviews] lastObject];
尽管这一观点可能是不可见的,甚至一些它的子视图的覆盖...
再次,它取决于你的UI,但是这可能帮助...
Answer 2:
我永远爱涉及的类别,因为它们是螺栓上,可以方便地重复使用的解决方案。
所以,我创建了一个UIWindow上一个类别。 现在,您可以拨打visibleViewController在一个UIWindow,这将通过向下搜索控制器层次让你可见视图控制器。 这工作如果您正在使用导航和/或标签栏控制器。 如果您有其他类型的控制器的建议,请让我知道,我可以添加它。
的UIWindow + PazLabs.h(头文件)
#import <UIKit/UIKit.h>
@interface UIWindow (PazLabs)
- (UIViewController *) visibleViewController;
@end
一个UIWindow + PazLabs.m(执行文件)
#import "UIWindow+PazLabs.h"
@implementation UIWindow (PazLabs)
- (UIViewController *)visibleViewController {
UIViewController *rootViewController = self.rootViewController;
return [UIWindow getVisibleViewControllerFrom:rootViewController];
}
+ (UIViewController *) getVisibleViewControllerFrom:(UIViewController *) vc {
if ([vc isKindOfClass:[UINavigationController class]]) {
return [UIWindow getVisibleViewControllerFrom:[((UINavigationController *) vc) visibleViewController]];
} else if ([vc isKindOfClass:[UITabBarController class]]) {
return [UIWindow getVisibleViewControllerFrom:[((UITabBarController *) vc) selectedViewController]];
} else {
if (vc.presentedViewController) {
return [UIWindow getVisibleViewControllerFrom:vc.presentedViewController];
} else {
return vc;
}
}
}
@end
斯威夫特版本
public extension UIWindow {
public var visibleViewController: UIViewController? {
return UIWindow.getVisibleViewControllerFrom(self.rootViewController)
}
public static func getVisibleViewControllerFrom(_ vc: UIViewController?) -> UIViewController? {
if let nc = vc as? UINavigationController {
return UIWindow.getVisibleViewControllerFrom(nc.visibleViewController)
} else if let tc = vc as? UITabBarController {
return UIWindow.getVisibleViewControllerFrom(tc.selectedViewController)
} else {
if let pvc = vc?.presentedViewController {
return UIWindow.getVisibleViewControllerFrom(pvc)
} else {
return vc
}
}
}
}
Answer 3:
在斯威夫特的简单扩展UIApplication的(甚至关心约moreNavigationController内UITabBarController
在iPhone上):
extension UIApplication {
class func topViewController(base: UIViewController? = UIApplication.sharedApplication().keyWindow?.rootViewController) -> UIViewController? {
if let nav = base as? UINavigationController {
return topViewController(base: nav.visibleViewController)
}
if let tab = base as? UITabBarController {
let moreNavigationController = tab.moreNavigationController
if let top = moreNavigationController.topViewController where top.view.window != nil {
return topViewController(top)
} else if let selected = tab.selectedViewController {
return topViewController(selected)
}
}
if let presented = base?.presentedViewController {
return topViewController(base: presented)
}
return base
}
}
简单的用法:
if let rootViewController = UIApplication.topViewController() {
//do sth with root view controller
}
完美的作品:-)
更新干净的代码:
extension UIViewController {
var top: UIViewController? {
if let controller = self as? UINavigationController {
return controller.topViewController?.top
}
if let controller = self as? UISplitViewController {
return controller.viewControllers.last?.top
}
if let controller = self as? UITabBarController {
return controller.selectedViewController?.top
}
if let controller = presentedViewController {
return controller.top
}
return self
}
}
Answer 4:
您也可以通过发布一个NSNotificationCenter通知。 这使你可以同时处理多个,其中穿越视图控制器层次结构可能会非常棘手的情况 - 例如正在呈现模态等时,
例如,
// MyAppDelegate.h
NSString * const UIApplicationDidReceiveRemoteNotification;
// MyAppDelegate.m
NSString * const UIApplicationDidReceiveRemoteNotification = @"UIApplicationDidReceiveRemoteNotification";
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
[[NSNotificationCenter defaultCenter]
postNotificationName:UIApplicationDidReceiveRemoteNotification
object:self
userInfo:userInfo];
}
在每个视图控制器的:
-(void)viewDidLoad {
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(didReceiveRemoteNotification:)
name:UIApplicationDidReceiveRemoteNotification
object:nil];
}
-(void)viewDidUnload {
[[NSNotificationCenter defaultCenter]
removeObserver:self
name:UIApplicationDidReceiveRemoteNotification
object:nil];
}
-(void)didReceiveRemoteNotification:(NSDictionary *)userInfo {
// see http://stackoverflow.com/a/2777460/305149
if (self.isViewLoaded && self.view.window) {
// handle the notification
}
}
你也可以使用这种方法来这就需要在接收到通知,并通过几个视图控制器用于更新仪器控制。 在这种情况下,处理添加/ init和dealloc的方法,去除通话观察员分别。
Answer 5:
我发现的iOS 8已经搞砸了一切。 在iOS系统7有一个新的UITransitionView
上,只要你有一个展示模态视图层次结构UINavigationController
。 总之,这里是我的代码,发现得到的最顶层VC。 调用getTopMostViewController
应该返回一个VC,你应该能够发送邮件一样presentViewController:animated:completion
。 它的目的是让你一个VC,你可以用它来呈现模态VC,所以它很可能会停止,并在容器类,如返回UINavigationController
,而不是VC包含在其中。 应该不难适应代码来做到这一点。 我测试过在各种情况下,这种代码在iOS 6中,7和8。请让你发现我的错误认识。
+ (UIViewController*) getTopMostViewController
{
UIWindow *window = [[UIApplication sharedApplication] keyWindow];
if (window.windowLevel != UIWindowLevelNormal) {
NSArray *windows = [[UIApplication sharedApplication] windows];
for(window in windows) {
if (window.windowLevel == UIWindowLevelNormal) {
break;
}
}
}
for (UIView *subView in [window subviews])
{
UIResponder *responder = [subView nextResponder];
//added this block of code for iOS 8 which puts a UITransitionView in between the UIWindow and the UILayoutContainerView
if ([responder isEqual:window])
{
//this is a UITransitionView
if ([[subView subviews] count])
{
UIView *subSubView = [subView subviews][0]; //this should be the UILayoutContainerView
responder = [subSubView nextResponder];
}
}
if([responder isKindOfClass:[UIViewController class]]) {
return [self topViewController: (UIViewController *) responder];
}
}
return nil;
}
+ (UIViewController *) topViewController: (UIViewController *) controller
{
BOOL isPresenting = NO;
do {
// this path is called only on iOS 6+, so -presentedViewController is fine here.
UIViewController *presented = [controller presentedViewController];
isPresenting = presented != nil;
if(presented != nil) {
controller = presented;
}
} while (isPresenting);
return controller;
}
Answer 6:
码
下面是使用在斯威夫特3大的switch-case语法的方法:
extension UIWindow {
/// Returns the currently visible view controller if any reachable within the window.
public var visibleViewController: UIViewController? {
return UIWindow.visibleViewController(from: rootViewController)
}
/// Recursively follows navigation controllers, tab bar controllers and modal presented view controllers starting
/// from the given view controller to find the currently visible view controller.
///
/// - Parameters:
/// - viewController: The view controller to start the recursive search from.
/// - Returns: The view controller that is most probably visible on screen right now.
public static func visibleViewController(from viewController: UIViewController?) -> UIViewController? {
switch viewController {
case let navigationController as UINavigationController:
return UIWindow.visibleViewController(from: navigationController.visibleViewController ?? navigationController.topViewController)
case let tabBarController as UITabBarController:
return UIWindow.visibleViewController(from: tabBarController.selectedViewController)
case let presentingViewController where viewController?.presentedViewController != nil:
return UIWindow.visibleViewController(from: presentingViewController?.presentedViewController)
default:
return viewController
}
}
}
其基本思路是一样zirinisp的答案,它只是采用了更为迅捷3的语法。
用法
你可能想创建一个名为UIWindowExtension.swift
。 确保它包括import UIKit
声明,现在复制上面的扩展代码 。
在呼叫侧它可以是用于在没有任何特定视图控制器 :
if let visibleViewCtrl = UIApplication.shared.keyWindow?.visibleViewController {
// do whatever you want with your `visibleViewCtrl`
}
或者,如果你知道你的可见视图控制器是从特定视图控制器可达:
if let visibleViewCtrl = UIWindow.visibleViewController(from: specificViewCtrl) {
// do whatever you want with your `visibleViewCtrl`
}
我希望它能帮助!
Answer 7:
方法更少的代码比所有其他解决方案:
Objective-C的版本:
- (UIViewController *)getTopViewController {
UIViewController *topViewController = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
while (topViewController.presentedViewController) topViewController = topViewController.presentedViewController;
return topViewController;
}
雨燕2.0的版本:(归功于Steve.B)
func getTopViewController() -> UIViewController {
var topViewController = UIApplication.sharedApplication().delegate!.window!!.rootViewController!
while (topViewController.presentedViewController != nil) {
topViewController = topViewController.presentedViewController!
}
return topViewController
}
任何地方工作在您的应用程序,即使情态动词。
Answer 8:
指定标题到每个视图控制器,然后通过下面给出的代码获取当前视图控制器的标题。
-(void)viewDidUnload {
NSString *currentController = self.navigationController.visibleViewController.title;
然后,通过您的标题像这样的检查
if([currentController isEqualToString:@"myViewControllerTitle"]){
//write your code according to View controller.
}
}
Answer 9:
zirinisp的回答:在斯威夫特:
extension UIWindow {
func visibleViewController() -> UIViewController? {
if let rootViewController: UIViewController = self.rootViewController {
return UIWindow.getVisibleViewControllerFrom(rootViewController)
}
return nil
}
class func getVisibleViewControllerFrom(vc:UIViewController) -> UIViewController {
if vc.isKindOfClass(UINavigationController.self) {
let navigationController = vc as UINavigationController
return UIWindow.getVisibleViewControllerFrom( navigationController.visibleViewController)
} else if vc.isKindOfClass(UITabBarController.self) {
let tabBarController = vc as UITabBarController
return UIWindow.getVisibleViewControllerFrom(tabBarController.selectedViewController!)
} else {
if let presentedViewController = vc.presentedViewController {
return UIWindow.getVisibleViewControllerFrom(presentedViewController.presentedViewController!)
} else {
return vc;
}
}
}
}
用法:
if let topController = window.visibleViewController() {
println(topController)
}
Answer 10:
我的是更好! :)
extension UIApplication {
var visibleViewController : UIViewController? {
return keyWindow?.rootViewController?.topViewController
}
}
extension UIViewController {
fileprivate var topViewController: UIViewController {
switch self {
case is UINavigationController:
return (self as! UINavigationController).visibleViewController?.topViewController ?? self
case is UITabBarController:
return (self as! UITabBarController).selectedViewController?.topViewController ?? self
default:
return presentedViewController?.topViewController ?? self
}
}
}
Answer 11:
为什么不直接处理在应用程序的委托推送通知的代码? 难道是直接关系到一个看法?
您可以检查是否UIViewController的观点是目前通过检查,如果它的视图的可视window
属性有值。 查看更多在这里 。
Answer 12:
关于NSNotificationCenter邮政以上(抱歉不能找出张贴在其评论...)
在一些情况下,都拿到了 - 各种各样的[NSConcreteNotification allKeys]错误。 更改此:
-(void)didReceiveRemoteNotification:(NSDictionary *)userInfo
为此:
-(void)didReceiveRemoteNotification:(NSNotification*)notif {
NSDictionary *dict = notif.userInfo;
}
Answer 13:
只是除了@zirinisp答案。
创建一个文件,命名为UIWindowExtension.swift
并粘贴下面的代码片段:
import UIKit
public extension UIWindow {
public var visibleViewController: UIViewController? {
return UIWindow.getVisibleViewControllerFrom(self.rootViewController)
}
public static func getVisibleViewControllerFrom(vc: UIViewController?) -> UIViewController? {
if let nc = vc as? UINavigationController {
return UIWindow.getVisibleViewControllerFrom(nc.visibleViewController)
} else if let tc = vc as? UITabBarController {
return UIWindow.getVisibleViewControllerFrom(tc.selectedViewController)
} else {
if let pvc = vc?.presentedViewController {
return UIWindow.getVisibleViewControllerFrom(pvc)
} else {
return vc
}
}
}
}
func getTopViewController() -> UIViewController? {
let appDelegate = UIApplication.sharedApplication().delegate
if let window = appDelegate!.window {
return window?.visibleViewController
}
return nil
}
在任何地方使用它作为:
if let topVC = getTopViewController() {
}
由于@zirinisp。
Answer 14:
这为我工作。 我有有不同的控制器,因此以前的答案没有似乎工作许多目标。
首先你想这是你的AppDelegate类中:
var window: UIWindow?
那么,在你的函数
let navigationController = window?.rootViewController as? UINavigationController
if let activeController = navigationController!.visibleViewController {
if activeController.isKindOfClass( MyViewController ) {
println("I have found my controller!")
}
}
Answer 15:
extension UIApplication {
/// The top most view controller
static var topMostViewController: UIViewController? {
return UIApplication.shared.keyWindow?.rootViewController?.visibleViewController
}
}
extension UIViewController {
/// The visible view controller from a given view controller
var visibleViewController: UIViewController? {
if let navigationController = self as? UINavigationController {
return navigationController.topViewController?.visibleViewController
} else if let tabBarController = self as? UITabBarController {
return tabBarController.selectedViewController?.visibleViewController
} else if let presentedViewController = presentedViewController {
return presentedViewController.visibleViewController
} else {
return self
}
}
}
有了这个,你可以很容易地得到像这样的顶级内线视图控制器
let viewController = UIApplication.topMostViewController
有一点要注意的是,如果有一个UIAlertController当前正在显示, UIApplication.topMostViewController
将返回UIAlertController
。
Answer 16:
雨燕2.0的版本jungledev的回答
func getTopViewController() -> UIViewController {
var topViewController = UIApplication.sharedApplication().delegate!.window!!.rootViewController!
while (topViewController.presentedViewController != nil) {
topViewController = topViewController.presentedViewController!
}
return topViewController
}
Answer 17:
这是我已经尝试了尽可能最好的方式。 如果它应该帮助的人......
+ (UIViewController*) topMostController
{
UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController;
while (topController.presentedViewController) {
topController = topController.presentedViewController;
}
return topController;
}
Answer 18:
经常检查你的构建配置如果您正在使用调试或释放您的应用程序。
重要提示:你可以不能够测试它无需调试模式下运行你的应用程序
这是我的解决办法
Answer 19:
我创建了一个类别UIApplication
与visibleViewControllers
财产。 其主要思想是非常简单。 我搅和viewDidAppear
和viewDidDisappear
的方法UIViewController
。 在viewDidAppear
方法被添加的viewController堆叠。 在viewDidDisappear
方法的viewController从栈中删除。 NSPointerArray
代替NSArray
存储弱UIViewController
的引用。 这种方法适用于任何viewControllers层次。
UIApplication的+ VisibleViewControllers.h
#import <UIKit/UIKit.h>
@interface UIApplication (VisibleViewControllers)
@property (nonatomic, readonly) NSArray<__kindof UIViewController *> *visibleViewControllers;
@end
UIApplication的+ VisibleViewControllers.m
#import "UIApplication+VisibleViewControllers.h"
#import <objc/runtime.h>
@interface UIApplication ()
@property (nonatomic, readonly) NSPointerArray *visibleViewControllersPointers;
@end
@implementation UIApplication (VisibleViewControllers)
- (NSArray<__kindof UIViewController *> *)visibleViewControllers {
return self.visibleViewControllersPointers.allObjects;
}
- (NSPointerArray *)visibleViewControllersPointers {
NSPointerArray *pointers = objc_getAssociatedObject(self, @selector(visibleViewControllersPointers));
if (!pointers) {
pointers = [NSPointerArray weakObjectsPointerArray];
objc_setAssociatedObject(self, @selector(visibleViewControllersPointers), pointers, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
return pointers;
}
@end
@implementation UIViewController (UIApplication_VisibleViewControllers)
+ (void)swizzleMethodWithOriginalSelector:(SEL)originalSelector swizzledSelector:(SEL)swizzledSelector {
Method originalMethod = class_getInstanceMethod(self, originalSelector);
Method swizzledMethod = class_getInstanceMethod(self, swizzledSelector);
BOOL didAddMethod = class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
if (didAddMethod) {
class_replaceMethod(self, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
}
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[self swizzleMethodWithOriginalSelector:@selector(viewDidAppear:)
swizzledSelector:@selector(uiapplication_visibleviewcontrollers_viewDidAppear:)];
[self swizzleMethodWithOriginalSelector:@selector(viewDidDisappear:)
swizzledSelector:@selector(uiapplication_visibleviewcontrollers_viewDidDisappear:)];
});
}
- (void)uiapplication_visibleviewcontrollers_viewDidAppear:(BOOL)animated {
[[UIApplication sharedApplication].visibleViewControllersPointers addPointer:(__bridge void * _Nullable)self];
[self uiapplication_visibleviewcontrollers_viewDidAppear:animated];
}
- (void)uiapplication_visibleviewcontrollers_viewDidDisappear:(BOOL)animated {
NSPointerArray *pointers = [UIApplication sharedApplication].visibleViewControllersPointers;
for (int i = 0; i < pointers.count; i++) {
UIViewController *viewController = [pointers pointerAtIndex:i];
if ([viewController isEqual:self]) {
[pointers removePointerAtIndex:i];
break;
}
}
[self uiapplication_visibleviewcontrollers_viewDidDisappear:animated];
}
@end
https://gist.github.com/medvedzzz/e6287b99011f2437ac0beb5a72a897f0
斯威夫特3版
UIApplication的+ VisibleViewControllers.swift
import UIKit
extension UIApplication {
private struct AssociatedObjectsKeys {
static var visibleViewControllersPointers = "UIApplication_visibleViewControllersPointers"
}
fileprivate var visibleViewControllersPointers: NSPointerArray {
var pointers = objc_getAssociatedObject(self, &AssociatedObjectsKeys.visibleViewControllersPointers) as! NSPointerArray?
if (pointers == nil) {
pointers = NSPointerArray.weakObjects()
objc_setAssociatedObject(self, &AssociatedObjectsKeys.visibleViewControllersPointers, pointers, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
return pointers!
}
var visibleViewControllers: [UIViewController] {
return visibleViewControllersPointers.allObjects as! [UIViewController]
}
}
extension UIViewController {
private static func swizzleFunc(withOriginalSelector originalSelector: Selector, swizzledSelector: Selector) {
let originalMethod = class_getInstanceMethod(self, originalSelector)
let swizzledMethod = class_getInstanceMethod(self, swizzledSelector)
let didAddMethod = class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))
if didAddMethod {
class_replaceMethod(self, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod))
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
}
override open class func initialize() {
if self != UIViewController.self {
return
}
let swizzlingClosure: () = {
UIViewController.swizzleFunc(withOriginalSelector: #selector(UIViewController.viewDidAppear(_:)),
swizzledSelector: #selector(uiapplication_visibleviewcontrollers_viewDidAppear(_:)))
UIViewController.swizzleFunc(withOriginalSelector: #selector(UIViewController.viewDidDisappear(_:)),
swizzledSelector: #selector(uiapplication_visibleviewcontrollers_viewDidDisappear(_:)))
}()
swizzlingClosure
}
@objc private func uiapplication_visibleviewcontrollers_viewDidAppear(_ animated: Bool) {
UIApplication.shared.visibleViewControllersPointers.addPointer(Unmanaged.passUnretained(self).toOpaque())
uiapplication_visibleviewcontrollers_viewDidAppear(animated)
}
@objc private func uiapplication_visibleviewcontrollers_viewDidDisappear(_ animated: Bool) {
let pointers = UIApplication.shared.visibleViewControllersPointers
for i in 0..<pointers.count {
if let pointer = pointers.pointer(at: i) {
let viewController = Unmanaged<AnyObject>.fromOpaque(pointer).takeUnretainedValue() as? UIViewController
if viewController.isEqual(self) {
pointers.removePointer(at: i)
break
}
}
}
uiapplication_visibleviewcontrollers_viewDidDisappear(animated)
}
}
https://gist.github.com/medvedzzz/ee6f4071639d987793977dba04e11399
文章来源: Get the current displaying UIViewController on the screen in AppDelegate.m