记录项目中所有 UIViewController 的类名
Posted
技术标签:
【中文标题】记录项目中所有 UIViewController 的类名【英文标题】:Logging the class name of all UIViewControllers in a project 【发布时间】:2012-12-13 17:24:35 【问题描述】:我们收到了一个巨大的外包项目,我们正试图“修复”它。项目中有数百个视图控制器。我们的目标是轻松确定我们当前在设备上查看的类别。
我们的解决方案(没有用,因此出现了 SO 问题)如下。
通过一个类别覆盖 UIViewController 的 viewDidAppear 方法:
-(void)viewDidAppear:(BOOL)animated
NSLog(@"Current View Class: %@", NSStringFromClass(self.class));
[self viewDidAppear:animated];
//Also tried this:
//[super viewDidAppear:animated];
这个类别将被放在项目的 .pch 中。
这不需要在数百个视图控制器中添加额外的代码,并且可以轻松打开和关闭。它不起作用,因为正如我们现在所了解的那样,meme>不能简单地通过 category/meme 覆盖现有方法>.
我们错过了什么?!?
【问题讨论】:
这段代码有一个无限循环,不是吗?你应该调用 [super viewDidAppear:animated]; @BrunoDomingues 因为这是 UIViewController 上的一个类别,所以调用 super 会调用不存在的 NSObject(UIViewController 的超类)上的 viewDidAppear。 你可以从 UIWindow rootViewController 找到当前可见视图(视图控制器)。 @9dan 那到底会去哪里? 我在这里用 [self viewDidAppear:animated] 试过了;它确实有一个无限循环,并且有超级崩溃。在您的项目中 viewControllers 的 viewDidAppear 做了什么?因为默认情况下它什么都不做。您可以删除行 [self viewDidAppear:animated];它会起作用的。 【参考方案1】:答案是调配方法!这是我们想出的:
#import "UIViewController+Logging.h"
#import <objc/runtime.h>
@implementation UIViewController (Logging)
-(void)swizzled_viewDidAppear:(BOOL)animated
NSLog(@"Current View Class: %@", NSStringFromClass(self.class));
[self swizzled_viewDidAppear:animated];
+ (void)load
Method original, swizzled;
original = class_getInstanceMethod(self, @selector(viewDidAppear:));
swizzled = class_getInstanceMethod(self, @selector(swizzled_viewDidAppear:));
method_exchangeImplementations(original, swizzled);
@end
【讨论】:
今天一直在使用它,我们遇到了一个“问题”。如果子类调用 viewDidAppear 但没有调用 [super viewDidAppear],则不会得到日志。 刚刚遇到这个。为了其他人阅读 cmets,所有 UIViewController 子类都必须调用 [super viewDidAppear],所以如果缺少它,那是另一个程序员错误。【参考方案2】:
viewWillAppear
日志
下面是打印当前视图控制器类名的解决方案,当它出现在控制台时:
在 Xcode 中创建符号断点 对于符号,添加-[UIViewController viewWillAppear:]
对于Action,添加一个调试器命令和这个表达式:
expr -- (void) printf("? %s\n", (char *)object_getClassName($arg1))
勾选评估动作后自动继续。
每当我在项目中迷失时,这对我有很大帮助!
deinit
日志
您还可以添加日志以查看您的视图控制器 deinit
何时被调用:
-[UIViewController dealloc]
对于Action,添加一个调试器命令和这个表达式:
expr -- (void) printf("? %s\n", (char *)object_getClassName($arg1))
勾选评估动作后自动继续。
这个非常方便,可以确保视图控制器从内存中释放,同时也是捕捉保留周期的良好指标。
【讨论】:
【参考方案3】:这是解决方案
在你的 .pch 文件中包含这个
#define UIViewController MyViewController
#import "MyViewController.h"
创建新的 UIViewController 子类
.h 文件
#import <UIKit/UIKit.h>
#ifdef UIViewController
#undef UIViewController
#endif
@interface MyViewController : UIViewController
@end
#ifndef UIViewController
#define UIViewController MyViewController
#endif
还有.m文件
#import "MyViewController.h"
@implementation MyViewController
- (void)viewDidLoad
[super viewDidLoad];
NSLog(@"Current View Class: %@", NSStringFromClass(self.class));
@end
【讨论】:
刚刚有机会测试这段代码,它也能正常工作。与方法调配相比,这种方法有什么优点/缺点吗? 我的代码正在做的是将超类UIViewController
替换为MyViewController
。我现在找不到这两种方法的任何缺点..
感谢您的解决方案,在接受答案之前仍在等待进一步的信息。
当然 :) 寻找最好的【参考方案4】:
视图控制器是否共享一个公共基类?如果是这样,您可以将其放在 [viewDidAppear:] 的基类实现中。如果他们不共享一个共同的基础,那么也许这将是一项有价值的任务,因为它在未来无论如何都会有用(共同的分析代码等)
【讨论】:
很遗憾没有。它们都是 UIViewController 的简单子类。寻找解决方案的方法。 我知道你有数百个控制器,但是一个好的查找/替换可以很容易地帮助你从一个通用的控制器类继承。这将使这项特定任务变得容易,并有其他好处。【参考方案5】:您可以从 Xcode 进行应用程序范围的查找和替换,但不一定会找到所有情况(但您尝试的方法也不会)。你可以寻找“[super viewDidLoad];”并替换为 "[super viewDidLoad]; NSLog(@"Current View Class: %@", NSStringFromClass(self.class));"
【讨论】:
寻找一个可以在整个应用程序范围内工作的更简单的解决方案,而不是像问题中描述的那样修改每个类。【参考方案6】:应用程序是否使用导航控制器来显示视图控制器?如果是这样,您可以使用 NavigationController 的方法来报告当前控制器:
- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated
[self reportNewController:viewController];
- (void) reportNewController:(UIViewController *)viewController
NSString *name = viewController.title;
NSLog(@"Name is %@",name);
【讨论】:
【参考方案7】:您可以使用方法调配。这是一个很好的指南: http://nshipster.com/method-swizzling/
【讨论】:
以上是关于记录项目中所有 UIViewController 的类名的主要内容,如果未能解决你的问题,请参考以下文章
使用目标 c 后,UiViewController 不会从标签栏项目中快速加载
使用 UIAppearence 更改 UIViewController 的直接子视图的背景颜色