├── 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 |
--------------------------------------------------------------------------------