Last active
June 28, 2016 01:46
-
-
Save zats/339380006894da2c4759 to your computer and use it in GitHub Desktop.
Improving View Debugging in Xcode by showing ViewController class this view belongs to http://blog.zats.io/2015/06/16/improving-view-debugging-in-xcode/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifdef DEBUG | |
#import "WMLSwizzler.h" | |
static SEL wml_loadViewSEL; | |
static void wml_swizzleLoadViewForClass(Class class) { | |
typedef void(*load_view_t)(id, SEL); | |
__block load_view_t loadView = (load_view_t)[class S_replaceInstanceMethod:wml_loadViewSEL withBlock:^(UIViewController *self){ | |
loadView(self, wml_loadViewSEL); | |
if (!self.isViewLoaded) { | |
return; | |
} | |
Class viewClass = [self.view class]; | |
Class viewControllerClass = [self class]; | |
// in case this method was called twice | |
if ([NSStringFromClass(viewClass) hasPrefix:NSStringFromClass(viewControllerClass)]) { | |
return; | |
} | |
NSString *viewClassName = viewClass == [UIView class] ? | |
[NSString stringWithFormat:@"%@.view", NSStringFromClass(viewControllerClass)] : | |
[NSString stringWithFormat:@"%@.view: %@", NSStringFromClass(viewControllerClass), NSStringFromClass(viewClass)]; | |
Class newViewClass = NSClassFromString(viewClassName); | |
if (!newViewClass) { | |
newViewClass = objc_allocateClassPair(viewClass, [viewClassName cStringUsingEncoding:NSUTF8StringEncoding], 0); | |
objc_registerClassPair(newViewClass); | |
} | |
object_setClass(self.view, newViewClass); | |
}]; | |
} | |
static BOOL const wml_isKindOfClass(Class class, Class possibleAncestor) { | |
if (class == possibleAncestor) { | |
return YES; | |
} | |
do { | |
class = class_getSuperclass(class); | |
if (class == possibleAncestor) { | |
return YES; | |
} | |
} while (class && class != [NSObject class]); | |
return NO; | |
} | |
@interface UIViewController (WMLViewDebugging) | |
@end | |
@implementation UIViewController (WMLViewDebugging) | |
+ (void)load { | |
@autoreleasepool { | |
static dispatch_once_t onceToken; | |
dispatch_once(&onceToken, ^{ | |
wml_loadViewSEL = @selector(loadView); | |
IMP originalIMP = [UIViewController instanceMethodForSelector:wml_loadViewSEL]; | |
wml_swizzleLoadViewForClass([UIViewController class]); | |
unsigned int classesCount = 0; | |
Class *classList = objc_copyClassList(&classesCount); | |
for (unsigned int i = 0; i < classesCount; ++i) { | |
Class cls = classList[i]; | |
const char *cClassName = class_getName(cls); | |
if (strcmp(cClassName, "JSExport") == 0 || | |
strcmp(cClassName, "Object") == 0 || | |
strcmp(cClassName, "__NSGenericDeallocHandler") == 0 || | |
strcmp(cClassName, "__NSMessageBuilder") == 0 || | |
strcmp(cClassName, "_NSZombie_") == 0){ | |
continue; | |
} | |
// If you encounter crash here, add exception to the previous if case | |
if (cls == [UIViewController class] || | |
!wml_isKindOfClass(cls, [UIViewController class]) || | |
[cls instanceMethodForSelector:wml_loadViewSEL] == originalIMP) { | |
continue; | |
} | |
wml_swizzleLoadViewForClass(cls); | |
} | |
}); | |
} | |
} | |
@end | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment