├── README.md └── Swizzling-Demo ├── Swizzling-Demo.xcodeproj ├── project.pbxproj └── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ └── Swizzling-Demo.xcscmblueprint └── Swizzling-Demo ├── AppDelegate ├── AppDelegate.h └── AppDelegate.m ├── Classes ├── NSArray+LXZArray.h ├── NSArray+LXZArray.m ├── ViewController.h └── ViewController.m └── Project File ├── Assets.xcassets └── AppIcon.appiconset │ └── Contents.json ├── Base.lproj ├── LaunchScreen.storyboard └── Main.storyboard ├── Info.plist └── main.m /README.md: -------------------------------------------------------------------------------- 1 | *** 2 | 3 | > 公司年底要在新年前发一个版本,最近一直很忙,好久没有更新博客了。正好现在新版本开发的差不多了,抽空总结一下。 4 | > 5 | > 由于最近开发新版本,就避免不了在开发和调试过程中引起崩溃,以及诱发一些之前的__bug__导致的崩溃。而且项目比较大也很不好排查,正好想起之前研究过的`Method Swizzling`,考虑是否能用这个苹果的“黑魔法”解决问题,当然用好这个黑魔法并不局限于解决这些问题.... 6 | 7 | --- 8 | 9 | 10 | 11 | 在简书的文章中详细的讲解了Method Swizzling,为了方便大家学习和理解,所以在Github上写了这个小Demo,可以帮助大家更好的理解Method Swizzling。 12 | 13 | 在Demo中简单实现了一个崩溃拦截的代码,等以后有时间的话,我计划写一个崩溃拦截系统,并且会发到博客和Github上。 14 | 15 | #### 原文地址 16 | 17 | * [iOS黑魔法-Method Swizzling](http://www.jianshu.com/p/ff19c04b34d0) 18 | 19 | -------------------------------------------------------------------------------- /Swizzling-Demo/Swizzling-Demo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 79EF6C861D757DE200F3B3C7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 79EF6C7A1D757DE200F3B3C7 /* AppDelegate.m */; }; 11 | 79EF6C871D757DE200F3B3C7 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 79EF6C7D1D757DE200F3B3C7 /* ViewController.m */; }; 12 | 79EF6C881D757DE200F3B3C7 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 79EF6C7F1D757DE200F3B3C7 /* Assets.xcassets */; }; 13 | 79EF6C891D757DE200F3B3C7 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 79EF6C801D757DE200F3B3C7 /* LaunchScreen.storyboard */; }; 14 | 79EF6C8A1D757DE200F3B3C7 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 79EF6C821D757DE200F3B3C7 /* Main.storyboard */; }; 15 | 79EF6C8B1D757DE200F3B3C7 /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 79EF6C841D757DE200F3B3C7 /* Info.plist */; }; 16 | 79EF6C8C1D757DE200F3B3C7 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 79EF6C851D757DE200F3B3C7 /* main.m */; }; 17 | 79EF6C901D75816A00F3B3C7 /* NSArray+LXZArray.m in Sources */ = {isa = PBXBuildFile; fileRef = 79EF6C8F1D75816A00F3B3C7 /* NSArray+LXZArray.m */; }; 18 | /* End PBXBuildFile section */ 19 | 20 | /* Begin PBXFileReference section */ 21 | 79EF6C5E1D757D7800F3B3C7 /* Swizzling-Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Swizzling-Demo.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 22 | 79EF6C791D757DE200F3B3C7 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 23 | 79EF6C7A1D757DE200F3B3C7 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 24 | 79EF6C7C1D757DE200F3B3C7 /* ViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 25 | 79EF6C7D1D757DE200F3B3C7 /* ViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 26 | 79EF6C7F1D757DE200F3B3C7 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 27 | 79EF6C811D757DE200F3B3C7 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 28 | 79EF6C831D757DE200F3B3C7 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 29 | 79EF6C841D757DE200F3B3C7 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 30 | 79EF6C851D757DE200F3B3C7 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 31 | 79EF6C8E1D75816A00F3B3C7 /* NSArray+LXZArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+LXZArray.h"; sourceTree = ""; }; 32 | 79EF6C8F1D75816A00F3B3C7 /* NSArray+LXZArray.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSArray+LXZArray.m"; sourceTree = ""; }; 33 | /* End PBXFileReference section */ 34 | 35 | /* Begin PBXFrameworksBuildPhase section */ 36 | 79EF6C5B1D757D7800F3B3C7 /* Frameworks */ = { 37 | isa = PBXFrameworksBuildPhase; 38 | buildActionMask = 2147483647; 39 | files = ( 40 | ); 41 | runOnlyForDeploymentPostprocessing = 0; 42 | }; 43 | /* End PBXFrameworksBuildPhase section */ 44 | 45 | /* Begin PBXGroup section */ 46 | 79EF6C551D757D7800F3B3C7 = { 47 | isa = PBXGroup; 48 | children = ( 49 | 79EF6C601D757D7800F3B3C7 /* Swizzling-Demo */, 50 | 79EF6C5F1D757D7800F3B3C7 /* Products */, 51 | ); 52 | sourceTree = ""; 53 | }; 54 | 79EF6C5F1D757D7800F3B3C7 /* Products */ = { 55 | isa = PBXGroup; 56 | children = ( 57 | 79EF6C5E1D757D7800F3B3C7 /* Swizzling-Demo.app */, 58 | ); 59 | name = Products; 60 | sourceTree = ""; 61 | }; 62 | 79EF6C601D757D7800F3B3C7 /* Swizzling-Demo */ = { 63 | isa = PBXGroup; 64 | children = ( 65 | 79EF6C781D757DE200F3B3C7 /* AppDelegate */, 66 | 79EF6C7B1D757DE200F3B3C7 /* Classes */, 67 | 79EF6C7E1D757DE200F3B3C7 /* Project File */, 68 | ); 69 | path = "Swizzling-Demo"; 70 | sourceTree = ""; 71 | }; 72 | 79EF6C781D757DE200F3B3C7 /* AppDelegate */ = { 73 | isa = PBXGroup; 74 | children = ( 75 | 79EF6C791D757DE200F3B3C7 /* AppDelegate.h */, 76 | 79EF6C7A1D757DE200F3B3C7 /* AppDelegate.m */, 77 | ); 78 | path = AppDelegate; 79 | sourceTree = ""; 80 | }; 81 | 79EF6C7B1D757DE200F3B3C7 /* Classes */ = { 82 | isa = PBXGroup; 83 | children = ( 84 | 79EF6C7C1D757DE200F3B3C7 /* ViewController.h */, 85 | 79EF6C7D1D757DE200F3B3C7 /* ViewController.m */, 86 | 79EF6C8D1D757E1900F3B3C7 /* Swizzling Class */, 87 | ); 88 | path = Classes; 89 | sourceTree = ""; 90 | }; 91 | 79EF6C7E1D757DE200F3B3C7 /* Project File */ = { 92 | isa = PBXGroup; 93 | children = ( 94 | 79EF6C7F1D757DE200F3B3C7 /* Assets.xcassets */, 95 | 79EF6C801D757DE200F3B3C7 /* LaunchScreen.storyboard */, 96 | 79EF6C821D757DE200F3B3C7 /* Main.storyboard */, 97 | 79EF6C841D757DE200F3B3C7 /* Info.plist */, 98 | 79EF6C851D757DE200F3B3C7 /* main.m */, 99 | ); 100 | path = "Project File"; 101 | sourceTree = ""; 102 | }; 103 | 79EF6C8D1D757E1900F3B3C7 /* Swizzling Class */ = { 104 | isa = PBXGroup; 105 | children = ( 106 | 79EF6C8E1D75816A00F3B3C7 /* NSArray+LXZArray.h */, 107 | 79EF6C8F1D75816A00F3B3C7 /* NSArray+LXZArray.m */, 108 | ); 109 | name = "Swizzling Class"; 110 | sourceTree = ""; 111 | }; 112 | /* End PBXGroup section */ 113 | 114 | /* Begin PBXNativeTarget section */ 115 | 79EF6C5D1D757D7800F3B3C7 /* Swizzling-Demo */ = { 116 | isa = PBXNativeTarget; 117 | buildConfigurationList = 79EF6C751D757D7800F3B3C7 /* Build configuration list for PBXNativeTarget "Swizzling-Demo" */; 118 | buildPhases = ( 119 | 79EF6C5A1D757D7800F3B3C7 /* Sources */, 120 | 79EF6C5B1D757D7800F3B3C7 /* Frameworks */, 121 | 79EF6C5C1D757D7800F3B3C7 /* Resources */, 122 | ); 123 | buildRules = ( 124 | ); 125 | dependencies = ( 126 | ); 127 | name = "Swizzling-Demo"; 128 | productName = "Swizzling-Demo"; 129 | productReference = 79EF6C5E1D757D7800F3B3C7 /* Swizzling-Demo.app */; 130 | productType = "com.apple.product-type.application"; 131 | }; 132 | /* End PBXNativeTarget section */ 133 | 134 | /* Begin PBXProject section */ 135 | 79EF6C561D757D7800F3B3C7 /* Project object */ = { 136 | isa = PBXProject; 137 | attributes = { 138 | LastUpgradeCheck = 0710; 139 | ORGANIZATIONNAME = "刘小壮"; 140 | TargetAttributes = { 141 | 79EF6C5D1D757D7800F3B3C7 = { 142 | CreatedOnToolsVersion = 7.1; 143 | }; 144 | }; 145 | }; 146 | buildConfigurationList = 79EF6C591D757D7800F3B3C7 /* Build configuration list for PBXProject "Swizzling-Demo" */; 147 | compatibilityVersion = "Xcode 3.2"; 148 | developmentRegion = English; 149 | hasScannedForEncodings = 0; 150 | knownRegions = ( 151 | en, 152 | Base, 153 | ); 154 | mainGroup = 79EF6C551D757D7800F3B3C7; 155 | productRefGroup = 79EF6C5F1D757D7800F3B3C7 /* Products */; 156 | projectDirPath = ""; 157 | projectRoot = ""; 158 | targets = ( 159 | 79EF6C5D1D757D7800F3B3C7 /* Swizzling-Demo */, 160 | ); 161 | }; 162 | /* End PBXProject section */ 163 | 164 | /* Begin PBXResourcesBuildPhase section */ 165 | 79EF6C5C1D757D7800F3B3C7 /* Resources */ = { 166 | isa = PBXResourcesBuildPhase; 167 | buildActionMask = 2147483647; 168 | files = ( 169 | 79EF6C8B1D757DE200F3B3C7 /* Info.plist in Resources */, 170 | 79EF6C8A1D757DE200F3B3C7 /* Main.storyboard in Resources */, 171 | 79EF6C881D757DE200F3B3C7 /* Assets.xcassets in Resources */, 172 | 79EF6C891D757DE200F3B3C7 /* LaunchScreen.storyboard in Resources */, 173 | ); 174 | runOnlyForDeploymentPostprocessing = 0; 175 | }; 176 | /* End PBXResourcesBuildPhase section */ 177 | 178 | /* Begin PBXSourcesBuildPhase section */ 179 | 79EF6C5A1D757D7800F3B3C7 /* Sources */ = { 180 | isa = PBXSourcesBuildPhase; 181 | buildActionMask = 2147483647; 182 | files = ( 183 | 79EF6C871D757DE200F3B3C7 /* ViewController.m in Sources */, 184 | 79EF6C901D75816A00F3B3C7 /* NSArray+LXZArray.m in Sources */, 185 | 79EF6C8C1D757DE200F3B3C7 /* main.m in Sources */, 186 | 79EF6C861D757DE200F3B3C7 /* AppDelegate.m in Sources */, 187 | ); 188 | runOnlyForDeploymentPostprocessing = 0; 189 | }; 190 | /* End PBXSourcesBuildPhase section */ 191 | 192 | /* Begin PBXVariantGroup section */ 193 | 79EF6C801D757DE200F3B3C7 /* LaunchScreen.storyboard */ = { 194 | isa = PBXVariantGroup; 195 | children = ( 196 | 79EF6C811D757DE200F3B3C7 /* Base */, 197 | ); 198 | name = LaunchScreen.storyboard; 199 | sourceTree = ""; 200 | }; 201 | 79EF6C821D757DE200F3B3C7 /* Main.storyboard */ = { 202 | isa = PBXVariantGroup; 203 | children = ( 204 | 79EF6C831D757DE200F3B3C7 /* Base */, 205 | ); 206 | name = Main.storyboard; 207 | sourceTree = ""; 208 | }; 209 | /* End PBXVariantGroup section */ 210 | 211 | /* Begin XCBuildConfiguration section */ 212 | 79EF6C731D757D7800F3B3C7 /* Debug */ = { 213 | isa = XCBuildConfiguration; 214 | buildSettings = { 215 | ALWAYS_SEARCH_USER_PATHS = NO; 216 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 217 | CLANG_CXX_LIBRARY = "libc++"; 218 | CLANG_ENABLE_MODULES = YES; 219 | CLANG_ENABLE_OBJC_ARC = YES; 220 | CLANG_WARN_BOOL_CONVERSION = YES; 221 | CLANG_WARN_CONSTANT_CONVERSION = YES; 222 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 223 | CLANG_WARN_EMPTY_BODY = YES; 224 | CLANG_WARN_ENUM_CONVERSION = YES; 225 | CLANG_WARN_INT_CONVERSION = YES; 226 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 227 | CLANG_WARN_UNREACHABLE_CODE = YES; 228 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 229 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 230 | COPY_PHASE_STRIP = NO; 231 | DEBUG_INFORMATION_FORMAT = dwarf; 232 | ENABLE_STRICT_OBJC_MSGSEND = YES; 233 | ENABLE_TESTABILITY = YES; 234 | GCC_C_LANGUAGE_STANDARD = gnu99; 235 | GCC_DYNAMIC_NO_PIC = NO; 236 | GCC_NO_COMMON_BLOCKS = YES; 237 | GCC_OPTIMIZATION_LEVEL = 0; 238 | GCC_PREPROCESSOR_DEFINITIONS = ( 239 | "DEBUG=1", 240 | "$(inherited)", 241 | ); 242 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 243 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 244 | GCC_WARN_UNDECLARED_SELECTOR = YES; 245 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 246 | GCC_WARN_UNUSED_FUNCTION = YES; 247 | GCC_WARN_UNUSED_VARIABLE = YES; 248 | IPHONEOS_DEPLOYMENT_TARGET = 9.1; 249 | MTL_ENABLE_DEBUG_INFO = YES; 250 | ONLY_ACTIVE_ARCH = YES; 251 | SDKROOT = iphoneos; 252 | }; 253 | name = Debug; 254 | }; 255 | 79EF6C741D757D7800F3B3C7 /* Release */ = { 256 | isa = XCBuildConfiguration; 257 | buildSettings = { 258 | ALWAYS_SEARCH_USER_PATHS = NO; 259 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 260 | CLANG_CXX_LIBRARY = "libc++"; 261 | CLANG_ENABLE_MODULES = YES; 262 | CLANG_ENABLE_OBJC_ARC = YES; 263 | CLANG_WARN_BOOL_CONVERSION = YES; 264 | CLANG_WARN_CONSTANT_CONVERSION = YES; 265 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 266 | CLANG_WARN_EMPTY_BODY = YES; 267 | CLANG_WARN_ENUM_CONVERSION = YES; 268 | CLANG_WARN_INT_CONVERSION = YES; 269 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 270 | CLANG_WARN_UNREACHABLE_CODE = YES; 271 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 272 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 273 | COPY_PHASE_STRIP = NO; 274 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 275 | ENABLE_NS_ASSERTIONS = NO; 276 | ENABLE_STRICT_OBJC_MSGSEND = YES; 277 | GCC_C_LANGUAGE_STANDARD = gnu99; 278 | GCC_NO_COMMON_BLOCKS = YES; 279 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 280 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 281 | GCC_WARN_UNDECLARED_SELECTOR = YES; 282 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 283 | GCC_WARN_UNUSED_FUNCTION = YES; 284 | GCC_WARN_UNUSED_VARIABLE = YES; 285 | IPHONEOS_DEPLOYMENT_TARGET = 9.1; 286 | MTL_ENABLE_DEBUG_INFO = NO; 287 | SDKROOT = iphoneos; 288 | VALIDATE_PRODUCT = YES; 289 | }; 290 | name = Release; 291 | }; 292 | 79EF6C761D757D7800F3B3C7 /* Debug */ = { 293 | isa = XCBuildConfiguration; 294 | buildSettings = { 295 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 296 | INFOPLIST_FILE = "$(SRCROOT)/Swizzling-Demo/Project File/Info.plist"; 297 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 298 | PRODUCT_BUNDLE_IDENTIFIER = "com.liuxiaozhuang.Swizzling-Demo"; 299 | PRODUCT_NAME = "$(TARGET_NAME)"; 300 | }; 301 | name = Debug; 302 | }; 303 | 79EF6C771D757D7800F3B3C7 /* Release */ = { 304 | isa = XCBuildConfiguration; 305 | buildSettings = { 306 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 307 | INFOPLIST_FILE = "$(SRCROOT)/Swizzling-Demo/Project File/Info.plist"; 308 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 309 | PRODUCT_BUNDLE_IDENTIFIER = "com.liuxiaozhuang.Swizzling-Demo"; 310 | PRODUCT_NAME = "$(TARGET_NAME)"; 311 | }; 312 | name = Release; 313 | }; 314 | /* End XCBuildConfiguration section */ 315 | 316 | /* Begin XCConfigurationList section */ 317 | 79EF6C591D757D7800F3B3C7 /* Build configuration list for PBXProject "Swizzling-Demo" */ = { 318 | isa = XCConfigurationList; 319 | buildConfigurations = ( 320 | 79EF6C731D757D7800F3B3C7 /* Debug */, 321 | 79EF6C741D757D7800F3B3C7 /* Release */, 322 | ); 323 | defaultConfigurationIsVisible = 0; 324 | defaultConfigurationName = Release; 325 | }; 326 | 79EF6C751D757D7800F3B3C7 /* Build configuration list for PBXNativeTarget "Swizzling-Demo" */ = { 327 | isa = XCConfigurationList; 328 | buildConfigurations = ( 329 | 79EF6C761D757D7800F3B3C7 /* Debug */, 330 | 79EF6C771D757D7800F3B3C7 /* Release */, 331 | ); 332 | defaultConfigurationIsVisible = 0; 333 | }; 334 | /* End XCConfigurationList section */ 335 | }; 336 | rootObject = 79EF6C561D757D7800F3B3C7 /* Project object */; 337 | } 338 | -------------------------------------------------------------------------------- /Swizzling-Demo/Swizzling-Demo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Swizzling-Demo/Swizzling-Demo.xcodeproj/project.xcworkspace/xcshareddata/Swizzling-Demo.xcscmblueprint: -------------------------------------------------------------------------------- 1 | { 2 | "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "631A2EB88517E73A0A233EAE21F3667A2276696E", 3 | "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : { 4 | 5 | }, 6 | "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : { 7 | "631A2EB88517E73A0A233EAE21F3667A2276696E" : 0, 8 | "88EFCEAC42A9049BBFE200767CC7F994AC461D4A" : 0 9 | }, 10 | "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "DDD990DF-B8F1-4500-91E3-93BD35C2FA07", 11 | "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : { 12 | "631A2EB88517E73A0A233EAE21F3667A2276696E" : "%E7%AE%80%E4%B9%A6%E5%8D%9A%E5%AE%A2Demo-Method%20Swizzling\/", 13 | "88EFCEAC42A9049BBFE200767CC7F994AC461D4A" : "" 14 | }, 15 | "DVTSourceControlWorkspaceBlueprintNameKey" : "Swizzling-Demo", 16 | "DVTSourceControlWorkspaceBlueprintVersion" : 204, 17 | "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "Swizzling-Demo\/Swizzling-Demo.xcodeproj", 18 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [ 19 | { 20 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/DeveloperErenLiu\/BlogDemo-Swizzling.git", 21 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", 22 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "631A2EB88517E73A0A233EAE21F3667A2276696E" 23 | }, 24 | { 25 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/git.coding.net\/NewDream\/fengdu.git", 26 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", 27 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "88EFCEAC42A9049BBFE200767CC7F994AC461D4A" 28 | } 29 | ] 30 | } -------------------------------------------------------------------------------- /Swizzling-Demo/Swizzling-Demo/AppDelegate/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // Swizzling-Demo 4 | // 5 | // Created by 刘小壮 on 16/8/30. 6 | // Copyright © 2016年 刘小壮. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /Swizzling-Demo/Swizzling-Demo/AppDelegate/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // Swizzling-Demo 4 | // 5 | // Created by 刘小壮 on 16/8/30. 6 | // Copyright © 2016年 刘小壮. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | - (void)applicationWillResignActive:(UIApplication *)application { 24 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 25 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 26 | } 27 | 28 | - (void)applicationDidEnterBackground:(UIApplication *)application { 29 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 31 | } 32 | 33 | - (void)applicationWillEnterForeground:(UIApplication *)application { 34 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 35 | } 36 | 37 | - (void)applicationDidBecomeActive:(UIApplication *)application { 38 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 39 | } 40 | 41 | - (void)applicationWillTerminate:(UIApplication *)application { 42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /Swizzling-Demo/Swizzling-Demo/Classes/NSArray+LXZArray.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSArray+LXZArray.h 3 | // Swizzling-Demo 4 | // 5 | // Created by 刘小壮 on 16/8/30. 6 | // Copyright © 2016年 刘小壮. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSArray (LXZArray) 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Swizzling-Demo/Swizzling-Demo/Classes/NSArray+LXZArray.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSArray+LXZArray.m 3 | // Swizzling-Demo 4 | // 5 | // Created by 刘小壮 on 16/8/30. 6 | // Copyright © 2016年 刘小壮. All rights reserved. 7 | // 8 | 9 | #import "NSArray+LXZArray.h" 10 | #import 11 | 12 | /** 13 | 在iOS中NSNumber、NSArray、NSDictionary等这些类都是类簇,一个NSArray的实现可能由多个类组成。 14 | 所以如果想对NSArray进行Swizzling,必须获取到其“真身”进行Swizzling,直接对NSArray进行操作是无效的。 15 | 16 | 下面列举了NSArray和NSDictionary本类的类名,可以通过Runtime函数取出本类。 17 | NSArray __NSArrayI 18 | NSMutableArray __NSArrayM 19 | NSDictionary __NSDictionaryI 20 | NSMutableDictionary __NSDictionaryM 21 | */ 22 | 23 | @implementation NSArray (LXZArray) 24 | 25 | // Swizzling核心代码 26 | // 需要注意的是,好多同学反馈下面代码不起作用,造成这个问题的原因大多都是其调用了super load方法。在下面的load方法中,不应该调用父类的load方法。 27 | + (void)load { 28 | Method fromMethod = class_getInstanceMethod(objc_getClass("__NSArrayI"), @selector(objectAtIndex:)); 29 | Method toMethod = class_getInstanceMethod(objc_getClass("__NSArrayI"), @selector(lxz_objectAtIndex:)); 30 | method_exchangeImplementations(fromMethod, toMethod); 31 | } 32 | 33 | // 为了避免和系统的方法冲突,我一般都会在swizzling方法前面加前缀 34 | - (id)lxz_objectAtIndex:(NSUInteger)index { 35 | // 判断下标是否越界,如果越界就进入异常拦截 36 | if (self.count-1 < index) { 37 | @try { 38 | return [self lxz_objectAtIndex:index]; 39 | } 40 | @catch (NSException *exception) { 41 | // 在崩溃后会打印崩溃信息。如果是线上,可以在这里将崩溃信息发送到服务器 42 | NSLog(@"---------- %s Crash Because Method %s ----------\n", class_getName(self.class), __func__); 43 | NSLog(@"%@", [exception callStackSymbols]); 44 | return nil; 45 | } 46 | @finally {} 47 | } // 如果没有问题,则正常进行方法调用 48 | else { 49 | return [self lxz_objectAtIndex:index]; 50 | } 51 | } 52 | 53 | @end 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /Swizzling-Demo/Swizzling-Demo/Classes/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // Swizzling-Demo 4 | // 5 | // Created by 刘小壮 on 16/8/30. 6 | // Copyright © 2016年 刘小壮. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /Swizzling-Demo/Swizzling-Demo/Classes/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // Swizzling-Demo 4 | // 5 | // Created by 刘小壮 on 16/8/30. 6 | // Copyright © 2016年 刘小壮. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | 11 | @implementation ViewController 12 | 13 | - (void)viewDidLoad { 14 | [super viewDidLoad]; 15 | 16 | /** 17 | 在本文中对NSArray进行了Swizzling,实现了NSArray异常操作的崩溃拦截功能。本篇文章只是简单的写了一下,主要是为了介绍Method Swizzling这个知识点。等以后有时间,会根据这个思路写一个崩溃拦截系统。 18 | 19 | 备注:为了方便调试过程中及时发现问题,建议只在线上版本使用这个功能,在测试阶段不要开启,以便及时发现并处理问题。 20 | */ 21 | 22 | // 测试代码 23 | NSArray *array = @[@0, @1, @2, @3]; 24 | [array objectAtIndex:3]; 25 | [array objectAtIndex:4]; 26 | } 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /Swizzling-Demo/Swizzling-Demo/Project File/Assets.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 | } -------------------------------------------------------------------------------- /Swizzling-Demo/Swizzling-Demo/Project File/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Swizzling-Demo/Swizzling-Demo/Project File/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Swizzling-Demo/Swizzling-Demo/Project File/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 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 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /Swizzling-Demo/Swizzling-Demo/Project File/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // Swizzling-Demo 4 | // 5 | // Created by 刘小壮 on 16/8/30. 6 | // Copyright © 2016年 刘小壮. 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 | --------------------------------------------------------------------------------