├── DaiMethodHelper ├── Default-568h@2x.png ├── ILoveDaidouji │ └── ILoveDaidouji.a ├── Category │ ├── NSString+Daidouji1.h │ ├── NSString+Daidouji2.h │ ├── MainViewController+DaidoujiCategory1.h │ ├── MainViewController+DaidoujiCategory2.h │ ├── NSString+Daidouji1.m │ ├── NSString+Daidouji2.m │ ├── MainViewController+DaidoujiCategory1.m │ ├── MainViewController+DaidoujiCategory2.m │ ├── UIAlertView+DaiMethodHelper.h │ └── UIAlertView+ DaiMethodHelper.m ├── AppDelegate.h ├── main.m ├── MainViewController.h ├── AppDelegate.m ├── DaiMethodHelper │ ├── DaiMethodInfomation.h │ ├── DaiMethodHelper.h │ ├── DaiMethodInfomation.m │ └── DaiMethodHelper.m ├── Images.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Info.plist ├── MainViewController.xib └── MainViewController.m ├── DaiMethodHelper.xcodeproj ├── project.xcworkspace │ └── contents.xcworkspacedata ├── xcuserdata │ └── ChilunChen.xcuserdatad │ │ └── xcschemes │ │ └── DaiDuplicateMethodScanner.xcscheme └── project.pbxproj ├── .gitignore └── README.md /DaiMethodHelper/Default-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaidoujiChen/DaiMethodHelper/HEAD/DaiMethodHelper/Default-568h@2x.png -------------------------------------------------------------------------------- /DaiMethodHelper/ILoveDaidouji/ILoveDaidouji.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaidoujiChen/DaiMethodHelper/HEAD/DaiMethodHelper/ILoveDaidouji/ILoveDaidouji.a -------------------------------------------------------------------------------- /DaiMethodHelper.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /DaiMethodHelper/Category/NSString+Daidouji1.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+Daidouji1.h 3 | // DaiMethodHelper 4 | // 5 | // Created by DaidoujiChen on 2015/9/8. 6 | // Copyright (c) 2015年 ChilunChen. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSString (Daidouji1) 12 | 13 | - (NSString *)iLoveDaidouji; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /DaiMethodHelper/Category/NSString+Daidouji2.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+Daidouji2.h 3 | // DaiMethodHelper 4 | // 5 | // Created by DaidoujiChen on 2015/9/8. 6 | // Copyright (c) 2015年 ChilunChen. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSString (Daidouji2) 12 | 13 | - (NSString *)iLoveDaidouji; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /DaiMethodHelper/Category/MainViewController+DaidoujiCategory1.h: -------------------------------------------------------------------------------- 1 | // 2 | // MainViewController+DaidoujiCategory1.h 3 | // DaiMethodHelper 4 | // 5 | // Created by DaidoujiChen on 2015/9/8. 6 | // Copyright (c) 2015年 ChilunChen. All rights reserved. 7 | // 8 | 9 | #import "MainViewController.h" 10 | 11 | @interface MainViewController (DaidoujiCategory1) 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /DaiMethodHelper/Category/MainViewController+DaidoujiCategory2.h: -------------------------------------------------------------------------------- 1 | // 2 | // MainViewController+DaidoujiCategory2.h 3 | // DaiMethodHelper 4 | // 5 | // Created by DaidoujiChen on 2015/9/8. 6 | // Copyright (c) 2015年 ChilunChen. All rights reserved. 7 | // 8 | 9 | #import "MainViewController.h" 10 | 11 | @interface MainViewController (DaidoujiCategory2) 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /DaiMethodHelper/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // DaiMethodHelper 4 | // 5 | // Created by 啟倫 陳 on 2015/9/6. 6 | // Copyright (c) 2015年 ChilunChen. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | 17 | -------------------------------------------------------------------------------- /DaiMethodHelper/Category/NSString+Daidouji1.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+Daidouji1.m 3 | // DaiMethodHelper 4 | // 5 | // Created by DaidoujiChen on 2015/9/8. 6 | // Copyright (c) 2015年 ChilunChen. All rights reserved. 7 | // 8 | 9 | #import "NSString+Daidouji1.h" 10 | 11 | @implementation NSString (Daidouji1) 12 | 13 | - (NSString *)iLoveDaidouji { 14 | return @"iLoveDaidouji1"; 15 | } 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /DaiMethodHelper/Category/NSString+Daidouji2.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+Daidouji2.m 3 | // DaiMethodHelper 4 | // 5 | // Created by DaidoujiChen on 2015/9/8. 6 | // Copyright (c) 2015年 ChilunChen. All rights reserved. 7 | // 8 | 9 | #import "NSString+Daidouji2.h" 10 | 11 | @implementation NSString (Daidouji2) 12 | 13 | - (NSString *)iLoveDaidouji { 14 | return @"iLoveDaidouji2"; 15 | } 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /DaiMethodHelper/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // DaiMethodHelper 4 | // 5 | // Created by 啟倫 陳 on 2015/9/6. 6 | // Copyright (c) 2015年 ChilunChen. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /DaiMethodHelper/MainViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // MainViewController.h 3 | // DaiMethodHelper 4 | // 5 | // Created by 啟倫 陳 on 2015/9/6. 6 | // Copyright (c) 2015年 ChilunChen. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface MainViewController : UIViewController 12 | 13 | + (void)swizzling:(Class)aClass from:(SEL)before to:(SEL)after; 14 | - (NSString *)iLoveDaidouji:(NSString *)input; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /DaiMethodHelper/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // DaiMethodHelper 4 | // 5 | // Created by 啟倫 陳 on 2015/9/6. 6 | // Copyright (c) 2015年 ChilunChen. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | #import "MainViewController.h" 11 | 12 | @implementation AppDelegate 13 | 14 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 15 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 16 | self.window.rootViewController = [MainViewController new]; 17 | [self.window makeKeyAndVisible]; 18 | return YES; 19 | } 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /DaiMethodHelper/DaiMethodHelper/DaiMethodInfomation.h: -------------------------------------------------------------------------------- 1 | // 2 | // DaiMethodInfomation.h 3 | // DaiMethodHelper 4 | // 5 | // Created by 啟倫 陳 on 2015/9/6. 6 | // Copyright (c) 2015年 ChilunChen. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface DaiMethodInfomation : NSObject 12 | 13 | @property (nonatomic, readonly) BOOL isClassMethod; 14 | @property (nonatomic, readonly) NSString *className; 15 | @property (nonatomic, readonly) NSString *categoryName; 16 | @property (nonatomic, readonly) NSString *methodName; 17 | @property (nonatomic, readonly) NSString *fromPath; 18 | @property (nonatomic, readonly) NSUInteger address; 19 | 20 | - (id)initWithAddress:(NSUInteger)address; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /DaiMethodHelper/Category/MainViewController+DaidoujiCategory1.m: -------------------------------------------------------------------------------- 1 | // 2 | // MainViewController+DaidoujiCategory1.m 3 | // DaiMethodHelper 4 | // 5 | // Created by DaidoujiChen on 2015/9/8. 6 | // Copyright (c) 2015年 ChilunChen. All rights reserved. 7 | // 8 | 9 | #import "MainViewController+DaidoujiCategory1.h" 10 | 11 | @implementation MainViewController (DaidoujiCategory1) 12 | 13 | + (void)load { 14 | static dispatch_once_t onceToken; 15 | dispatch_once(&onceToken, ^{ 16 | [self swizzling:[self class] from:@selector(iLoveDaidouji:) to:@selector(swi1_iLoveDaidouji:)]; 17 | }); 18 | } 19 | 20 | - (NSString *)swi1_iLoveDaidouji:(NSString *)input { 21 | NSLog(@"SwizzlingDaidoujiCategory1"); 22 | return [self swi1_iLoveDaidouji:input]; 23 | } 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /DaiMethodHelper/Category/MainViewController+DaidoujiCategory2.m: -------------------------------------------------------------------------------- 1 | // 2 | // MainViewController+DaidoujiCategory2.m 3 | // DaiMethodHelper 4 | // 5 | // Created by DaidoujiChen on 2015/9/8. 6 | // Copyright (c) 2015年 ChilunChen. All rights reserved. 7 | // 8 | 9 | #import "MainViewController+DaidoujiCategory2.h" 10 | 11 | @implementation MainViewController (DaidoujiCategory2) 12 | 13 | + (void)load { 14 | static dispatch_once_t onceToken; 15 | dispatch_once(&onceToken, ^{ 16 | [self swizzling:[self class] from:@selector(iLoveDaidouji:) to:@selector(swi2_iLoveDaidouji:)]; 17 | }); 18 | } 19 | 20 | - (NSString *)swi2_iLoveDaidouji:(NSString *)input { 21 | NSLog(@"SwizzlingDaidoujiCategory2"); 22 | return [self swi2_iLoveDaidouji:input]; 23 | } 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /DaiMethodHelper/DaiMethodHelper/DaiMethodHelper.h: -------------------------------------------------------------------------------- 1 | // 2 | // DaiMethodHelper.h 3 | // DaiMethodHelper 4 | // 5 | // Created by 啟倫 陳 on 2015/9/6. 6 | // Copyright (c) 2015年 ChilunChen. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface DaiMethodHelper : NSObject 12 | 13 | // 掃描所有的 classes, 檢查是否有重複定義的 methods 14 | // 會同時檢查 class methods 與 instance methods 15 | + (void)scanClasses; 16 | 17 | // 掃描特定 class, 會同時檢查 class methods 與 instance methods 18 | + (void)scanClass:(Class)aClass; 19 | 20 | // 驗證 method 確實運行在哪一個 implementation 上, 會同時檢查 class methods 與 instance methods 21 | + (void)verifyClass:(Class)aClass selector:(SEL)selector; 22 | 23 | // 排除萬難的執行某一個 method 24 | + (void *)perform:(id)object selector:(SEL)selector category:(NSString *)category, ...; 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /DaiMethodHelper/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /DaiMethodHelper/Category/UIAlertView+DaiMethodHelper.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIAlertView+Hentai.h 3 | // DaiMethodHelper 4 | // 5 | // Created by DaidoujiChen on 2015/9/8. 6 | // Copyright (c) 2015年 ChilunChen. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | typedef void (^ClickBlock)(NSInteger clickIndex); 12 | typedef void (^CancelBlock)(void); 13 | typedef void (^AccountBlock)(NSString *userName, NSString *password); 14 | 15 | @interface UIAlertView (Hentai) 16 | 17 | + (UIAlertView *)alertViewWithTitle:(NSString *)title message:(NSString *)message; 18 | + (UIAlertView *)alertViewWithTitle:(NSString *)title message:(NSString *)message cancelButtonTitle:(NSString *)cancelButtonTitle; 19 | + (UIAlertView *)alertViewWithTitle:(NSString *)title message:(NSString *)message cancelButtonTitle:(NSString *)cancelButtonTitle otherButtonTitles:(NSArray *)otherButtons onClickIndex:(ClickBlock)clicked onCancel:(CancelBlock)cancelled; 20 | 21 | @property (nonatomic, copy) ClickBlock clicked; 22 | @property (nonatomic, copy) CancelBlock cancelled; 23 | @property (nonatomic, copy) AccountBlock account; 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /DaiMethodHelper/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | tw.tyche.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UIRequiredDeviceCapabilities 26 | 27 | armv7 28 | 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.gitignore.io/api/xcode,objective-c,osx 2 | 3 | ### Xcode ### 4 | # Xcode 5 | # 6 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 7 | 8 | ## Build generated 9 | build/ 10 | DerivedData 11 | 12 | ## Various settings 13 | *.pbxuser 14 | !default.pbxuser 15 | *.mode1v3 16 | !default.mode1v3 17 | *.mode2v3 18 | !default.mode2v3 19 | *.perspectivev3 20 | !default.perspectivev3 21 | xcuserdata 22 | 23 | ## Other 24 | *.xccheckout 25 | *.moved-aside 26 | *.xcuserstate 27 | 28 | 29 | ### Objective-C ### 30 | # Xcode 31 | # 32 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 33 | 34 | ## Build generated 35 | build/ 36 | DerivedData 37 | 38 | ## Various settings 39 | *.pbxuser 40 | !default.pbxuser 41 | *.mode1v3 42 | !default.mode1v3 43 | *.mode2v3 44 | !default.mode2v3 45 | *.perspectivev3 46 | !default.perspectivev3 47 | xcuserdata 48 | 49 | ## Other 50 | *.xccheckout 51 | *.moved-aside 52 | *.xcuserstate 53 | *.xcscmblueprint 54 | 55 | ## Obj-C/Swift specific 56 | *.hmap 57 | *.ipa 58 | 59 | # CocoaPods 60 | # 61 | # We recommend against adding the Pods directory to your .gitignore. However 62 | # you should judge for yourself, the pros and cons are mentioned at: 63 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 64 | # 65 | #Pods/ 66 | 67 | # Carthage 68 | # 69 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 70 | # Carthage/Checkouts 71 | 72 | Carthage/Build 73 | 74 | ### Objective-C Patch ### 75 | *.xcscmblueprint 76 | 77 | 78 | ### OSX ### 79 | .DS_Store 80 | .AppleDouble 81 | .LSOverride 82 | 83 | # Icon must end with two \r 84 | Icon 85 | 86 | 87 | # Thumbnails 88 | ._* 89 | 90 | # Files that might appear in the root of a volume 91 | .DocumentRevisions-V100 92 | .fseventsd 93 | .Spotlight-V100 94 | .TemporaryItems 95 | .Trashes 96 | .VolumeIcon.icns 97 | 98 | # Directories potentially created on remote AFP share 99 | .AppleDB 100 | .AppleDesktop 101 | Network Trash Folder 102 | Temporary Items 103 | .apdisk 104 | -------------------------------------------------------------------------------- /DaiMethodHelper/MainViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /DaiMethodHelper/Category/UIAlertView+ DaiMethodHelper.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIAlertView+DaiMethodHelper.m 3 | // DaiMethodHelper 4 | // 5 | // Created by DaidoujiChen on 2015/9/8. 6 | // Copyright (c) 2015年 ChilunChen. All rights reserved. 7 | // 8 | 9 | #import "UIAlertView+DaiMethodHelper.h" 10 | 11 | #import 12 | 13 | @implementation UIAlertView (Hentai) 14 | 15 | @dynamic clicked, cancelled; 16 | 17 | #pragma mark - dynamic 18 | 19 | - (void)setClicked:(ClickBlock)clicked { 20 | objc_setAssociatedObject(self, @selector(clicked), clicked, OBJC_ASSOCIATION_COPY_NONATOMIC); 21 | } 22 | 23 | - (ClickBlock)clicked { 24 | return objc_getAssociatedObject(self, _cmd); 25 | } 26 | 27 | - (void)setCancelled:(CancelBlock)cancelled { 28 | objc_setAssociatedObject(self, @selector(cancelled), cancelled, OBJC_ASSOCIATION_COPY_NONATOMIC); 29 | } 30 | 31 | - (CancelBlock)cancelled { 32 | return objc_getAssociatedObject(self, _cmd); 33 | } 34 | 35 | - (void)setAccount:(AccountBlock)hentai_account { 36 | objc_setAssociatedObject(self, @selector(account), hentai_account, OBJC_ASSOCIATION_COPY_NONATOMIC); 37 | } 38 | 39 | - (AccountBlock)account { 40 | return objc_getAssociatedObject(self, _cmd); 41 | } 42 | 43 | #pragma mark - instance method 44 | 45 | + (UIAlertView *)alertViewWithTitle:(NSString *)title message:(NSString *)message { 46 | return [UIAlertView alertViewWithTitle:title message:message cancelButtonTitle:@"取消"]; 47 | } 48 | 49 | + (UIAlertView *)alertViewWithTitle:(NSString *)title message:(NSString *)message cancelButtonTitle:(NSString *)cancelButtonTitle { 50 | UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title message:message delegate:nil cancelButtonTitle:cancelButtonTitle otherButtonTitles:nil]; 51 | [alert show]; 52 | return alert; 53 | } 54 | 55 | + (UIAlertView *)alertViewWithTitle:(NSString *)title message:(NSString *)message cancelButtonTitle:(NSString *)cancelButtonTitle otherButtonTitles:(NSArray *)otherButtons onClickIndex:(ClickBlock)clicked onCancel:(CancelBlock)cancelled { 56 | UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title message:message delegate:[self class] cancelButtonTitle:cancelButtonTitle otherButtonTitles:nil]; 57 | alert.clicked = clicked; 58 | alert.cancelled = cancelled; 59 | 60 | for (NSString *buttonTitle in otherButtons) { 61 | [alert addButtonWithTitle:buttonTitle]; 62 | } 63 | [alert show]; 64 | return alert; 65 | } 66 | 67 | #pragma mark - UIAlertViewDelegate 68 | 69 | + (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex { 70 | if (buttonIndex == alertView.cancelButtonIndex) { 71 | if (alertView.cancelled) { 72 | alertView.cancelled(); 73 | } 74 | } 75 | else { 76 | if (alertView.clicked) { 77 | alertView.clicked(buttonIndex - 1); 78 | } 79 | } 80 | } 81 | 82 | @end 83 | -------------------------------------------------------------------------------- /DaiMethodHelper/DaiMethodHelper/DaiMethodInfomation.m: -------------------------------------------------------------------------------- 1 | // 2 | // DaiMethodInfomation.m 3 | // DaiMethodHelper 4 | // 5 | // Created by 啟倫 陳 on 2015/9/6. 6 | // Copyright (c) 2015年 ChilunChen. All rights reserved. 7 | // 8 | 9 | #import "DaiMethodInfomation.h" 10 | #import 11 | 12 | @interface DaiMethodInfomation () 13 | 14 | @property (nonatomic, assign) BOOL isClassMethod; 15 | @property (nonatomic, strong) NSString *className; 16 | @property (nonatomic, strong) NSString *categoryName; 17 | @property (nonatomic, strong) NSString *methodName; 18 | @property (nonatomic, strong) NSString *fromPath; 19 | @property (nonatomic, assign) NSUInteger address; 20 | 21 | @end 22 | 23 | @implementation DaiMethodInfomation 24 | 25 | #pragma mark - method override 26 | 27 | - (NSString *)description { 28 | NSMutableString *description = [NSMutableString string]; 29 | [description appendFormat:@"%@", self.isClassMethod ? @"+" : @"-"]; 30 | [description appendFormat:@"%@ ", self.methodName]; 31 | [description appendFormat:@"(%p) ", (void *)self.address]; 32 | [description appendFormat:@"in %@", self.className]; 33 | if (self.categoryName) { 34 | [description appendFormat:@"(%@)", self.categoryName]; 35 | } 36 | [description appendFormat:@" from %@", [self.fromPath lastPathComponent]]; 37 | return description; 38 | } 39 | 40 | #pragma mark - private instance method 41 | 42 | // symbol like -[ClassName(CategoryName) MethodName] 43 | - (BOOL)fillInfomation:(NSString *)symbol { 44 | self.isClassMethod = ([symbol characterAtIndex:0] == '+'); 45 | 46 | NSCharacterSet *removeCharacter = [NSCharacterSet characterSetWithCharactersInString:@"+-[]"]; 47 | NSArray *splitNames = [[symbol stringByTrimmingCharactersInSet:removeCharacter] componentsSeparatedByString:@" "]; 48 | if (splitNames.count < 2) { 49 | return NO; 50 | } 51 | self.methodName = splitNames[1]; 52 | 53 | NSRange startOfCategoryName = [splitNames[0] rangeOfString:@"("]; 54 | if (startOfCategoryName.location == NSNotFound) { 55 | self.className = splitNames[0]; 56 | self.categoryName = nil; 57 | } 58 | else { 59 | NSRange endOfCategoryName = [splitNames[0] rangeOfString:@")"]; 60 | self.className = [splitNames[0] substringToIndex:startOfCategoryName.location]; 61 | NSUInteger location = startOfCategoryName.location + 1; 62 | NSUInteger length = endOfCategoryName.location - location; 63 | self.categoryName = [splitNames[0] substringWithRange:NSMakeRange(location, length)]; 64 | } 65 | return YES; 66 | } 67 | 68 | #pragma mark - instance method 69 | 70 | - (id)initWithAddress:(NSUInteger)address { 71 | self = [super init]; 72 | if (self) { 73 | Dl_info info; 74 | if (dladdr((const void *)(NSUInteger)address, &info)) { 75 | self.address = address; 76 | 77 | BOOL isSuccess = YES; 78 | if (info.dli_fname) { 79 | self.fromPath = [NSString stringWithUTF8String:info.dli_fname]; 80 | } 81 | else { 82 | isSuccess = NO; 83 | } 84 | 85 | if (info.dli_sname) { 86 | isSuccess = [self fillInfomation:[NSString stringWithUTF8String:info.dli_sname]]; 87 | } 88 | else { 89 | isSuccess = NO; 90 | } 91 | 92 | if (!isSuccess) { 93 | return nil; 94 | } 95 | } 96 | else { 97 | return nil; 98 | } 99 | } 100 | return self; 101 | } 102 | 103 | @end 104 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DaiMethodHelper 2 | 3 | A Tool for scan duplicate methods, verify method implementation, or force invoke the method! 4 | 5 | DaidoujiChen 6 | 7 | daidoujichen@gmail.com 8 | 9 | ## Special Thanks 10 | [ryanolsonk](https://github.com/ryanolsonk) 11 | 12 | [OptimusKe](https://github.com/OptimusKe) 13 | 14 | [MiaShopgal](https://github.com/MiaShopgal) 15 | 16 | # Overview 17 | * Scan single class for duplicate methods in categories. 18 | * Like scan single class, we also can scan all of them! 19 | * Verify a method in a class(metaclass). Lookup the current implementation. 20 | * Force to invoke a method. Can not be dodge, swizzling penetration. 21 | 22 | # Usage 23 | 24 | ## Scan 25 | If we want to check if there are any duplicate methods in `NSString`. Using `[DaiMethodHelper scanClass:]` 26 | 27 | ````` 28 | [DaiMethodHelper scanClass:[NSString class]]; 29 | 30 | output: 31 | ===== Duplicate in NSString ===== 32 | -iLoveDaidouji (0x10db6f5eb) in NSString(Daidouji3) from DaiMethodHelper 33 | -iLoveDaidouji (0x10db6ea70) in NSString(Daidouji2) from DaiMethodHelper 34 | -iLoveDaidouji (0x10db6ea50) in NSString(Daidouji1) from DaiMethodHelper 35 | ===== Duplicate in NSString ===== 36 | -_initWithUTF8String:maxLength: (0x10e7f9316) in NSString(UISafeInstantiators) from UIKit 37 | -_initWithUTF8String:maxLength: (0x111055a1f) in NSString(BaseBoard) from BaseBoard 38 | 39 | ````` 40 | 41 | We found there are three methods named `iLoveDaidouji` in categories `Daidouji1`, `Daidouji2` and `Daidouji3`. 42 | 43 | In the runtime, which one will be invoked? 44 | 45 | ## Verify 46 | For this concern, `DaiMethodHelper` provide a method to verify. This method named `[DaiMethodHelper verifyClass:selector:]` 47 | 48 | ````` 49 | [DaiMethodHelper verifyClass:[NSString class] selector:@selector(iLoveDaidouji)]; 50 | 51 | output: 52 | * -iLoveDaidouji (0x1022225eb) in NSString(Daidouji3) from DaiMethodHelper 53 | -iLoveDaidouji (0x102221a70) in NSString(Daidouji2) from DaiMethodHelper 54 | -iLoveDaidouji (0x102221a50) in NSString(Daidouji1) from DaiMethodHelper 55 | ````` 56 | 57 | As the output, runtime choose the method `iLoveDaidouji` in category `Daidouji3`. 58 | 59 | Check it out! 60 | 61 | ````` 62 | NSString *string = [NSString new]; 63 | NSLog(@"%@", [string iLoveDaidouji]); 64 | 65 | output: 66 | 2015-09-10 15:53:47.727 DaiMethodHelper[9259:212520] iLoveDaidouji3 67 | ````` 68 | 69 | Yes, it run on category `Daidouji3` correctly. And then, is it possible to run the method in category `Daidouji1`? 70 | 71 | ## Force 72 | In this case, by default, runtime never choose the method in category `Daidouji1`. We need to use a little trick to done it. 73 | 74 | ````` 75 | NSString *string = [NSString new]; 76 | NSLog(@"%@", [DaiMethodHelper perform:string selector:@selector(iLoveDaidouji) category:@"Daidouji1"]); 77 | 78 | output: 79 | found -iLoveDaidouji (0x109589a50) in NSString(Daidouji1) from DaiMethodHelper 80 | 2015-09-10 16:03:24.666 DaiMethodHelper[9391:219463] iLoveDaidouji1 81 | ````` 82 | 83 | The result show, we found a method `-iLoveDaidouji` in category `Daidouji1`. And perform it. 84 | 85 | ## Swizzling? 86 | Finally we made a simple method swizzling in `MainViewController`. like 87 | 88 | > \- (NSString *)swi2_iLoveDaidouji:(NSString *)input { 89 | > 90 | > NSLog(@"SwizzlingDaidoujiCategory2"); 91 | > 92 | > > \- (NSString *)swi1_iLoveDaidouji:(NSString *)input { 93 | > > 94 | > > NSLog(@"SwizzlingDaidoujiCategory1"); 95 | > > 96 | > > > \- (NSString *)iLoveDaidouji:(NSString *)input { 97 | > > > 98 | > > > NSLog(@"OriginDaidouji"); 99 | > > > 100 | > > > return [NSString stringWithFormat:@"iLoveDaidouji+%@", input]; 101 | > > > 102 | > > > } 103 | > > 104 | > > } 105 | > 106 | > } 107 | 108 | ````` 109 | NSLog(@"%@", [self iLoveDaidouji:@"very much"]); 110 | 111 | output: 112 | 2015-09-10 16:10:35.816 DaiMethodHelper[9510:224080] SwizzlingDaidoujiCategory2 113 | 2015-09-10 16:10:35.817 DaiMethodHelper[9510:224080] SwizzlingDaidoujiCategory1 114 | 2015-09-10 16:10:35.817 DaiMethodHelper[9510:224080] OriginDaidouji 115 | 2015-09-10 16:10:35.817 DaiMethodHelper[9510:224080] iLoveDaidouji+very much 116 | ````` 117 | 118 | The interesting thing is we can also use `[DaiMethodHelper perform:selector:category:]` pass through all whe swizzling. 119 | 120 | ````` 121 | NSLog(@"%@", [DaiMethodHelper perform:self selector:@selector(iLoveDaidouji:) category:nil, @"very much"]); 122 | 123 | output: 124 | swizzling by -swi2_iLoveDaidouji: (0x10992d130) in MainViewController(DaidoujiCategory2) from DaiMethodHelper 125 | swizzling by -swi1_iLoveDaidouji: (0x10992adb0) in MainViewController(DaidoujiCategory1) from DaiMethodHelper 126 | found -iLoveDaidouji: (0x10992ce40) in MainViewController from DaiMethodHelper 127 | 2015-09-10 16:19:03.590 DaiMethodHelper[9617:228273] OriginDaidouji 128 | 2015-09-10 16:19:03.591 DaiMethodHelper[9617:228273] iLoveDaidouji+very much 129 | ````` 130 | 131 | The method only run the original code. Ignore all the swizzle. Fun! 132 | 133 | # Warning 134 | I am not sure apple allow the method `invokeUsingIMP:` in `NSInvocation` or not. 135 | 136 | -------------------------------------------------------------------------------- /DaiMethodHelper.xcodeproj/xcuserdata/ChilunChen.xcuserdatad/xcschemes/DaiDuplicateMethodScanner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 75 | 77 | 83 | 84 | 85 | 86 | 87 | 88 | 94 | 96 | 102 | 103 | 104 | 105 | 107 | 108 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /DaiMethodHelper/MainViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // MainViewController.m 3 | // DaiMethodHelper 4 | // 5 | // Created by 啟倫 陳 on 2015/9/6. 6 | // Copyright (c) 2015年 ChilunChen. All rights reserved. 7 | // 8 | 9 | #import "MainViewController.h" 10 | #import 11 | #import "DaiMethodHelper.h" 12 | #import "UIAlertView+DaiMethodHelper.h" 13 | #import "NSString+Daidouji1.h" 14 | #import "NSString+Daidouji2.h" 15 | 16 | @interface MainViewController () 17 | 18 | @property (nonatomic, assign) NSInteger status; 19 | 20 | @end 21 | 22 | @implementation MainViewController 23 | 24 | #pragma mark - ibaction 25 | 26 | - (IBAction)pressButtonAction:(id)sender { 27 | __weak MainViewController *weakSelf = self; 28 | printf("\n--------------- Status%td ---------------\n\n\n", self.status); 29 | switch (self.status) { 30 | case -1: 31 | { 32 | [UIAlertView alertViewWithTitle:@"Warning!!!" message:@"Please change to console log page for this DEMO thx. :)" cancelButtonTitle:nil otherButtonTitles:@[@"Next"] onClickIndex: ^(NSInteger clickIndex) { 33 | [weakSelf pressButtonAction:nil]; 34 | } onCancel:nil]; 35 | break; 36 | } 37 | 38 | case 0: 39 | { 40 | printf("call [DaiMethodHelper scanClasses]\n\n"); 41 | [DaiMethodHelper scanClasses]; 42 | [UIAlertView alertViewWithTitle:@"Scan Methods In All Classes" message:@"You would find duplicate method in console log (if there's any)" cancelButtonTitle:nil otherButtonTitles:@[@"Next"] onClickIndex: ^(NSInteger clickIndex) { 43 | [weakSelf pressButtonAction:nil]; 44 | } onCancel:nil]; 45 | break; 46 | } 47 | 48 | case 1: 49 | { 50 | printf("call [DaiMethodHelper scanClass:[NSString class]]\n\n"); 51 | [DaiMethodHelper scanClass:[NSString class]]; 52 | [UIAlertView alertViewWithTitle:@"Scan Methods In Specific Class" message:@"There are three methods duplicate named \"iLoveDaidouji\" in \"NSString\"" cancelButtonTitle:nil otherButtonTitles:@[@"Next"] onClickIndex: ^(NSInteger clickIndex) { 53 | [weakSelf pressButtonAction:nil]; 54 | } onCancel:nil]; 55 | break; 56 | } 57 | 58 | case 2: 59 | { 60 | printf("We would not know which method will be invoked at runtime.\n\n"); 61 | [UIAlertView alertViewWithTitle:@"Tip" message:@"We would not know which method will be invoked at runtime." cancelButtonTitle:nil otherButtonTitles:@[@"Next"] onClickIndex: ^(NSInteger clickIndex) { 62 | [weakSelf pressButtonAction:nil]; 63 | } onCancel:nil]; 64 | break; 65 | } 66 | 67 | case 3: 68 | { 69 | printf("call [DaiMethodHelper verifyClass:[NSString class] selector:@selector(iLoveDaidouji)]\n\n"); 70 | [DaiMethodHelper verifyClass:[NSString class] selector:@selector(iLoveDaidouji)]; 71 | [UIAlertView alertViewWithTitle:@"Verify This Method" message:@"Now we know, it will invoke the method implement in category \"Daidouji3\" when we call method \"iLoveDaidouji\"" cancelButtonTitle:nil otherButtonTitles:@[@"Next"] onClickIndex: ^(NSInteger clickIndex) { 72 | [weakSelf pressButtonAction:nil]; 73 | } onCancel:nil]; 74 | break; 75 | } 76 | 77 | case 4: 78 | { 79 | 80 | NSString *string = [NSString new]; 81 | printf("NSString *string = [NSString new];\n"); 82 | printf("print [string iLoveDaidouji].UTF8String\n"); 83 | printf("return %s\n\n", [string iLoveDaidouji].UTF8String); 84 | [UIAlertView alertViewWithTitle:@"Demo" message:@"The return value is \"iLoveDaidouji\" when \"iLoveDaidouji\" is called directly" cancelButtonTitle:nil otherButtonTitles:@[@"Next"] onClickIndex: ^(NSInteger clickIndex) { 85 | [weakSelf pressButtonAction:nil]; 86 | } onCancel:nil]; 87 | break; 88 | } 89 | 90 | case 5: 91 | { 92 | NSString *string = [NSString new]; 93 | printf("NSString *string = [NSString new];\n"); 94 | printf("print [(NSString *)[DaiMethodHelper perform:string selector:@selector(iLoveDaidouji) category:@\"Daidouji1\"] UTF8String]\n"); 95 | printf("return %s\n\n", [(NSString *)[DaiMethodHelper perform:string selector:@selector(iLoveDaidouji) category:@"Daidouji1"] UTF8String]); 96 | [UIAlertView alertViewWithTitle:@"Demo" message:@"Or we can force to invoke the method \"iLoveDaidouji\" in category \"Daidouji1\"" cancelButtonTitle:nil otherButtonTitles:@[@"Next"] onClickIndex: ^(NSInteger clickIndex) { 97 | [weakSelf pressButtonAction:nil]; 98 | } onCancel:nil]; 99 | break; 100 | } 101 | 102 | case 6: 103 | { 104 | printf("run [self iLoveDaidouji:@\"love\"]\n\n"); 105 | NSLog(@"%@", [self iLoveDaidouji:@"love"]); 106 | [UIAlertView alertViewWithTitle:@"Swizzling" message:@"Swizzling is a powerful tool to help us, and have better understanding of third party source. Our method might be injected into any code that we would not know." cancelButtonTitle:nil otherButtonTitles:@[@"Next"] onClickIndex: ^(NSInteger clickIndex) { 107 | [weakSelf pressButtonAction:nil]; 108 | } onCancel:nil]; 109 | break; 110 | } 111 | 112 | case 7: 113 | { 114 | printf("run [DaiMethodHelper perform:self selector:@selector(iLoveDaidouji:) category:nil, @\"love\"]\n\n"); 115 | NSLog(@"%@", [DaiMethodHelper perform:self selector:@selector(iLoveDaidouji:) category:nil, @"love"]); 116 | [UIAlertView alertViewWithTitle:nil message:@"It is a possible way to protect our methods." cancelButtonTitle:@"Finish"]; 117 | break; 118 | } 119 | 120 | default: 121 | break; 122 | } 123 | printf("\n\n\n--------------- Status%td ---------------", self.status++); 124 | } 125 | 126 | #pragma mark - class method 127 | 128 | + (void)swizzling:(Class)aClass from:(SEL)before to:(SEL)after { 129 | SEL originalSelector = before; 130 | SEL swizzledSelector = after; 131 | 132 | Method originalMethod = class_getInstanceMethod(aClass, originalSelector); 133 | Method swizzledMethod = class_getInstanceMethod(aClass, swizzledSelector); 134 | 135 | BOOL didAddMethod = class_addMethod(aClass, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod)); 136 | 137 | if (didAddMethod) { 138 | class_replaceMethod(aClass, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod)); 139 | } 140 | else { 141 | method_exchangeImplementations(originalMethod, swizzledMethod); 142 | } 143 | } 144 | 145 | #pragma mark - instance method 146 | 147 | - (NSString *)iLoveDaidouji:(NSString *)input { 148 | NSLog(@"OriginDaidouji"); 149 | return [NSString stringWithFormat:@"iLoveDaidouji+%@", input]; 150 | } 151 | 152 | #pragma mark - life cycle 153 | 154 | - (void)viewDidLoad { 155 | [super viewDidLoad]; 156 | self.status = -1; 157 | } 158 | 159 | @end 160 | -------------------------------------------------------------------------------- /DaiMethodHelper/DaiMethodHelper/DaiMethodHelper.m: -------------------------------------------------------------------------------- 1 | // 2 | // DaiMethodHelper.m 3 | // DaiMethodHelper 4 | // 5 | // Created by 啟倫 陳 on 2015/9/6. 6 | // Copyright (c) 2015年 ChilunChen. All rights reserved. 7 | // 8 | 9 | #import "DaiMethodHelper.h" 10 | #import 11 | #import "DaiMethodInfomation.h" 12 | 13 | @implementation DaiMethodHelper 14 | 15 | #pragma mark - private class method 16 | 17 | // 整理出該 class 中所有的 methods, filter 可以決定是不是有需要過濾掉的東西 18 | + (NSDictionary *)methodsInClass:(Class)aClass filterRule:(BOOL (^)(Method method))filter { 19 | 20 | // 列出所有 methods 21 | unsigned int count = 0; 22 | Method *methods = class_copyMethodList(aClass, &count); 23 | NSMutableDictionary *addressMappingTable = [NSMutableDictionary dictionary]; 24 | for (unsigned int index = 0; index < count; index++) { 25 | 26 | // 需要過濾, 且過濾判斷為不需要時, 跳過這個 method 27 | if (filter && !filter(methods[index])) { 28 | continue; 29 | } 30 | 31 | NSString *methodName = [NSString stringWithUTF8String:sel_getName(method_getName(methods[index]))]; 32 | NSMutableArray *addresses = addressMappingTable[methodName]; 33 | if (!addresses) { 34 | addresses = [NSMutableArray array]; 35 | addressMappingTable[methodName] = addresses; 36 | } 37 | [addresses addObject:@((NSUInteger)method_getImplementation(methods[index]))]; 38 | } 39 | free(methods); 40 | return addressMappingTable; 41 | } 42 | 43 | // 掃描某一個固定的 class 44 | + (void)scan:(Class)aClass { 45 | 46 | // 先將 methods 按照名字分類 47 | NSDictionary *addressMappingTable = [self methodsInClass:aClass filterRule:nil]; 48 | 49 | [addressMappingTable enumerateKeysAndObjectsUsingBlock: ^(NSString *key, NSMutableArray *addresses, BOOL *stop) { 50 | 51 | // 找出重複兩次以上的 method name, 並且區分為 category methods 與 nativa methods 52 | if (addresses.count > 1) { 53 | NSMutableArray *categoryMethods = [NSMutableArray array]; 54 | NSMutableArray *nativeMethods = [NSMutableArray array]; 55 | [addresses enumerateObjectsUsingBlock: ^(NSNumber *address, NSUInteger idx, BOOL *stop) { 56 | DaiMethodInfomation *information = [[DaiMethodInfomation alloc] initWithAddress:address.unsignedIntegerValue]; 57 | if (information) { 58 | if (information.categoryName) { 59 | [categoryMethods addObject:information]; 60 | } 61 | else { 62 | [nativeMethods addObject:information]; 63 | } 64 | } 65 | }]; 66 | 67 | printf("===== Duplicate in %s =====\n", class_getName(aClass)); 68 | [categoryMethods enumerateObjectsUsingBlock: ^(id obj, NSUInteger idx, BOOL *stop) { 69 | printf("%s\n", [obj description].UTF8String); 70 | }]; 71 | 72 | [nativeMethods enumerateObjectsUsingBlock: ^(id obj, NSUInteger idx, BOOL *stop) { 73 | printf("%s\n", [obj description].UTF8String); 74 | }]; 75 | } 76 | }]; 77 | } 78 | 79 | // 驗證指定的 selector 運行哪一個 implementation 80 | + (void)verify:(Class)aClass selector:(SEL)selector { 81 | 82 | // 過濾掉不需要的 method name 83 | NSDictionary *addressMappingTable = [self methodsInClass:aClass filterRule: ^BOOL(Method method) { 84 | return (strcmp(sel_getName(selector), sel_getName(method_getName(method))) == 0); 85 | }]; 86 | 87 | IMP currentIMP = class_getMethodImplementation(aClass, selector); 88 | [addressMappingTable[NSStringFromSelector(selector)] enumerateObjectsUsingBlock: ^(NSNumber *address, NSUInteger idx, BOOL *stop) { 89 | DaiMethodInfomation *information = [[DaiMethodInfomation alloc] initWithAddress:address.unsignedIntegerValue]; 90 | if (information) { 91 | printf("%c %s\n", ((NSUInteger)currentIMP == address.unsignedIntegerValue) ? '*' : ' ', [information description].UTF8String); 92 | } 93 | }]; 94 | } 95 | 96 | // 有些 class 會被轉成像是 __NSCFConstantString, 但是本質上他是 NSString 的一個子類 97 | // 這邊可以把一些狀況導正 98 | + (Class)tollFreeClass:(id)object { 99 | if ([object isKindOfClass:[NSCalendar class]]) { 100 | return [NSCalendar class]; 101 | } 102 | else if ([object isKindOfClass:[NSData class]]) { 103 | return [NSData class]; 104 | } 105 | else if ([object isKindOfClass:[NSError class]]) { 106 | return [NSError class]; 107 | } 108 | else if ([object isKindOfClass:[NSLocale class]]) { 109 | return [NSLocale class]; 110 | } 111 | else if ([object isKindOfClass:[NSArray class]]) { 112 | return [NSArray class]; 113 | } 114 | else if ([object isKindOfClass:[NSMutableArray class]]) { 115 | return [NSMutableArray class]; 116 | } 117 | else if ([object isKindOfClass:[NSAttributedString class]]) { 118 | return [NSAttributedString class]; 119 | } 120 | else if ([object isKindOfClass:[NSMutableAttributedString class]]) { 121 | return [NSMutableAttributedString class]; 122 | } 123 | else if ([object isKindOfClass:[NSCharacterSet class]]) { 124 | return [NSCharacterSet class]; 125 | } 126 | else if ([object isKindOfClass:[NSMutableCharacterSet class]]) { 127 | return [NSMutableCharacterSet class]; 128 | } 129 | else if ([object isKindOfClass:[NSDate class]]) { 130 | return [NSDate class]; 131 | } 132 | else if ([object isKindOfClass:[NSMutableData class]]) { 133 | return [NSMutableData class]; 134 | } 135 | else if ([object isKindOfClass:[NSDictionary class]]) { 136 | return [NSDictionary class]; 137 | } 138 | else if ([object isKindOfClass:[NSMutableDictionary class]]) { 139 | return [NSMutableDictionary class]; 140 | } 141 | else if ([object isKindOfClass:[NSSet class]]) { 142 | return [NSSet class]; 143 | } 144 | else if ([object isKindOfClass:[NSMutableSet class]]) { 145 | return [NSMutableSet class]; 146 | } 147 | else if ([object isKindOfClass:[NSString class]]) { 148 | return [NSString class]; 149 | } 150 | else if ([object isKindOfClass:[NSMutableString class]]) { 151 | return [NSMutableString class]; 152 | } 153 | else if ([object isKindOfClass:[NSNumber class]]) { 154 | return [NSNumber class]; 155 | } 156 | else if ([object isKindOfClass:[NSInputStream class]]) { 157 | return [NSInputStream class]; 158 | } 159 | else if ([object isKindOfClass:[NSTimer class]]) { 160 | return [NSTimer class]; 161 | } 162 | else if ([object isKindOfClass:[NSTimeZone class]]) { 163 | return [NSTimeZone class]; 164 | } 165 | else if ([object isKindOfClass:[NSURL class]]) { 166 | return [NSURL class]; 167 | } 168 | else if ([object isKindOfClass:[NSOutputStream class]]) { 169 | return [NSOutputStream class]; 170 | } 171 | else { 172 | return [object class]; 173 | } 174 | } 175 | 176 | + (NSString *)spaceGenerator:(NSInteger)spaceCount { 177 | NSMutableString *spaceString = [NSMutableString string]; 178 | for (NSInteger space = 0; space < spaceCount; space++) { 179 | [spaceString appendString:@" "]; 180 | } 181 | return spaceString; 182 | } 183 | 184 | #pragma mark - class method 185 | 186 | + (void)scanClasses { 187 | unsigned int count; 188 | count = objc_getClassList(NULL, 0); 189 | 190 | // 取得所有存活的 classes 191 | if (count) { 192 | Class *classes = (__unsafe_unretained Class *)malloc(sizeof(Class) * count); 193 | count = objc_getClassList(classes, count); 194 | for (unsigned int index = 0; index < count; index++) { 195 | [self scanClass:classes[index]]; 196 | } 197 | free(classes); 198 | } 199 | } 200 | 201 | + (void)scanClass:(Class)aClass { 202 | [self scan:aClass]; 203 | [self scan:objc_getMetaClass(class_getName(aClass))]; 204 | } 205 | 206 | + (void)verifyClass:(Class)aClass selector:(SEL)selector { 207 | 208 | // 分別對 class methods 與 instance methods 驗證 209 | [self verify:aClass selector:selector]; 210 | [self verify:objc_getMetaClass(class_getName(aClass)) selector:selector]; 211 | } 212 | 213 | + (void *)perform:(id)object selector:(SEL)selector category:(NSString *)category, ... { 214 | 215 | // 先找到鎖定的那個 method implementation 216 | __block DaiMethodInfomation *information = nil; 217 | __block BOOL swizzlingDetect = NO; 218 | __block SEL targetSelector = selector; 219 | __block NSInteger swizzlingCount = 0; 220 | do { 221 | swizzlingDetect = NO; 222 | [self methodsInClass:[self tollFreeClass:object] filterRule: ^BOOL(Method method) { 223 | if (strcmp(sel_getName(targetSelector), sel_getName(method_getName(method))) == 0) { 224 | DaiMethodInfomation *newInformation = [[DaiMethodInfomation alloc] initWithAddress:(NSUInteger)method_getImplementation(method)]; 225 | 226 | // 最後需要判別該 method 有沒有被 swizzling 227 | swizzlingDetect = (![newInformation.methodName isEqualToString:NSStringFromSelector(selector)]); 228 | if (swizzlingDetect) { 229 | printf("%sswizzling by %s\n", [self spaceGenerator:swizzlingCount++].UTF8String, [newInformation description].UTF8String); 230 | targetSelector = NSSelectorFromString(newInformation.methodName); 231 | } 232 | else { 233 | 234 | // 判斷是不是正確選定的 category 235 | BOOL isCorrectCategory = (!category && !newInformation.categoryName) || ([newInformation.categoryName isEqualToString:category]); 236 | 237 | if (isCorrectCategory) { 238 | printf("%sfound %s\n", [self spaceGenerator:swizzlingCount++].UTF8String, [newInformation description].UTF8String); 239 | information = newInformation; 240 | } 241 | } 242 | } 243 | return NO; 244 | }]; 245 | } while (swizzlingDetect); 246 | 247 | // 如果有找到該一個 implementation 248 | if (information) { 249 | 250 | // 建立 invocation 251 | id dummyObject = [[self tollFreeClass:object] new]; 252 | NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[dummyObject methodSignatureForSelector:targetSelector]]; 253 | [invocation setTarget:object]; 254 | [invocation setSelector:targetSelector]; 255 | 256 | // 填入參數 257 | va_list list; 258 | va_start(list, category); 259 | for (NSUInteger index = 2; index < invocation.methodSignature.numberOfArguments; index++) { 260 | void *var = va_arg(list, void *); 261 | [invocation setArgument:&var atIndex:index]; 262 | } 263 | va_end(list); 264 | 265 | // 運行 266 | NSArray *invokeComponents = @[@"in", @"vok", @"eUsi", @"ngI", @"MP", @":"]; 267 | SEL invokeSelector = NSSelectorFromString([invokeComponents componentsJoinedByString:@""]); 268 | void (*invokeIMP)(id, SEL, void *) = (void (*)(id, SEL, void *))class_getMethodImplementation([self tollFreeClass:invocation], invokeSelector); 269 | invokeIMP(invocation, invokeSelector, (void *)information.address); 270 | 271 | // 如果有回傳值 272 | if (invocation.methodSignature.methodReturnType[0] != 'v') { 273 | void *returnValue; 274 | [invocation getReturnValue:&returnValue]; 275 | return returnValue; 276 | } 277 | } 278 | return 0; 279 | } 280 | 281 | @end 282 | -------------------------------------------------------------------------------- /DaiMethodHelper.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 019A17731B9C2BF800BB8986 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 019A17721B9C2BF800BB8986 /* main.m */; }; 11 | 019A17761B9C2BF800BB8986 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 019A17751B9C2BF800BB8986 /* AppDelegate.m */; }; 12 | 019A177E1B9C2BF800BB8986 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 019A177D1B9C2BF800BB8986 /* Images.xcassets */; }; 13 | 019A17971B9C2C1C00BB8986 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 019A17961B9C2C1C00BB8986 /* Default-568h@2x.png */; }; 14 | 019A179C1B9C2C4F00BB8986 /* MainViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 019A179A1B9C2C4F00BB8986 /* MainViewController.m */; }; 15 | 019A179D1B9C2C4F00BB8986 /* MainViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 019A179B1B9C2C4F00BB8986 /* MainViewController.xib */; }; 16 | 019A17A01B9C2CF700BB8986 /* DaiMethodHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 019A179F1B9C2CF700BB8986 /* DaiMethodHelper.m */; }; 17 | 019A17A61B9C86F000BB8986 /* DaiMethodInfomation.m in Sources */ = {isa = PBXBuildFile; fileRef = 019A17A51B9C86F000BB8986 /* DaiMethodInfomation.m */; }; 18 | 1C40724F1B9D78A9001F386C /* ILoveDaidouji.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 01AD39E41B9C95A2008BADEC /* ILoveDaidouji.a */; }; 19 | 1C6ECD1E1B9EB334003EE818 /* NSString+Daidouji1.m in Sources */ = {isa = PBXBuildFile; fileRef = 1C6ECD1D1B9EB334003EE818 /* NSString+Daidouji1.m */; }; 20 | 1C6ECD211B9EB39A003EE818 /* NSString+Daidouji2.m in Sources */ = {isa = PBXBuildFile; fileRef = 1C6ECD201B9EB39A003EE818 /* NSString+Daidouji2.m */; }; 21 | 1C6ECD241B9EB454003EE818 /* MainViewController+DaidoujiCategory1.m in Sources */ = {isa = PBXBuildFile; fileRef = 1C6ECD231B9EB454003EE818 /* MainViewController+DaidoujiCategory1.m */; }; 22 | 1C6ECD271B9EB58A003EE818 /* MainViewController+DaidoujiCategory2.m in Sources */ = {isa = PBXBuildFile; fileRef = 1C6ECD261B9EB58A003EE818 /* MainViewController+DaidoujiCategory2.m */; }; 23 | 1C6ECD2A1B9EB809003EE818 /* UIAlertView+ DaiMethodHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 1C6ECD291B9EB809003EE818 /* UIAlertView+ DaiMethodHelper.m */; }; 24 | /* End PBXBuildFile section */ 25 | 26 | /* Begin PBXFileReference section */ 27 | 019A176D1B9C2BF800BB8986 /* DaiMethodHelper.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DaiMethodHelper.app; sourceTree = BUILT_PRODUCTS_DIR; }; 28 | 019A17711B9C2BF800BB8986 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 29 | 019A17721B9C2BF800BB8986 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 30 | 019A17741B9C2BF800BB8986 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 31 | 019A17751B9C2BF800BB8986 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 32 | 019A177D1B9C2BF800BB8986 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 33 | 019A17961B9C2C1C00BB8986 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; }; 34 | 019A17991B9C2C4F00BB8986 /* MainViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MainViewController.h; sourceTree = ""; }; 35 | 019A179A1B9C2C4F00BB8986 /* MainViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MainViewController.m; sourceTree = ""; }; 36 | 019A179B1B9C2C4F00BB8986 /* MainViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MainViewController.xib; sourceTree = ""; }; 37 | 019A179E1B9C2CF700BB8986 /* DaiMethodHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DaiMethodHelper.h; sourceTree = ""; }; 38 | 019A179F1B9C2CF700BB8986 /* DaiMethodHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DaiMethodHelper.m; sourceTree = ""; }; 39 | 019A17A41B9C86F000BB8986 /* DaiMethodInfomation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DaiMethodInfomation.h; sourceTree = ""; }; 40 | 019A17A51B9C86F000BB8986 /* DaiMethodInfomation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DaiMethodInfomation.m; sourceTree = ""; }; 41 | 01AD39E41B9C95A2008BADEC /* ILoveDaidouji.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = ILoveDaidouji.a; sourceTree = ""; }; 42 | 1C6ECD1C1B9EB334003EE818 /* NSString+Daidouji1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+Daidouji1.h"; sourceTree = ""; }; 43 | 1C6ECD1D1B9EB334003EE818 /* NSString+Daidouji1.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+Daidouji1.m"; sourceTree = ""; }; 44 | 1C6ECD1F1B9EB39A003EE818 /* NSString+Daidouji2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+Daidouji2.h"; sourceTree = ""; }; 45 | 1C6ECD201B9EB39A003EE818 /* NSString+Daidouji2.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+Daidouji2.m"; sourceTree = ""; }; 46 | 1C6ECD221B9EB454003EE818 /* MainViewController+DaidoujiCategory1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MainViewController+DaidoujiCategory1.h"; sourceTree = ""; }; 47 | 1C6ECD231B9EB454003EE818 /* MainViewController+DaidoujiCategory1.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MainViewController+DaidoujiCategory1.m"; sourceTree = ""; }; 48 | 1C6ECD251B9EB58A003EE818 /* MainViewController+DaidoujiCategory2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MainViewController+DaidoujiCategory2.h"; sourceTree = ""; }; 49 | 1C6ECD261B9EB58A003EE818 /* MainViewController+DaidoujiCategory2.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MainViewController+DaidoujiCategory2.m"; sourceTree = ""; }; 50 | 1C6ECD281B9EB809003EE818 /* UIAlertView+DaiMethodHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIAlertView+DaiMethodHelper.h"; sourceTree = ""; }; 51 | 1C6ECD291B9EB809003EE818 /* UIAlertView+ DaiMethodHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIAlertView+ DaiMethodHelper.m"; sourceTree = ""; }; 52 | /* End PBXFileReference section */ 53 | 54 | /* Begin PBXFrameworksBuildPhase section */ 55 | 019A176A1B9C2BF800BB8986 /* Frameworks */ = { 56 | isa = PBXFrameworksBuildPhase; 57 | buildActionMask = 2147483647; 58 | files = ( 59 | 1C40724F1B9D78A9001F386C /* ILoveDaidouji.a in Frameworks */, 60 | ); 61 | runOnlyForDeploymentPostprocessing = 0; 62 | }; 63 | /* End PBXFrameworksBuildPhase section */ 64 | 65 | /* Begin PBXGroup section */ 66 | 019A17641B9C2BF800BB8986 = { 67 | isa = PBXGroup; 68 | children = ( 69 | 019A176F1B9C2BF800BB8986 /* DaiMethodHelper */, 70 | 019A176E1B9C2BF800BB8986 /* Products */, 71 | ); 72 | sourceTree = ""; 73 | }; 74 | 019A176E1B9C2BF800BB8986 /* Products */ = { 75 | isa = PBXGroup; 76 | children = ( 77 | 019A176D1B9C2BF800BB8986 /* DaiMethodHelper.app */, 78 | ); 79 | name = Products; 80 | sourceTree = ""; 81 | }; 82 | 019A176F1B9C2BF800BB8986 /* DaiMethodHelper */ = { 83 | isa = PBXGroup; 84 | children = ( 85 | 1C6ECD1B1B9EB31A003EE818 /* Category */, 86 | 01AD39E31B9C95A2008BADEC /* ILoveDaidouji */, 87 | 019A17981B9C2C3B00BB8986 /* DaiMethodHelper */, 88 | 019A17741B9C2BF800BB8986 /* AppDelegate.h */, 89 | 019A17751B9C2BF800BB8986 /* AppDelegate.m */, 90 | 019A17991B9C2C4F00BB8986 /* MainViewController.h */, 91 | 019A179A1B9C2C4F00BB8986 /* MainViewController.m */, 92 | 019A179B1B9C2C4F00BB8986 /* MainViewController.xib */, 93 | 019A177D1B9C2BF800BB8986 /* Images.xcassets */, 94 | 019A17701B9C2BF800BB8986 /* Supporting Files */, 95 | ); 96 | path = DaiMethodHelper; 97 | sourceTree = ""; 98 | }; 99 | 019A17701B9C2BF800BB8986 /* Supporting Files */ = { 100 | isa = PBXGroup; 101 | children = ( 102 | 019A17961B9C2C1C00BB8986 /* Default-568h@2x.png */, 103 | 019A17711B9C2BF800BB8986 /* Info.plist */, 104 | 019A17721B9C2BF800BB8986 /* main.m */, 105 | ); 106 | name = "Supporting Files"; 107 | sourceTree = ""; 108 | }; 109 | 019A17981B9C2C3B00BB8986 /* DaiMethodHelper */ = { 110 | isa = PBXGroup; 111 | children = ( 112 | 019A179E1B9C2CF700BB8986 /* DaiMethodHelper.h */, 113 | 019A179F1B9C2CF700BB8986 /* DaiMethodHelper.m */, 114 | 019A17A41B9C86F000BB8986 /* DaiMethodInfomation.h */, 115 | 019A17A51B9C86F000BB8986 /* DaiMethodInfomation.m */, 116 | ); 117 | path = DaiMethodHelper; 118 | sourceTree = ""; 119 | }; 120 | 01AD39E31B9C95A2008BADEC /* ILoveDaidouji */ = { 121 | isa = PBXGroup; 122 | children = ( 123 | 01AD39E41B9C95A2008BADEC /* ILoveDaidouji.a */, 124 | ); 125 | path = ILoveDaidouji; 126 | sourceTree = ""; 127 | }; 128 | 1C6ECD1B1B9EB31A003EE818 /* Category */ = { 129 | isa = PBXGroup; 130 | children = ( 131 | 1C6ECD281B9EB809003EE818 /* UIAlertView+DaiMethodHelper.h */, 132 | 1C6ECD291B9EB809003EE818 /* UIAlertView+ DaiMethodHelper.m */, 133 | 1C6ECD1C1B9EB334003EE818 /* NSString+Daidouji1.h */, 134 | 1C6ECD1D1B9EB334003EE818 /* NSString+Daidouji1.m */, 135 | 1C6ECD1F1B9EB39A003EE818 /* NSString+Daidouji2.h */, 136 | 1C6ECD201B9EB39A003EE818 /* NSString+Daidouji2.m */, 137 | 1C6ECD221B9EB454003EE818 /* MainViewController+DaidoujiCategory1.h */, 138 | 1C6ECD231B9EB454003EE818 /* MainViewController+DaidoujiCategory1.m */, 139 | 1C6ECD251B9EB58A003EE818 /* MainViewController+DaidoujiCategory2.h */, 140 | 1C6ECD261B9EB58A003EE818 /* MainViewController+DaidoujiCategory2.m */, 141 | ); 142 | path = Category; 143 | sourceTree = ""; 144 | }; 145 | /* End PBXGroup section */ 146 | 147 | /* Begin PBXNativeTarget section */ 148 | 019A176C1B9C2BF800BB8986 /* DaiMethodHelper */ = { 149 | isa = PBXNativeTarget; 150 | buildConfigurationList = 019A17901B9C2BF800BB8986 /* Build configuration list for PBXNativeTarget "DaiMethodHelper" */; 151 | buildPhases = ( 152 | 019A17691B9C2BF800BB8986 /* Sources */, 153 | 019A176A1B9C2BF800BB8986 /* Frameworks */, 154 | 019A176B1B9C2BF800BB8986 /* Resources */, 155 | ); 156 | buildRules = ( 157 | ); 158 | dependencies = ( 159 | ); 160 | name = DaiMethodHelper; 161 | productName = DaiMethodHelper; 162 | productReference = 019A176D1B9C2BF800BB8986 /* DaiMethodHelper.app */; 163 | productType = "com.apple.product-type.application"; 164 | }; 165 | /* End PBXNativeTarget section */ 166 | 167 | /* Begin PBXProject section */ 168 | 019A17651B9C2BF800BB8986 /* Project object */ = { 169 | isa = PBXProject; 170 | attributes = { 171 | LastUpgradeCheck = 0620; 172 | ORGANIZATIONNAME = ChilunChen; 173 | TargetAttributes = { 174 | 019A176C1B9C2BF800BB8986 = { 175 | CreatedOnToolsVersion = 6.2; 176 | }; 177 | }; 178 | }; 179 | buildConfigurationList = 019A17681B9C2BF800BB8986 /* Build configuration list for PBXProject "DaiMethodHelper" */; 180 | compatibilityVersion = "Xcode 3.2"; 181 | developmentRegion = English; 182 | hasScannedForEncodings = 0; 183 | knownRegions = ( 184 | en, 185 | Base, 186 | ); 187 | mainGroup = 019A17641B9C2BF800BB8986; 188 | productRefGroup = 019A176E1B9C2BF800BB8986 /* Products */; 189 | projectDirPath = ""; 190 | projectRoot = ""; 191 | targets = ( 192 | 019A176C1B9C2BF800BB8986 /* DaiMethodHelper */, 193 | ); 194 | }; 195 | /* End PBXProject section */ 196 | 197 | /* Begin PBXResourcesBuildPhase section */ 198 | 019A176B1B9C2BF800BB8986 /* Resources */ = { 199 | isa = PBXResourcesBuildPhase; 200 | buildActionMask = 2147483647; 201 | files = ( 202 | 019A177E1B9C2BF800BB8986 /* Images.xcassets in Resources */, 203 | 019A179D1B9C2C4F00BB8986 /* MainViewController.xib in Resources */, 204 | 019A17971B9C2C1C00BB8986 /* Default-568h@2x.png in Resources */, 205 | ); 206 | runOnlyForDeploymentPostprocessing = 0; 207 | }; 208 | /* End PBXResourcesBuildPhase section */ 209 | 210 | /* Begin PBXSourcesBuildPhase section */ 211 | 019A17691B9C2BF800BB8986 /* Sources */ = { 212 | isa = PBXSourcesBuildPhase; 213 | buildActionMask = 2147483647; 214 | files = ( 215 | 1C6ECD241B9EB454003EE818 /* MainViewController+DaidoujiCategory1.m in Sources */, 216 | 019A17761B9C2BF800BB8986 /* AppDelegate.m in Sources */, 217 | 019A179C1B9C2C4F00BB8986 /* MainViewController.m in Sources */, 218 | 1C6ECD271B9EB58A003EE818 /* MainViewController+DaidoujiCategory2.m in Sources */, 219 | 019A17A61B9C86F000BB8986 /* DaiMethodInfomation.m in Sources */, 220 | 019A17A01B9C2CF700BB8986 /* DaiMethodHelper.m in Sources */, 221 | 1C6ECD1E1B9EB334003EE818 /* NSString+Daidouji1.m in Sources */, 222 | 1C6ECD211B9EB39A003EE818 /* NSString+Daidouji2.m in Sources */, 223 | 1C6ECD2A1B9EB809003EE818 /* UIAlertView+ DaiMethodHelper.m in Sources */, 224 | 019A17731B9C2BF800BB8986 /* main.m in Sources */, 225 | ); 226 | runOnlyForDeploymentPostprocessing = 0; 227 | }; 228 | /* End PBXSourcesBuildPhase section */ 229 | 230 | /* Begin XCBuildConfiguration section */ 231 | 019A178E1B9C2BF800BB8986 /* Debug */ = { 232 | isa = XCBuildConfiguration; 233 | buildSettings = { 234 | ALWAYS_SEARCH_USER_PATHS = NO; 235 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 236 | CLANG_CXX_LIBRARY = "libc++"; 237 | CLANG_ENABLE_MODULES = YES; 238 | CLANG_ENABLE_OBJC_ARC = YES; 239 | CLANG_WARN_BOOL_CONVERSION = YES; 240 | CLANG_WARN_CONSTANT_CONVERSION = YES; 241 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 242 | CLANG_WARN_EMPTY_BODY = YES; 243 | CLANG_WARN_ENUM_CONVERSION = YES; 244 | CLANG_WARN_INT_CONVERSION = YES; 245 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 246 | CLANG_WARN_UNREACHABLE_CODE = YES; 247 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 248 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 249 | COPY_PHASE_STRIP = NO; 250 | ENABLE_STRICT_OBJC_MSGSEND = YES; 251 | GCC_C_LANGUAGE_STANDARD = gnu99; 252 | GCC_DYNAMIC_NO_PIC = NO; 253 | GCC_OPTIMIZATION_LEVEL = 0; 254 | GCC_PREPROCESSOR_DEFINITIONS = ( 255 | "DEBUG=1", 256 | "$(inherited)", 257 | ); 258 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 259 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 260 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 261 | GCC_WARN_UNDECLARED_SELECTOR = YES; 262 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 263 | GCC_WARN_UNUSED_FUNCTION = YES; 264 | GCC_WARN_UNUSED_VARIABLE = YES; 265 | IPHONEOS_DEPLOYMENT_TARGET = 8.2; 266 | MTL_ENABLE_DEBUG_INFO = YES; 267 | ONLY_ACTIVE_ARCH = YES; 268 | SDKROOT = iphoneos; 269 | }; 270 | name = Debug; 271 | }; 272 | 019A178F1B9C2BF800BB8986 /* Release */ = { 273 | isa = XCBuildConfiguration; 274 | buildSettings = { 275 | ALWAYS_SEARCH_USER_PATHS = NO; 276 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 277 | CLANG_CXX_LIBRARY = "libc++"; 278 | CLANG_ENABLE_MODULES = YES; 279 | CLANG_ENABLE_OBJC_ARC = YES; 280 | CLANG_WARN_BOOL_CONVERSION = YES; 281 | CLANG_WARN_CONSTANT_CONVERSION = YES; 282 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 283 | CLANG_WARN_EMPTY_BODY = YES; 284 | CLANG_WARN_ENUM_CONVERSION = YES; 285 | CLANG_WARN_INT_CONVERSION = YES; 286 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 287 | CLANG_WARN_UNREACHABLE_CODE = YES; 288 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 289 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 290 | COPY_PHASE_STRIP = NO; 291 | ENABLE_NS_ASSERTIONS = NO; 292 | ENABLE_STRICT_OBJC_MSGSEND = YES; 293 | GCC_C_LANGUAGE_STANDARD = gnu99; 294 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 295 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 296 | GCC_WARN_UNDECLARED_SELECTOR = YES; 297 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 298 | GCC_WARN_UNUSED_FUNCTION = YES; 299 | GCC_WARN_UNUSED_VARIABLE = YES; 300 | IPHONEOS_DEPLOYMENT_TARGET = 8.2; 301 | MTL_ENABLE_DEBUG_INFO = NO; 302 | SDKROOT = iphoneos; 303 | VALIDATE_PRODUCT = YES; 304 | }; 305 | name = Release; 306 | }; 307 | 019A17911B9C2BF800BB8986 /* Debug */ = { 308 | isa = XCBuildConfiguration; 309 | buildSettings = { 310 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 311 | INFOPLIST_FILE = DaiMethodHelper/Info.plist; 312 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 313 | LIBRARY_SEARCH_PATHS = ( 314 | "$(inherited)", 315 | "$(PROJECT_DIR)/DaiMethodHelper/ILoveDaidouji", 316 | ); 317 | OTHER_LDFLAGS = "-ObjC"; 318 | PRODUCT_NAME = DaiMethodHelper; 319 | }; 320 | name = Debug; 321 | }; 322 | 019A17921B9C2BF800BB8986 /* Release */ = { 323 | isa = XCBuildConfiguration; 324 | buildSettings = { 325 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 326 | INFOPLIST_FILE = DaiMethodHelper/Info.plist; 327 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 328 | LIBRARY_SEARCH_PATHS = ( 329 | "$(inherited)", 330 | "$(PROJECT_DIR)/DaiMethodHelper/ILoveDaidouji", 331 | ); 332 | OTHER_LDFLAGS = "-ObjC"; 333 | PRODUCT_NAME = DaiMethodHelper; 334 | }; 335 | name = Release; 336 | }; 337 | /* End XCBuildConfiguration section */ 338 | 339 | /* Begin XCConfigurationList section */ 340 | 019A17681B9C2BF800BB8986 /* Build configuration list for PBXProject "DaiMethodHelper" */ = { 341 | isa = XCConfigurationList; 342 | buildConfigurations = ( 343 | 019A178E1B9C2BF800BB8986 /* Debug */, 344 | 019A178F1B9C2BF800BB8986 /* Release */, 345 | ); 346 | defaultConfigurationIsVisible = 0; 347 | defaultConfigurationName = Release; 348 | }; 349 | 019A17901B9C2BF800BB8986 /* Build configuration list for PBXNativeTarget "DaiMethodHelper" */ = { 350 | isa = XCConfigurationList; 351 | buildConfigurations = ( 352 | 019A17911B9C2BF800BB8986 /* Debug */, 353 | 019A17921B9C2BF800BB8986 /* Release */, 354 | ); 355 | defaultConfigurationIsVisible = 0; 356 | defaultConfigurationName = Release; 357 | }; 358 | /* End XCConfigurationList section */ 359 | }; 360 | rootObject = 019A17651B9C2BF800BB8986 /* Project object */; 361 | } 362 | --------------------------------------------------------------------------------