├── .gitignore ├── README.md ├── Resources └── TTGRemakeMethodSignatureForSelector_0.png ├── TTGRemakeMethodSignatureForSelector.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcuserdata │ └── tutuge.xcuserdatad │ └── xcschemes │ ├── TTGRemakeMethodSignatureForSelector.xcscheme │ └── xcschememanagement.plist └── TTGRemakeMethodSignatureForSelector ├── NSObject+TTGRemakeMethodSignatureForSelector.h ├── NSObject+TTGRemakeMethodSignatureForSelector.m └── main.m /.gitignore: -------------------------------------------------------------------------------- 1 | # Mac OS X 2 | .DS_Store 3 | 4 | # Xcode 5 | 6 | ## Build generated 7 | build/ 8 | DerivedData 9 | 10 | ## Various settings 11 | *.pbxuser 12 | !default.pbxuser 13 | *.mode1v3 14 | !default.mode1v3 15 | *.mode2v3 16 | !default.mode2v3 17 | *.perspectivev3 18 | !default.perspectivev3 19 | xcuserdata 20 | 21 | ## Other 22 | *.xccheckout 23 | *.moved-aside 24 | *.xcuserstate 25 | *.xcscmblueprint 26 | 27 | ## Obj-C/Swift specific 28 | *.hmap 29 | *.ipa 30 | 31 | ## Playgrounds 32 | timeline.xctimeline 33 | playground.xcworkspace 34 | 35 | # Swift Package Manager 36 | .build/ 37 | 38 | # Carthage 39 | Carthage/Build 40 | 41 | # AppCode 42 | .idea/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TTGRemakeMethodSignatureForSelector 2 | 3 | Remake `methodSignatureForSelector:`,just for research. 4 | 5 | 如果你在天朝: 6 | 团队博客:[http://icbu.info/diy_methodsignatureforselector/](http://icbu.info/diy_methodsignatureforselector/) 7 | 土土哥的技术Blog: [http://tutuge.me/2017/04/08/diy-methodSignatureForSelector/](http://tutuge.me/2017/04/08/diy-methodSignatureForSelector/) 8 | 9 | ## Core code 10 | 11 | ttg_MethodDescription 12 | 13 | ``` 14 | struct objc_method_description ttg_MethodDescription(Class class, SEL sel) { 15 | // Result 16 | struct objc_method_description description = (struct objc_method_description){NULL, NULL}; 17 | 18 | // Loop class 19 | Class currentClass = class; 20 | 21 | while (currentClass && description.name == NULL) { 22 | // Get protocol list 23 | unsigned int count = 0; 24 | __unsafe_unretained Protocol **protocols = class_copyProtocolList(currentClass, &count); 25 | 26 | // Check each protocol 27 | for (unsigned int i = 0; i < count; i++) { 28 | // Required method 29 | description = protocol_getMethodDescription(protocols[i], sel, YES, class_isMetaClass(currentClass) ^ 1); 30 | if (description.name != NULL) { 31 | break; 32 | } 33 | 34 | // Optional method 35 | description = protocol_getMethodDescription(protocols[i], sel, NO, class_isMetaClass(currentClass) ^ 1); 36 | if (description.name != NULL) { 37 | break; 38 | } 39 | } 40 | 41 | // release 42 | free(protocols); 43 | 44 | // Found in protocol 45 | if (description.name != NULL) { 46 | return description; 47 | } 48 | 49 | // Get superClass and continue 50 | currentClass = class_getSuperclass(currentClass); 51 | } 52 | 53 | // Get implemented instance method 54 | Method method = class_getInstanceMethod(class, sel); 55 | if (method) { 56 | // Get description 57 | return *method_getDescription(method); 58 | } else { 59 | // Return Null result 60 | return (struct objc_method_description){NULL, NULL}; 61 | } 62 | } 63 | ``` 64 | 65 | NSObject Category 66 | 67 | ``` 68 | @implementation NSObject (TTGRemakeMethodSignatureForSelector) 69 | 70 | - (NSMethodSignature *)ttg_methodSignatureForSelector:(SEL)sel { 71 | struct objc_method_description description = ttg_MethodDescription([self class], sel); // Get from class 72 | if (sel && description.types != NULL) { 73 | return [NSMethodSignature signatureWithObjCTypes:description.types]; 74 | } else { 75 | return nil; 76 | } 77 | } 78 | 79 | + (NSMethodSignature *)ttg_methodSignatureForSelector:(SEL)sel { 80 | struct objc_method_description description = ttg_MethodDescription(object_getClass(self), sel); // Get from metaClass 81 | if (sel && description.types != NULL) { 82 | return [NSMethodSignature signatureWithObjCTypes:description.types]; 83 | } else { 84 | return nil; 85 | } 86 | } 87 | 88 | @end 89 | ``` 90 | 91 | ## CoreFoundation.framework implementation from Hopper Disassemabler 92 | 93 | [NSObject methodSignatureForSelector:] 94 | 95 | ``` 96 | void * +[NSObject methodSignatureForSelector:](void * self, void * _cmd, void * arg2) { 97 | rdi = self; 98 | rbx = arg2; 99 | if ((rbx != 0x0) && (___methodDescriptionForSelector(object_getClass(rdi), rbx) != 0x0)) { 100 | rax = [NSMethodSignature signatureWithObjCTypes:rdx]; 101 | } 102 | else { 103 | rax = 0x0; 104 | } 105 | return rax; 106 | } 107 | ``` 108 | 109 | ___methodDescriptionForSelector: 110 | 111 | ![](https://github.com/zekunyan/TTGRemakeMethodSignatureForSelector/raw/master/Resources/TTGRemakeMethodSignatureForSelector_0.png) 112 | 113 | ``` 114 | int ___methodDescriptionForSelector(int arg0, int arg1) { 115 | var_40 = arg1; 116 | var_38 = arg0; 117 | if (arg0 == 0x0) goto loc_918d6; 118 | 119 | loc_917e2: 120 | r15 = var_38; 121 | goto loc_917f0; 122 | 123 | loc_917f0: 124 | r12 = class_copyProtocolList(r15, 0x0); 125 | var_50 = r15; 126 | if (0x0 == 0x0) goto loc_918a0; 127 | 128 | loc_91814: 129 | r13 = 0x0; 130 | var_48 = r12; 131 | goto loc_91820; 132 | 133 | loc_91820: 134 | rbx = var_40; 135 | rdi = r15; 136 | r15 = protocol_getMethodDescription(*(r12 + r13 * 0x8), rbx, 0x1, (class_isMetaClass(r15) ^ 0x1) & 0xff); 137 | r14 = 0x1; 138 | if (r15 != 0x0) goto loc_918b4; 139 | 140 | loc_91853: 141 | r15 = protocol_getMethodDescription(*(r12 + r13 * 0x8), rbx, 0x0, (class_isMetaClass(rdi) ^ 0x1) & 0xff); 142 | r14 = 0x0; 143 | if (r15 != 0x0) goto loc_918b0; 144 | 145 | loc_91879: 146 | r13 = r13 + 0x1; 147 | r15 = var_50; 148 | r12 = var_48; 149 | if (r13 < 0x0) goto loc_91820; 150 | 151 | loc_9188c: 152 | r15 = 0x0; 153 | goto loc_918b4; 154 | 155 | loc_918b4: 156 | free(r12); 157 | if (r15 != 0x0) goto loc_918ff; 158 | 159 | loc_918c1: 160 | r15 = class_getSuperclass(var_50); 161 | if (r15 != 0x0) goto loc_917f0; 162 | 163 | loc_918d6: 164 | rax = class_getInstanceMethod(var_38, var_40); 165 | if (rax != 0x0) { 166 | rax = method_getDescription(rax); 167 | r15 = *rax; 168 | r14 = *(rax + 0x8); 169 | } 170 | else { 171 | r15 = 0x0; 172 | r14 = 0x0; 173 | } 174 | goto loc_918ff; 175 | 176 | loc_918ff: 177 | rax = r15; 178 | return rax; 179 | 180 | loc_918b0: 181 | r12 = var_48; 182 | goto loc_918b4; 183 | 184 | loc_918a0: 185 | if (r12 == 0x0) goto loc_918c1; 186 | 187 | loc_918a5: 188 | r14 = 0x0; 189 | r15 = 0x0; 190 | goto loc_918b4; 191 | } 192 | ``` 193 | 194 | 195 | 196 | -------------------------------------------------------------------------------- /Resources/TTGRemakeMethodSignatureForSelector_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zekunyan/TTGRemakeMethodSignatureForSelector/6c15a52814beac8c2fd8644197b4e152fc289618/Resources/TTGRemakeMethodSignatureForSelector_0.png -------------------------------------------------------------------------------- /TTGRemakeMethodSignatureForSelector.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | BFEC19A71E9A7A9E001F40F2 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = BFEC19A61E9A7A9E001F40F2 /* main.m */; }; 11 | BFEC19AF1E9A7ADE001F40F2 /* NSObject+TTGRemakeMethodSignatureForSelector.m in Sources */ = {isa = PBXBuildFile; fileRef = BFEC19AE1E9A7ADE001F40F2 /* NSObject+TTGRemakeMethodSignatureForSelector.m */; }; 12 | /* End PBXBuildFile section */ 13 | 14 | /* Begin PBXCopyFilesBuildPhase section */ 15 | BFEC19A11E9A7A9E001F40F2 /* CopyFiles */ = { 16 | isa = PBXCopyFilesBuildPhase; 17 | buildActionMask = 2147483647; 18 | dstPath = /usr/share/man/man1/; 19 | dstSubfolderSpec = 0; 20 | files = ( 21 | ); 22 | runOnlyForDeploymentPostprocessing = 1; 23 | }; 24 | /* End PBXCopyFilesBuildPhase section */ 25 | 26 | /* Begin PBXFileReference section */ 27 | BFEC19A31E9A7A9E001F40F2 /* TTGRemakeMethodSignatureForSelector */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = TTGRemakeMethodSignatureForSelector; sourceTree = BUILT_PRODUCTS_DIR; }; 28 | BFEC19A61E9A7A9E001F40F2 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 29 | BFEC19AD1E9A7ADE001F40F2 /* NSObject+TTGRemakeMethodSignatureForSelector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+TTGRemakeMethodSignatureForSelector.h"; sourceTree = ""; }; 30 | BFEC19AE1E9A7ADE001F40F2 /* NSObject+TTGRemakeMethodSignatureForSelector.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+TTGRemakeMethodSignatureForSelector.m"; sourceTree = ""; }; 31 | /* End PBXFileReference section */ 32 | 33 | /* Begin PBXFrameworksBuildPhase section */ 34 | BFEC19A01E9A7A9E001F40F2 /* Frameworks */ = { 35 | isa = PBXFrameworksBuildPhase; 36 | buildActionMask = 2147483647; 37 | files = ( 38 | ); 39 | runOnlyForDeploymentPostprocessing = 0; 40 | }; 41 | /* End PBXFrameworksBuildPhase section */ 42 | 43 | /* Begin PBXGroup section */ 44 | BFEC199A1E9A7A9E001F40F2 = { 45 | isa = PBXGroup; 46 | children = ( 47 | BFEC19A51E9A7A9E001F40F2 /* TTGRemakeMethodSignatureForSelector */, 48 | BFEC19A41E9A7A9E001F40F2 /* Products */, 49 | ); 50 | sourceTree = ""; 51 | }; 52 | BFEC19A41E9A7A9E001F40F2 /* Products */ = { 53 | isa = PBXGroup; 54 | children = ( 55 | BFEC19A31E9A7A9E001F40F2 /* TTGRemakeMethodSignatureForSelector */, 56 | ); 57 | name = Products; 58 | sourceTree = ""; 59 | }; 60 | BFEC19A51E9A7A9E001F40F2 /* TTGRemakeMethodSignatureForSelector */ = { 61 | isa = PBXGroup; 62 | children = ( 63 | BFEC19A61E9A7A9E001F40F2 /* main.m */, 64 | BFEC19AD1E9A7ADE001F40F2 /* NSObject+TTGRemakeMethodSignatureForSelector.h */, 65 | BFEC19AE1E9A7ADE001F40F2 /* NSObject+TTGRemakeMethodSignatureForSelector.m */, 66 | ); 67 | path = TTGRemakeMethodSignatureForSelector; 68 | sourceTree = ""; 69 | }; 70 | /* End PBXGroup section */ 71 | 72 | /* Begin PBXNativeTarget section */ 73 | BFEC19A21E9A7A9E001F40F2 /* TTGRemakeMethodSignatureForSelector */ = { 74 | isa = PBXNativeTarget; 75 | buildConfigurationList = BFEC19AA1E9A7A9E001F40F2 /* Build configuration list for PBXNativeTarget "TTGRemakeMethodSignatureForSelector" */; 76 | buildPhases = ( 77 | BFEC199F1E9A7A9E001F40F2 /* Sources */, 78 | BFEC19A01E9A7A9E001F40F2 /* Frameworks */, 79 | BFEC19A11E9A7A9E001F40F2 /* CopyFiles */, 80 | ); 81 | buildRules = ( 82 | ); 83 | dependencies = ( 84 | ); 85 | name = TTGRemakeMethodSignatureForSelector; 86 | productName = TTGRemakeMethodSignatureForSelector; 87 | productReference = BFEC19A31E9A7A9E001F40F2 /* TTGRemakeMethodSignatureForSelector */; 88 | productType = "com.apple.product-type.tool"; 89 | }; 90 | /* End PBXNativeTarget section */ 91 | 92 | /* Begin PBXProject section */ 93 | BFEC199B1E9A7A9E001F40F2 /* Project object */ = { 94 | isa = PBXProject; 95 | attributes = { 96 | LastUpgradeCheck = 0830; 97 | ORGANIZATIONNAME = tutuge; 98 | TargetAttributes = { 99 | BFEC19A21E9A7A9E001F40F2 = { 100 | CreatedOnToolsVersion = 8.3; 101 | ProvisioningStyle = Automatic; 102 | }; 103 | }; 104 | }; 105 | buildConfigurationList = BFEC199E1E9A7A9E001F40F2 /* Build configuration list for PBXProject "TTGRemakeMethodSignatureForSelector" */; 106 | compatibilityVersion = "Xcode 3.2"; 107 | developmentRegion = English; 108 | hasScannedForEncodings = 0; 109 | knownRegions = ( 110 | en, 111 | ); 112 | mainGroup = BFEC199A1E9A7A9E001F40F2; 113 | productRefGroup = BFEC19A41E9A7A9E001F40F2 /* Products */; 114 | projectDirPath = ""; 115 | projectRoot = ""; 116 | targets = ( 117 | BFEC19A21E9A7A9E001F40F2 /* TTGRemakeMethodSignatureForSelector */, 118 | ); 119 | }; 120 | /* End PBXProject section */ 121 | 122 | /* Begin PBXSourcesBuildPhase section */ 123 | BFEC199F1E9A7A9E001F40F2 /* Sources */ = { 124 | isa = PBXSourcesBuildPhase; 125 | buildActionMask = 2147483647; 126 | files = ( 127 | BFEC19A71E9A7A9E001F40F2 /* main.m in Sources */, 128 | BFEC19AF1E9A7ADE001F40F2 /* NSObject+TTGRemakeMethodSignatureForSelector.m in Sources */, 129 | ); 130 | runOnlyForDeploymentPostprocessing = 0; 131 | }; 132 | /* End PBXSourcesBuildPhase section */ 133 | 134 | /* Begin XCBuildConfiguration section */ 135 | BFEC19A81E9A7A9E001F40F2 /* Debug */ = { 136 | isa = XCBuildConfiguration; 137 | buildSettings = { 138 | ALWAYS_SEARCH_USER_PATHS = NO; 139 | CLANG_ANALYZER_NONNULL = YES; 140 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 141 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 142 | CLANG_CXX_LIBRARY = "libc++"; 143 | CLANG_ENABLE_MODULES = YES; 144 | CLANG_ENABLE_OBJC_ARC = YES; 145 | CLANG_WARN_BOOL_CONVERSION = YES; 146 | CLANG_WARN_CONSTANT_CONVERSION = YES; 147 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 148 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 149 | CLANG_WARN_EMPTY_BODY = YES; 150 | CLANG_WARN_ENUM_CONVERSION = YES; 151 | CLANG_WARN_INFINITE_RECURSION = YES; 152 | CLANG_WARN_INT_CONVERSION = YES; 153 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 154 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 155 | CLANG_WARN_UNREACHABLE_CODE = YES; 156 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 157 | CODE_SIGN_IDENTITY = "-"; 158 | COPY_PHASE_STRIP = NO; 159 | DEBUG_INFORMATION_FORMAT = dwarf; 160 | ENABLE_STRICT_OBJC_MSGSEND = YES; 161 | ENABLE_TESTABILITY = YES; 162 | GCC_C_LANGUAGE_STANDARD = gnu99; 163 | GCC_DYNAMIC_NO_PIC = NO; 164 | GCC_NO_COMMON_BLOCKS = YES; 165 | GCC_OPTIMIZATION_LEVEL = 0; 166 | GCC_PREPROCESSOR_DEFINITIONS = ( 167 | "DEBUG=1", 168 | "$(inherited)", 169 | ); 170 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 171 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 172 | GCC_WARN_UNDECLARED_SELECTOR = YES; 173 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 174 | GCC_WARN_UNUSED_FUNCTION = YES; 175 | GCC_WARN_UNUSED_VARIABLE = YES; 176 | MACOSX_DEPLOYMENT_TARGET = 10.12; 177 | MTL_ENABLE_DEBUG_INFO = YES; 178 | ONLY_ACTIVE_ARCH = YES; 179 | SDKROOT = macosx; 180 | }; 181 | name = Debug; 182 | }; 183 | BFEC19A91E9A7A9E001F40F2 /* Release */ = { 184 | isa = XCBuildConfiguration; 185 | buildSettings = { 186 | ALWAYS_SEARCH_USER_PATHS = NO; 187 | CLANG_ANALYZER_NONNULL = YES; 188 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 189 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 190 | CLANG_CXX_LIBRARY = "libc++"; 191 | CLANG_ENABLE_MODULES = YES; 192 | CLANG_ENABLE_OBJC_ARC = YES; 193 | CLANG_WARN_BOOL_CONVERSION = YES; 194 | CLANG_WARN_CONSTANT_CONVERSION = YES; 195 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 196 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 197 | CLANG_WARN_EMPTY_BODY = YES; 198 | CLANG_WARN_ENUM_CONVERSION = YES; 199 | CLANG_WARN_INFINITE_RECURSION = YES; 200 | CLANG_WARN_INT_CONVERSION = YES; 201 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 202 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 203 | CLANG_WARN_UNREACHABLE_CODE = YES; 204 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 205 | CODE_SIGN_IDENTITY = "-"; 206 | COPY_PHASE_STRIP = NO; 207 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 208 | ENABLE_NS_ASSERTIONS = NO; 209 | ENABLE_STRICT_OBJC_MSGSEND = YES; 210 | GCC_C_LANGUAGE_STANDARD = gnu99; 211 | GCC_NO_COMMON_BLOCKS = YES; 212 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 213 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 214 | GCC_WARN_UNDECLARED_SELECTOR = YES; 215 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 216 | GCC_WARN_UNUSED_FUNCTION = YES; 217 | GCC_WARN_UNUSED_VARIABLE = YES; 218 | MACOSX_DEPLOYMENT_TARGET = 10.12; 219 | MTL_ENABLE_DEBUG_INFO = NO; 220 | SDKROOT = macosx; 221 | }; 222 | name = Release; 223 | }; 224 | BFEC19AB1E9A7A9E001F40F2 /* Debug */ = { 225 | isa = XCBuildConfiguration; 226 | buildSettings = { 227 | PRODUCT_NAME = "$(TARGET_NAME)"; 228 | }; 229 | name = Debug; 230 | }; 231 | BFEC19AC1E9A7A9E001F40F2 /* Release */ = { 232 | isa = XCBuildConfiguration; 233 | buildSettings = { 234 | PRODUCT_NAME = "$(TARGET_NAME)"; 235 | }; 236 | name = Release; 237 | }; 238 | /* End XCBuildConfiguration section */ 239 | 240 | /* Begin XCConfigurationList section */ 241 | BFEC199E1E9A7A9E001F40F2 /* Build configuration list for PBXProject "TTGRemakeMethodSignatureForSelector" */ = { 242 | isa = XCConfigurationList; 243 | buildConfigurations = ( 244 | BFEC19A81E9A7A9E001F40F2 /* Debug */, 245 | BFEC19A91E9A7A9E001F40F2 /* Release */, 246 | ); 247 | defaultConfigurationIsVisible = 0; 248 | defaultConfigurationName = Release; 249 | }; 250 | BFEC19AA1E9A7A9E001F40F2 /* Build configuration list for PBXNativeTarget "TTGRemakeMethodSignatureForSelector" */ = { 251 | isa = XCConfigurationList; 252 | buildConfigurations = ( 253 | BFEC19AB1E9A7A9E001F40F2 /* Debug */, 254 | BFEC19AC1E9A7A9E001F40F2 /* Release */, 255 | ); 256 | defaultConfigurationIsVisible = 0; 257 | defaultConfigurationName = Release; 258 | }; 259 | /* End XCConfigurationList section */ 260 | }; 261 | rootObject = BFEC199B1E9A7A9E001F40F2 /* Project object */; 262 | } 263 | -------------------------------------------------------------------------------- /TTGRemakeMethodSignatureForSelector.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /TTGRemakeMethodSignatureForSelector.xcodeproj/xcuserdata/tutuge.xcuserdatad/xcschemes/TTGRemakeMethodSignatureForSelector.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /TTGRemakeMethodSignatureForSelector.xcodeproj/xcuserdata/tutuge.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | TTGRemakeMethodSignatureForSelector.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | BF2912631E9A7E330029ED46 16 | 17 | primary 18 | 19 | 20 | BF29126F1E9A7E490029ED46 21 | 22 | primary 23 | 24 | 25 | BFEC19A21E9A7A9E001F40F2 26 | 27 | primary 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /TTGRemakeMethodSignatureForSelector/NSObject+TTGRemakeMethodSignatureForSelector.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+TTGRemakeMethodSignatureForSelector.h 3 | // TTGRemakeMethodSignatureForSelector 4 | // 5 | // Created by tutuge on 2017/4/9. 6 | // Copyright © 2017年 tutuge. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | /** 12 | * Remake [NSObject methodSignatureForSelector:] 13 | * Just for research 14 | */ 15 | @interface NSObject (TTGRemakeMethodSignatureForSelector) 16 | 17 | /** 18 | * Get instance method signature 19 | * 20 | * @param sel selector 21 | * 22 | * @return signature 23 | */ 24 | - (NSMethodSignature *)ttg_methodSignatureForSelector:(SEL)sel; 25 | 26 | /** 27 | * Get class method signature 28 | * 29 | * @param sel selector 30 | * 31 | * @return signature 32 | */ 33 | + (NSMethodSignature *)ttg_methodSignatureForSelector:(SEL)sel; 34 | 35 | @end 36 | -------------------------------------------------------------------------------- /TTGRemakeMethodSignatureForSelector/NSObject+TTGRemakeMethodSignatureForSelector.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+TTGRemakeMethodSignatureForSelector.m 3 | // TTGRemakeMethodSignatureForSelector 4 | // 5 | // Created by tutuge on 2017/4/9. 6 | // Copyright © 2017年 tutuge. All rights reserved. 7 | // 8 | 9 | #import "NSObject+TTGRemakeMethodSignatureForSelector.h" 10 | #import 11 | 12 | struct objc_method_description ttg_MethodDescription(Class class, SEL sel) { 13 | // Result 14 | struct objc_method_description description = (struct objc_method_description){NULL, NULL}; 15 | 16 | // Loop class 17 | Class currentClass = class; 18 | 19 | while (currentClass && description.name == NULL) { 20 | // Get protocol list 21 | unsigned int count = 0; 22 | __unsafe_unretained Protocol **protocols = class_copyProtocolList(currentClass, &count); 23 | 24 | // Check each protocol 25 | for (unsigned int i = 0; i < count; i++) { 26 | // Required method 27 | description = protocol_getMethodDescription(protocols[i], sel, YES, class_isMetaClass(currentClass) ^ 1); 28 | if (description.name != NULL) { 29 | break; 30 | } 31 | 32 | // Optional method 33 | description = protocol_getMethodDescription(protocols[i], sel, NO, class_isMetaClass(currentClass) ^ 1); 34 | if (description.name != NULL) { 35 | break; 36 | } 37 | } 38 | 39 | // release 40 | free(protocols); 41 | 42 | // Found in protocol 43 | if (description.name != NULL) { 44 | return description; 45 | } 46 | 47 | // Get superClass and continue 48 | currentClass = class_getSuperclass(currentClass); 49 | } 50 | 51 | // Get implemented instance method 52 | Method method = class_getInstanceMethod(class, sel); 53 | if (method) { 54 | // Get description 55 | return *method_getDescription(method); 56 | } else { 57 | // Return Null result 58 | return (struct objc_method_description){NULL, NULL}; 59 | } 60 | } 61 | 62 | @implementation NSObject (TTGRemakeMethodSignatureForSelector) 63 | 64 | - (NSMethodSignature *)ttg_methodSignatureForSelector:(SEL)sel { 65 | struct objc_method_description description = ttg_MethodDescription([self class], sel); // Get from class 66 | if (sel && description.types != NULL) { 67 | return [NSMethodSignature signatureWithObjCTypes:description.types]; 68 | } else { 69 | return nil; 70 | } 71 | } 72 | 73 | + (NSMethodSignature *)ttg_methodSignatureForSelector:(SEL)sel { 74 | struct objc_method_description description = ttg_MethodDescription(object_getClass(self), sel); // Get from metaClass 75 | if (sel && description.types != NULL) { 76 | return [NSMethodSignature signatureWithObjCTypes:description.types]; 77 | } else { 78 | return nil; 79 | } 80 | } 81 | 82 | @end 83 | -------------------------------------------------------------------------------- /TTGRemakeMethodSignatureForSelector/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // TTGRemakeMethodSignatureForSelector 4 | // 5 | // Created by tutuge on 2017/4/9. 6 | // Copyright © 2017年 tutuge. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "NSObject+TTGRemakeMethodSignatureForSelector.h" 11 | 12 | // Test protocol 13 | @protocol TestProtocol 14 | 15 | @required 16 | - (void)protocolTestFunc1; 17 | @optional 18 | - (void)protocolTestFunc2; 19 | 20 | @required 21 | + (void)protocolStaticTestFunc1; 22 | @optional 23 | + (void)protocolStaticTestFunc2; 24 | 25 | @end 26 | 27 | @interface TestClass : NSObject 28 | 29 | - (void)testFunc1; 30 | - (void)testFunc3; // Without implementation 31 | 32 | + (void)staticTestFunc1; 33 | + (void)staticTestFunc3; // Without implementation 34 | 35 | @end 36 | 37 | @implementation TestClass 38 | 39 | - (void)testFunc1 { 40 | NSLog(@"test func 1"); 41 | } 42 | - (void)testFunc2 {} // Without declaration 43 | 44 | + (void)staticTestFunc1 { 45 | NSLog(@"static test func 1"); 46 | } 47 | 48 | + (void)staticTestFunc2 {} // Without declaration 49 | 50 | - (void)protocolTestFunc1 {}; 51 | + (void)protocolStaticTestFunc1 {}; 52 | 53 | @end 54 | 55 | int main(int argc, const char * argv[]) { 56 | @autoreleasepool { 57 | TestClass *test = [TestClass new]; 58 | NSLog(@"*** Test NSObject methodSignatureForSelector *** "); 59 | NSLog(@"*** TestClass ***"); 60 | NSLog(@"removeObject: %@", [test methodSignatureForSelector:@selector(removeObject:)]); 61 | NSLog(@"testFunc1: %@", [test methodSignatureForSelector:@selector(testFunc1)]); 62 | NSLog(@"testFunc2: %@", [test methodSignatureForSelector:@selector(testFunc2)]); 63 | NSLog(@"testFunc3: %@", [test methodSignatureForSelector:@selector(testFunc3)]); 64 | NSLog(@"staticTestFunc1: %@", [TestClass methodSignatureForSelector:@selector(staticTestFunc1)]); 65 | NSLog(@"staticTestFunc2: %@", [TestClass methodSignatureForSelector:@selector(staticTestFunc2)]); 66 | NSLog(@"staticTestFunc3: %@", [TestClass methodSignatureForSelector:@selector(staticTestFunc3)]); 67 | 68 | NSLog(@"\n"); 69 | NSLog(@"*** Protocol ***"); 70 | NSLog(@"@required protocolTestFunc1: %@", [test methodSignatureForSelector:@selector(protocolTestFunc1)]); 71 | NSLog(@"@optional protocolTestFunc2: %@", [test methodSignatureForSelector:@selector(protocolTestFunc2)]); 72 | NSLog(@"@required protocolStaticTestFunc1: %@", [TestClass methodSignatureForSelector:@selector(protocolStaticTestFunc1)]); 73 | NSLog(@"@optional protocolStaticTestFunc2: %@", [TestClass methodSignatureForSelector:@selector(protocolStaticTestFunc2)]); 74 | 75 | NSLog(@"\n\n"); 76 | NSLog(@"*** Test ttg_methodSignatureForSelector *** "); 77 | NSLog(@"*** TestClass ***"); 78 | NSLog(@"removeObject: %@", [test ttg_methodSignatureForSelector:@selector(removeObject:)]); 79 | NSLog(@"testFunc1: %@", [test ttg_methodSignatureForSelector:@selector(testFunc1)]); 80 | NSLog(@"testFunc2: %@", [test ttg_methodSignatureForSelector:@selector(testFunc2)]); 81 | NSLog(@"testFunc3: %@", [test ttg_methodSignatureForSelector:@selector(testFunc3)]); 82 | NSLog(@"staticTestFunc1: %@", [TestClass ttg_methodSignatureForSelector:@selector(staticTestFunc1)]); 83 | NSLog(@"staticTestFunc2: %@", [TestClass ttg_methodSignatureForSelector:@selector(staticTestFunc2)]); 84 | NSLog(@"staticTestFunc3: %@", [TestClass ttg_methodSignatureForSelector:@selector(staticTestFunc3)]); 85 | 86 | NSLog(@"\n"); 87 | NSLog(@"*** Protocol ***"); 88 | NSLog(@"@required protocolTestFunc1: %@", [test ttg_methodSignatureForSelector:@selector(protocolTestFunc1)]); 89 | NSLog(@"@optional protocolTestFunc2: %@", [test ttg_methodSignatureForSelector:@selector(protocolTestFunc2)]); 90 | NSLog(@"@required protocolStaticTestFunc1: %@", [TestClass ttg_methodSignatureForSelector:@selector(protocolStaticTestFunc1)]); 91 | NSLog(@"@optional protocolStaticTestFunc2: %@", [TestClass ttg_methodSignatureForSelector:@selector(protocolStaticTestFunc2)]); 92 | 93 | NSLog(@"\n\n"); 94 | 95 | // Test signature equal 96 | NSMethodSignature *signature1 = [test methodSignatureForSelector:@selector(testFunc1)]; 97 | NSMethodSignature *signature2 = [test ttg_methodSignatureForSelector:@selector(testFunc1)]; 98 | NSLog(@"signature1 == signature2: %d", [signature1 isEqual:signature2]); 99 | 100 | // Invoke instance method 101 | NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[test ttg_methodSignatureForSelector:@selector(testFunc1)]]; 102 | invocation.target = test; 103 | invocation.selector = @selector(testFunc1); 104 | [invocation invoke]; 105 | 106 | // Invoke class method 107 | invocation = [NSInvocation invocationWithMethodSignature:[TestClass ttg_methodSignatureForSelector:@selector(staticTestFunc1)]]; 108 | invocation.target = [TestClass class]; 109 | invocation.selector = @selector(staticTestFunc1); 110 | [invocation invoke]; 111 | 112 | } 113 | return 0; 114 | } 115 | --------------------------------------------------------------------------------