Reputation: 124
I am working on an Analytics Project by Swizzling UIViewController
methods viewDidAppear
and viewDidAppear
, code snippet as follows,
- (void) swizzledViewDidAppear : (BOOL)animated {
if ([UA isAppInitialized]) { // Check if Analytics Initialized
if ([[self class] isSubclassOfClass:[UIViewController class]]) {
[UA startPage:[NSString stringWithFormat:@"%@", NSStringFromClass ([self class])]];
}
}
[self swizzledViewDidAppear:animated];
}
- (void) swizzledViewDidDisappear : (BOOL)animated {
if ([UA isAppInitialized]) { // Check if Analytics Initialized
if ([[self class] isSubclassOfClass:[UIViewController class]]) {
[UA endPage:[NSString stringWithFormat:@"%@", NSStringFromClass ([self class])]];
}
}
[self swizzledViewDidDisappear:animated];
}
This is the code snippet where I want to track only the Custom ViewController, ex: MyViewController or FooViewController...etc and not Framework related classes like UICompatibilityInputViewController, UIInputWindowController...etc.
Please let me know how can I achieve this. I tried to check for Subclass but still at one point Framework classes are getting recorded.
Thanks, Vijay
Upvotes: 1
Views: 723
Reputation: 50089
you can get a class's NSBundle and check if that bundle is yours.
//code
extension NSObject {
static var isOurClass: Bool {
let appBundle = Bundle.main
let clsBundle = Bundle(for: self.self);
return clsBundle.bundlePath.hasPrefix(appBundle.bundlePath)
}
}
//test
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
print("appdelegate class ours? \(AppDelegate.isOurClass)")
print("NSString class ours? \(NSString.isOurClass)")
return true
}
}
#import <Foundation/Foundation.h>
@interface T : NSObject
@end
@implementation T
@end
int main(int argc, char *argv[]) {
@autoreleasepool {
NSBundle *bundleOfApp = [NSBundle mainBundle];
NSLog(@"%@", bundleOfApp.bundlePath);
//ours
T *t = [T new];
NSBundle *bundleOfT = [NSBundle bundleForClass:t.class];
NSLog(@"%@", bundleOfT.bundlePath);
if([bundleOfT.bundlePath hasPrefix:bundleOfApp.bundlePath]) {
NSLog(@"ours");
}
//theirs
bundleOfT = [NSBundle bundleForClass:NSString.class];
NSLog(@"%@", bundleOfT.bundlePath);
if([bundleOfT.bundlePath hasPrefix:bundleOfApp.bundlePath]) {
}
else {
NSLog(@"theirs");
}
}
}
Upvotes: 2
Reputation: 208
I was swizzling viewDidLoad, loadView and awakeFromNib for measuring load times and there is some strange behavior I've noticed.
For framework classes like UIInputWindowController, UIKeyboardCandidateGridCollectionViewController : awakeFromNib or loadView doesn't get called. They immediately appear after viewDidLoad has been called.
So the following lines of codes:
- (void)swizzled_awakeFromNib
{
NSLog(@"*** Awake from nib %@", NSStringFromClass(self.class));
[self swizzled_awakeFromNib];
}
- (void)swizzled_viewDidLoad
{
NSLog(@"*** View did load %@", NSStringFromClass(self.class));
[self swizzled_viewDidLoad];
}
- (void)swizzled_loadView
{
NSLog(@"*** Load view %@", NSStringFromClass(self.class));
[self swizzled_loadView];
}
Prints:
*** Awake from nib UINavigationController
*** View did load UINavigationController
*** Load view MyLoginViewController
*** View did load UIInputWindowController
*** View did load UIKeyboardCandidateGridCollectionViewController
*** View did load UIInputWindowController
*** View did load UIApplicationRotationFollowingControllerNoTouches
*** View did load MyLoginViewController
So maybe you can add a property to your category and set it to YES if awakeFromNib and/or loadView has called. Then check that bool in your viewDidLoad method to see if its a framework class.
Upvotes: 0
Reputation: 2294
In this case you have make instance of your class like and check it like
MyViewController *myVcntrl = [[MyViewController alloc]init];
if ([myVcntrl isKindOfClass:[MyViewController class]]) {
NSLog(@"Class is of MyViewController type");
}
else {
NSLog(@"Not of MyViewController type");
}
Upvotes: 0