├── .gitignore ├── .gitmodules ├── .swiftlint.yml ├── Cartfile.private ├── Cartfile.resolved ├── LICENSE ├── README.md ├── Swizzle.podspec ├── Swizzle.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcshareddata │ └── xcschemes │ └── Swizzle.xcscheme ├── Swizzle ├── Info.plist ├── Swizzle.h └── Swizzle.swift └── SwizzleTests ├── Info.plist ├── NSObject+Dealloc.h ├── NSObject+Dealloc.m ├── SwizzleTests-Bridging-Header.h ├── SwizzleTests.swift ├── SwizzleUITests.swift └── _TestObject.swift /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | *.xccheckout 14 | *.moved-aside 15 | DerivedData 16 | *.hmap 17 | *.ipa 18 | *.xcuserstate 19 | 20 | # CocoaPods 21 | # 22 | # We recommend against adding the Pods directory to your .gitignore. However 23 | # you should judge for yourself, the pros and cons are mentioned at: 24 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 25 | # 26 | # Pods/ 27 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "Carthage/Checkouts/xcconfigs"] 2 | path = Carthage/Checkouts/xcconfigs 3 | url = https://github.com/mrackwitz/xcconfigs.git 4 | -------------------------------------------------------------------------------- /.swiftlint.yml: -------------------------------------------------------------------------------- 1 | # 2 | # NOTE: 3 | # To fix `trailing_whitespace` error, 4 | # go to Xcode Preferences -> Text Editing -> turn on both "Automatically trim trailing whitespace" and "Including whitespace-only lines". 5 | # 6 | 7 | disabled_rules: 8 | - line_length 9 | - function_body_length 10 | - type_body_length 11 | - file_length 12 | - cyclomatic_complexity 13 | 14 | - opening_brace # prefer Allman-Style 15 | - statement_position # allow `if {}\nelse {}` 16 | - type_name # allow "_" prefix name 17 | - variable_name # allow "_" prefix name 18 | - todo 19 | - valid_docs 20 | 21 | opt_in_rules: 22 | # - empty_count # local variable name `count` is frequently used 23 | 24 | included: 25 | - Swizzle 26 | - SwizzleTests 27 | 28 | excluded: 29 | - Carthage 30 | - Packages 31 | 32 | reporter: "xcode" # reporter type (xcode, json, csv, checkstyle) 33 | -------------------------------------------------------------------------------- /Cartfile.private: -------------------------------------------------------------------------------- 1 | github "mrackwitz/xcconfigs" 2 | -------------------------------------------------------------------------------- /Cartfile.resolved: -------------------------------------------------------------------------------- 1 | github "mrackwitz/xcconfigs" "3.0" 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Yasuhiro Inami 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Swizzle 2 | ======= 3 | 4 | Method-Swizzling for Swift. 5 | 6 | 7 | ## Example 8 | 9 | ```swift 10 | swizzleInstanceMethod(MyObject.self, from: #selector(MyObject.hello), to: #selector(MyObject.bye)) 11 | swizzleInstanceMethodString(MyObject.self, from: "dealloc", to: "_my_dealloc") 12 | 13 | swizzleClassMethod(MyObject.self, from: #selector(MyObject.hello), to: #selector(MyObject.bye)) 14 | swizzleClassMethodString(MyObject.self, from: "privateObjCClassMethod", to: "myClassMethod") 15 | ``` 16 | 17 | 18 | ## Licence 19 | 20 | [MIT](https://github.com/inamiy/Swizzle/blob/master/LICENSE) 21 | -------------------------------------------------------------------------------- /Swizzle.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'Swizzle' 3 | s.version = '0.1.0' 4 | s.license = { :type => 'MIT' } 5 | s.homepage = 'https://github.com/inamiy/Swizzle' 6 | s.authors = { 'Yasuhiro Inami' => 'inamiy@gmail.com' } 7 | s.summary = 'Method-Swizzling for Swift.' 8 | s.source = { :git => 'https://github.com/inamiy/Swizzle.git', :tag => "#{s.version}" } 9 | 10 | s.osx.deployment_target = '10.9' 11 | s.ios.deployment_target = '8.0' 12 | s.watchos.deployment_target = '2.0' 13 | s.tvos.deployment_target = '9.0' 14 | 15 | s.source_files = 'Swizzle/*.swift' 16 | end 17 | -------------------------------------------------------------------------------- /Swizzle.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1F7D639219C466CE00A7C3A6 /* Swizzle.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F7D639119C466CE00A7C3A6 /* Swizzle.h */; settings = {ATTRIBUTES = (Public, ); }; }; 11 | 1F7D639819C466CE00A7C3A6 /* Swizzle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1F7D638C19C466CE00A7C3A6 /* Swizzle.framework */; }; 12 | 1F7D639F19C466CE00A7C3A6 /* SwizzleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F7D639E19C466CE00A7C3A6 /* SwizzleTests.swift */; }; 13 | 1F7D63A919C466DA00A7C3A6 /* Swizzle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F7D63A819C466DA00A7C3A6 /* Swizzle.swift */; }; 14 | 1F7D63AB19C469BE00A7C3A6 /* _TestObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F7D63AA19C469BE00A7C3A6 /* _TestObject.swift */; }; 15 | 1FA3D1C819E16CC700EB17FD /* NSObject+Dealloc.m in Sources */ = {isa = PBXBuildFile; fileRef = 1FA3D1C719E16CC700EB17FD /* NSObject+Dealloc.m */; }; 16 | E200D74B219AA87F00038746 /* SwizzleUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E200D74A219AA87F00038746 /* SwizzleUITests.swift */; }; 17 | /* End PBXBuildFile section */ 18 | 19 | /* Begin PBXContainerItemProxy section */ 20 | 1F7D639919C466CE00A7C3A6 /* PBXContainerItemProxy */ = { 21 | isa = PBXContainerItemProxy; 22 | containerPortal = 1F7D638319C466CE00A7C3A6 /* Project object */; 23 | proxyType = 1; 24 | remoteGlobalIDString = 1F7D638B19C466CE00A7C3A6; 25 | remoteInfo = Swizzle; 26 | }; 27 | /* End PBXContainerItemProxy section */ 28 | 29 | /* Begin PBXFileReference section */ 30 | 1F7D638C19C466CE00A7C3A6 /* Swizzle.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Swizzle.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 31 | 1F7D639019C466CE00A7C3A6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 32 | 1F7D639119C466CE00A7C3A6 /* Swizzle.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Swizzle.h; sourceTree = ""; }; 33 | 1F7D639719C466CE00A7C3A6 /* SwizzleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwizzleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 34 | 1F7D639D19C466CE00A7C3A6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 35 | 1F7D639E19C466CE00A7C3A6 /* SwizzleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwizzleTests.swift; sourceTree = ""; }; 36 | 1F7D63A819C466DA00A7C3A6 /* Swizzle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Swizzle.swift; sourceTree = ""; }; 37 | 1F7D63AA19C469BE00A7C3A6 /* _TestObject.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = _TestObject.swift; sourceTree = ""; }; 38 | 1F9CD3C11DF6392400F16F38 /* UniversalFramework_Base.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = UniversalFramework_Base.xcconfig; sourceTree = ""; }; 39 | 1F9CD3C21DF6392400F16F38 /* UniversalFramework_Framework.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = UniversalFramework_Framework.xcconfig; sourceTree = ""; }; 40 | 1F9CD3C31DF6392400F16F38 /* UniversalFramework_Test.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = UniversalFramework_Test.xcconfig; sourceTree = ""; }; 41 | 1FA3D1C419E16C5000EB17FD /* SwizzleTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SwizzleTests-Bridging-Header.h"; sourceTree = ""; }; 42 | 1FA3D1C619E16CC700EB17FD /* NSObject+Dealloc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+Dealloc.h"; sourceTree = ""; }; 43 | 1FA3D1C719E16CC700EB17FD /* NSObject+Dealloc.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+Dealloc.m"; sourceTree = ""; }; 44 | E200D74A219AA87F00038746 /* SwizzleUITests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwizzleUITests.swift; sourceTree = ""; }; 45 | /* End PBXFileReference section */ 46 | 47 | /* Begin PBXFrameworksBuildPhase section */ 48 | 1F7D638819C466CE00A7C3A6 /* Frameworks */ = { 49 | isa = PBXFrameworksBuildPhase; 50 | buildActionMask = 2147483647; 51 | files = ( 52 | ); 53 | runOnlyForDeploymentPostprocessing = 0; 54 | }; 55 | 1F7D639419C466CE00A7C3A6 /* Frameworks */ = { 56 | isa = PBXFrameworksBuildPhase; 57 | buildActionMask = 2147483647; 58 | files = ( 59 | 1F7D639819C466CE00A7C3A6 /* Swizzle.framework in Frameworks */, 60 | ); 61 | runOnlyForDeploymentPostprocessing = 0; 62 | }; 63 | /* End PBXFrameworksBuildPhase section */ 64 | 65 | /* Begin PBXGroup section */ 66 | 1F7D638219C466CE00A7C3A6 = { 67 | isa = PBXGroup; 68 | children = ( 69 | 1F9CD3BB1DF6392400F16F38 /* xcconfigs */, 70 | 1F7D638E19C466CE00A7C3A6 /* Swizzle */, 71 | 1F7D639B19C466CE00A7C3A6 /* SwizzleTests */, 72 | 1F7D638D19C466CE00A7C3A6 /* Products */, 73 | ); 74 | sourceTree = ""; 75 | }; 76 | 1F7D638D19C466CE00A7C3A6 /* Products */ = { 77 | isa = PBXGroup; 78 | children = ( 79 | 1F7D638C19C466CE00A7C3A6 /* Swizzle.framework */, 80 | 1F7D639719C466CE00A7C3A6 /* SwizzleTests.xctest */, 81 | ); 82 | name = Products; 83 | sourceTree = ""; 84 | }; 85 | 1F7D638E19C466CE00A7C3A6 /* Swizzle */ = { 86 | isa = PBXGroup; 87 | children = ( 88 | 1F7D639119C466CE00A7C3A6 /* Swizzle.h */, 89 | 1F7D63A819C466DA00A7C3A6 /* Swizzle.swift */, 90 | 1F7D638F19C466CE00A7C3A6 /* Supporting Files */, 91 | ); 92 | path = Swizzle; 93 | sourceTree = ""; 94 | }; 95 | 1F7D638F19C466CE00A7C3A6 /* Supporting Files */ = { 96 | isa = PBXGroup; 97 | children = ( 98 | 1F7D639019C466CE00A7C3A6 /* Info.plist */, 99 | ); 100 | name = "Supporting Files"; 101 | sourceTree = ""; 102 | }; 103 | 1F7D639B19C466CE00A7C3A6 /* SwizzleTests */ = { 104 | isa = PBXGroup; 105 | children = ( 106 | 1FDEA67E1DF63A1F00869C7B /* Fixtures */, 107 | 1F7D639E19C466CE00A7C3A6 /* SwizzleTests.swift */, 108 | E200D74A219AA87F00038746 /* SwizzleUITests.swift */, 109 | 1F7D639C19C466CE00A7C3A6 /* Supporting Files */, 110 | ); 111 | path = SwizzleTests; 112 | sourceTree = ""; 113 | }; 114 | 1F7D639C19C466CE00A7C3A6 /* Supporting Files */ = { 115 | isa = PBXGroup; 116 | children = ( 117 | 1F7D639D19C466CE00A7C3A6 /* Info.plist */, 118 | ); 119 | name = "Supporting Files"; 120 | sourceTree = ""; 121 | }; 122 | 1F9CD3BB1DF6392400F16F38 /* xcconfigs */ = { 123 | isa = PBXGroup; 124 | children = ( 125 | 1F9CD3C11DF6392400F16F38 /* UniversalFramework_Base.xcconfig */, 126 | 1F9CD3C21DF6392400F16F38 /* UniversalFramework_Framework.xcconfig */, 127 | 1F9CD3C31DF6392400F16F38 /* UniversalFramework_Test.xcconfig */, 128 | ); 129 | name = xcconfigs; 130 | path = Carthage/Checkouts/xcconfigs; 131 | sourceTree = ""; 132 | }; 133 | 1FA3D1C919E1700400EB17FD /* ObjC-bridging */ = { 134 | isa = PBXGroup; 135 | children = ( 136 | 1FA3D1C419E16C5000EB17FD /* SwizzleTests-Bridging-Header.h */, 137 | 1FA3D1C619E16CC700EB17FD /* NSObject+Dealloc.h */, 138 | 1FA3D1C719E16CC700EB17FD /* NSObject+Dealloc.m */, 139 | ); 140 | name = "ObjC-bridging"; 141 | sourceTree = ""; 142 | }; 143 | 1FDEA67E1DF63A1F00869C7B /* Fixtures */ = { 144 | isa = PBXGroup; 145 | children = ( 146 | 1FA3D1C919E1700400EB17FD /* ObjC-bridging */, 147 | 1F7D63AA19C469BE00A7C3A6 /* _TestObject.swift */, 148 | ); 149 | name = Fixtures; 150 | sourceTree = ""; 151 | }; 152 | /* End PBXGroup section */ 153 | 154 | /* Begin PBXHeadersBuildPhase section */ 155 | 1F7D638919C466CE00A7C3A6 /* Headers */ = { 156 | isa = PBXHeadersBuildPhase; 157 | buildActionMask = 2147483647; 158 | files = ( 159 | 1F7D639219C466CE00A7C3A6 /* Swizzle.h in Headers */, 160 | ); 161 | runOnlyForDeploymentPostprocessing = 0; 162 | }; 163 | /* End PBXHeadersBuildPhase section */ 164 | 165 | /* Begin PBXNativeTarget section */ 166 | 1F7D638B19C466CE00A7C3A6 /* Swizzle */ = { 167 | isa = PBXNativeTarget; 168 | buildConfigurationList = 1F7D63A219C466CE00A7C3A6 /* Build configuration list for PBXNativeTarget "Swizzle" */; 169 | buildPhases = ( 170 | 1F7D638719C466CE00A7C3A6 /* Sources */, 171 | 1F7D638819C466CE00A7C3A6 /* Frameworks */, 172 | 1F7D638919C466CE00A7C3A6 /* Headers */, 173 | 1F7D638A19C466CE00A7C3A6 /* Resources */, 174 | ); 175 | buildRules = ( 176 | ); 177 | dependencies = ( 178 | ); 179 | name = Swizzle; 180 | productName = Swizzle; 181 | productReference = 1F7D638C19C466CE00A7C3A6 /* Swizzle.framework */; 182 | productType = "com.apple.product-type.framework"; 183 | }; 184 | 1F7D639619C466CE00A7C3A6 /* SwizzleTests */ = { 185 | isa = PBXNativeTarget; 186 | buildConfigurationList = 1F7D63A519C466CE00A7C3A6 /* Build configuration list for PBXNativeTarget "SwizzleTests" */; 187 | buildPhases = ( 188 | 1F7D639319C466CE00A7C3A6 /* Sources */, 189 | 1F7D639419C466CE00A7C3A6 /* Frameworks */, 190 | 1F7D639519C466CE00A7C3A6 /* Resources */, 191 | ); 192 | buildRules = ( 193 | ); 194 | dependencies = ( 195 | 1F7D639A19C466CE00A7C3A6 /* PBXTargetDependency */, 196 | ); 197 | name = SwizzleTests; 198 | productName = SwizzleTests; 199 | productReference = 1F7D639719C466CE00A7C3A6 /* SwizzleTests.xctest */; 200 | productType = "com.apple.product-type.bundle.unit-test"; 201 | }; 202 | /* End PBXNativeTarget section */ 203 | 204 | /* Begin PBXProject section */ 205 | 1F7D638319C466CE00A7C3A6 /* Project object */ = { 206 | isa = PBXProject; 207 | attributes = { 208 | LastUpgradeCheck = 1000; 209 | ORGANIZATIONNAME = "Yasuhiro Inami"; 210 | TargetAttributes = { 211 | 1F7D638B19C466CE00A7C3A6 = { 212 | CreatedOnToolsVersion = 6.1; 213 | LastSwiftMigration = 1000; 214 | }; 215 | 1F7D639619C466CE00A7C3A6 = { 216 | CreatedOnToolsVersion = 6.1; 217 | LastSwiftMigration = 1000; 218 | }; 219 | }; 220 | }; 221 | buildConfigurationList = 1F7D638619C466CE00A7C3A6 /* Build configuration list for PBXProject "Swizzle" */; 222 | compatibilityVersion = "Xcode 3.2"; 223 | developmentRegion = English; 224 | hasScannedForEncodings = 0; 225 | knownRegions = ( 226 | en, 227 | ); 228 | mainGroup = 1F7D638219C466CE00A7C3A6; 229 | productRefGroup = 1F7D638D19C466CE00A7C3A6 /* Products */; 230 | projectDirPath = ""; 231 | projectRoot = ""; 232 | targets = ( 233 | 1F7D638B19C466CE00A7C3A6 /* Swizzle */, 234 | 1F7D639619C466CE00A7C3A6 /* SwizzleTests */, 235 | ); 236 | }; 237 | /* End PBXProject section */ 238 | 239 | /* Begin PBXResourcesBuildPhase section */ 240 | 1F7D638A19C466CE00A7C3A6 /* Resources */ = { 241 | isa = PBXResourcesBuildPhase; 242 | buildActionMask = 2147483647; 243 | files = ( 244 | ); 245 | runOnlyForDeploymentPostprocessing = 0; 246 | }; 247 | 1F7D639519C466CE00A7C3A6 /* Resources */ = { 248 | isa = PBXResourcesBuildPhase; 249 | buildActionMask = 2147483647; 250 | files = ( 251 | ); 252 | runOnlyForDeploymentPostprocessing = 0; 253 | }; 254 | /* End PBXResourcesBuildPhase section */ 255 | 256 | /* Begin PBXSourcesBuildPhase section */ 257 | 1F7D638719C466CE00A7C3A6 /* Sources */ = { 258 | isa = PBXSourcesBuildPhase; 259 | buildActionMask = 2147483647; 260 | files = ( 261 | 1F7D63A919C466DA00A7C3A6 /* Swizzle.swift in Sources */, 262 | ); 263 | runOnlyForDeploymentPostprocessing = 0; 264 | }; 265 | 1F7D639319C466CE00A7C3A6 /* Sources */ = { 266 | isa = PBXSourcesBuildPhase; 267 | buildActionMask = 2147483647; 268 | files = ( 269 | 1FA3D1C819E16CC700EB17FD /* NSObject+Dealloc.m in Sources */, 270 | 1F7D639F19C466CE00A7C3A6 /* SwizzleTests.swift in Sources */, 271 | E200D74B219AA87F00038746 /* SwizzleUITests.swift in Sources */, 272 | 1F7D63AB19C469BE00A7C3A6 /* _TestObject.swift in Sources */, 273 | ); 274 | runOnlyForDeploymentPostprocessing = 0; 275 | }; 276 | /* End PBXSourcesBuildPhase section */ 277 | 278 | /* Begin PBXTargetDependency section */ 279 | 1F7D639A19C466CE00A7C3A6 /* PBXTargetDependency */ = { 280 | isa = PBXTargetDependency; 281 | target = 1F7D638B19C466CE00A7C3A6 /* Swizzle */; 282 | targetProxy = 1F7D639919C466CE00A7C3A6 /* PBXContainerItemProxy */; 283 | }; 284 | /* End PBXTargetDependency section */ 285 | 286 | /* Begin XCBuildConfiguration section */ 287 | 1F7D63A019C466CE00A7C3A6 /* Debug */ = { 288 | isa = XCBuildConfiguration; 289 | baseConfigurationReference = 1F9CD3C11DF6392400F16F38 /* UniversalFramework_Base.xcconfig */; 290 | buildSettings = { 291 | ALWAYS_SEARCH_USER_PATHS = NO; 292 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 293 | CLANG_CXX_LIBRARY = "libc++"; 294 | CLANG_ENABLE_MODULES = YES; 295 | CLANG_ENABLE_OBJC_ARC = YES; 296 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 297 | CLANG_WARN_BOOL_CONVERSION = YES; 298 | CLANG_WARN_COMMA = YES; 299 | CLANG_WARN_CONSTANT_CONVERSION = YES; 300 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 301 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 302 | CLANG_WARN_EMPTY_BODY = YES; 303 | CLANG_WARN_ENUM_CONVERSION = YES; 304 | CLANG_WARN_INFINITE_RECURSION = YES; 305 | CLANG_WARN_INT_CONVERSION = YES; 306 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 307 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 308 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 309 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 310 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 311 | CLANG_WARN_STRICT_PROTOTYPES = YES; 312 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 313 | CLANG_WARN_UNREACHABLE_CODE = YES; 314 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 315 | COPY_PHASE_STRIP = NO; 316 | CURRENT_PROJECT_VERSION = 1; 317 | ENABLE_STRICT_OBJC_MSGSEND = YES; 318 | ENABLE_TESTABILITY = YES; 319 | GCC_C_LANGUAGE_STANDARD = gnu99; 320 | GCC_DYNAMIC_NO_PIC = NO; 321 | GCC_NO_COMMON_BLOCKS = YES; 322 | GCC_OPTIMIZATION_LEVEL = 0; 323 | GCC_PREPROCESSOR_DEFINITIONS = ( 324 | "DEBUG=1", 325 | "$(inherited)", 326 | ); 327 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 328 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 329 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 330 | GCC_WARN_UNDECLARED_SELECTOR = YES; 331 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 332 | GCC_WARN_UNUSED_FUNCTION = YES; 333 | GCC_WARN_UNUSED_VARIABLE = YES; 334 | MTL_ENABLE_DEBUG_INFO = YES; 335 | ONLY_ACTIVE_ARCH = YES; 336 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 337 | VERSIONING_SYSTEM = "apple-generic"; 338 | VERSION_INFO_PREFIX = ""; 339 | }; 340 | name = Debug; 341 | }; 342 | 1F7D63A119C466CE00A7C3A6 /* Release */ = { 343 | isa = XCBuildConfiguration; 344 | baseConfigurationReference = 1F9CD3C11DF6392400F16F38 /* UniversalFramework_Base.xcconfig */; 345 | buildSettings = { 346 | ALWAYS_SEARCH_USER_PATHS = NO; 347 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 348 | CLANG_CXX_LIBRARY = "libc++"; 349 | CLANG_ENABLE_MODULES = YES; 350 | CLANG_ENABLE_OBJC_ARC = YES; 351 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 352 | CLANG_WARN_BOOL_CONVERSION = YES; 353 | CLANG_WARN_COMMA = YES; 354 | CLANG_WARN_CONSTANT_CONVERSION = YES; 355 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 356 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 357 | CLANG_WARN_EMPTY_BODY = YES; 358 | CLANG_WARN_ENUM_CONVERSION = YES; 359 | CLANG_WARN_INFINITE_RECURSION = YES; 360 | CLANG_WARN_INT_CONVERSION = YES; 361 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 362 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 363 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 364 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 365 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 366 | CLANG_WARN_STRICT_PROTOTYPES = YES; 367 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 368 | CLANG_WARN_UNREACHABLE_CODE = YES; 369 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 370 | COPY_PHASE_STRIP = YES; 371 | CURRENT_PROJECT_VERSION = 1; 372 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 373 | ENABLE_NS_ASSERTIONS = NO; 374 | ENABLE_STRICT_OBJC_MSGSEND = YES; 375 | GCC_C_LANGUAGE_STANDARD = gnu99; 376 | GCC_NO_COMMON_BLOCKS = YES; 377 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 378 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 379 | GCC_WARN_UNDECLARED_SELECTOR = YES; 380 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 381 | GCC_WARN_UNUSED_FUNCTION = YES; 382 | GCC_WARN_UNUSED_VARIABLE = YES; 383 | MTL_ENABLE_DEBUG_INFO = NO; 384 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 385 | VERSIONING_SYSTEM = "apple-generic"; 386 | VERSION_INFO_PREFIX = ""; 387 | }; 388 | name = Release; 389 | }; 390 | 1F7D63A319C466CE00A7C3A6 /* Debug */ = { 391 | isa = XCBuildConfiguration; 392 | baseConfigurationReference = 1F9CD3C21DF6392400F16F38 /* UniversalFramework_Framework.xcconfig */; 393 | buildSettings = { 394 | CLANG_ENABLE_MODULES = YES; 395 | COMBINE_HIDPI_IMAGES = YES; 396 | DEFINES_MODULE = YES; 397 | DYLIB_COMPATIBILITY_VERSION = 1; 398 | DYLIB_CURRENT_VERSION = 1; 399 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 400 | FRAMEWORK_VERSION = A; 401 | INFOPLIST_FILE = Swizzle/Info.plist; 402 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 403 | PRODUCT_BUNDLE_IDENTIFIER = "com.inamiy.$(PRODUCT_NAME:rfc1034identifier)"; 404 | PRODUCT_NAME = "$(PROJECT_NAME)"; 405 | SKIP_INSTALL = YES; 406 | SWIFT_VERSION = 4.2; 407 | }; 408 | name = Debug; 409 | }; 410 | 1F7D63A419C466CE00A7C3A6 /* Release */ = { 411 | isa = XCBuildConfiguration; 412 | baseConfigurationReference = 1F9CD3C21DF6392400F16F38 /* UniversalFramework_Framework.xcconfig */; 413 | buildSettings = { 414 | CLANG_ENABLE_MODULES = YES; 415 | COMBINE_HIDPI_IMAGES = YES; 416 | DEFINES_MODULE = YES; 417 | DYLIB_COMPATIBILITY_VERSION = 1; 418 | DYLIB_CURRENT_VERSION = 1; 419 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 420 | FRAMEWORK_VERSION = A; 421 | INFOPLIST_FILE = Swizzle/Info.plist; 422 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 423 | PRODUCT_BUNDLE_IDENTIFIER = "com.inamiy.$(PRODUCT_NAME:rfc1034identifier)"; 424 | PRODUCT_NAME = "$(PROJECT_NAME)"; 425 | SKIP_INSTALL = YES; 426 | SWIFT_VERSION = 4.2; 427 | }; 428 | name = Release; 429 | }; 430 | 1F7D63A619C466CE00A7C3A6 /* Debug */ = { 431 | isa = XCBuildConfiguration; 432 | baseConfigurationReference = 1F9CD3C31DF6392400F16F38 /* UniversalFramework_Test.xcconfig */; 433 | buildSettings = { 434 | CLANG_ENABLE_MODULES = YES; 435 | COMBINE_HIDPI_IMAGES = YES; 436 | FRAMEWORK_SEARCH_PATHS = ( 437 | "$(DEVELOPER_FRAMEWORKS_DIR)", 438 | "$(inherited)", 439 | ); 440 | GCC_PREPROCESSOR_DEFINITIONS = ( 441 | "DEBUG=1", 442 | "$(inherited)", 443 | ); 444 | INFOPLIST_FILE = SwizzleTests/Info.plist; 445 | PRODUCT_BUNDLE_IDENTIFIER = "com.inamiy.$(PRODUCT_NAME:rfc1034identifier)"; 446 | PRODUCT_NAME = "$(TARGET_NAME)"; 447 | SWIFT_OBJC_BRIDGING_HEADER = "SwizzleTests/SwizzleTests-Bridging-Header.h"; 448 | SWIFT_VERSION = 4.2; 449 | }; 450 | name = Debug; 451 | }; 452 | 1F7D63A719C466CE00A7C3A6 /* Release */ = { 453 | isa = XCBuildConfiguration; 454 | baseConfigurationReference = 1F9CD3C31DF6392400F16F38 /* UniversalFramework_Test.xcconfig */; 455 | buildSettings = { 456 | CLANG_ENABLE_MODULES = YES; 457 | COMBINE_HIDPI_IMAGES = YES; 458 | FRAMEWORK_SEARCH_PATHS = ( 459 | "$(DEVELOPER_FRAMEWORKS_DIR)", 460 | "$(inherited)", 461 | ); 462 | INFOPLIST_FILE = SwizzleTests/Info.plist; 463 | PRODUCT_BUNDLE_IDENTIFIER = "com.inamiy.$(PRODUCT_NAME:rfc1034identifier)"; 464 | PRODUCT_NAME = "$(TARGET_NAME)"; 465 | SWIFT_OBJC_BRIDGING_HEADER = "SwizzleTests/SwizzleTests-Bridging-Header.h"; 466 | SWIFT_VERSION = 4.2; 467 | }; 468 | name = Release; 469 | }; 470 | /* End XCBuildConfiguration section */ 471 | 472 | /* Begin XCConfigurationList section */ 473 | 1F7D638619C466CE00A7C3A6 /* Build configuration list for PBXProject "Swizzle" */ = { 474 | isa = XCConfigurationList; 475 | buildConfigurations = ( 476 | 1F7D63A019C466CE00A7C3A6 /* Debug */, 477 | 1F7D63A119C466CE00A7C3A6 /* Release */, 478 | ); 479 | defaultConfigurationIsVisible = 0; 480 | defaultConfigurationName = Release; 481 | }; 482 | 1F7D63A219C466CE00A7C3A6 /* Build configuration list for PBXNativeTarget "Swizzle" */ = { 483 | isa = XCConfigurationList; 484 | buildConfigurations = ( 485 | 1F7D63A319C466CE00A7C3A6 /* Debug */, 486 | 1F7D63A419C466CE00A7C3A6 /* Release */, 487 | ); 488 | defaultConfigurationIsVisible = 0; 489 | defaultConfigurationName = Release; 490 | }; 491 | 1F7D63A519C466CE00A7C3A6 /* Build configuration list for PBXNativeTarget "SwizzleTests" */ = { 492 | isa = XCConfigurationList; 493 | buildConfigurations = ( 494 | 1F7D63A619C466CE00A7C3A6 /* Debug */, 495 | 1F7D63A719C466CE00A7C3A6 /* Release */, 496 | ); 497 | defaultConfigurationIsVisible = 0; 498 | defaultConfigurationName = Release; 499 | }; 500 | /* End XCConfigurationList section */ 501 | }; 502 | rootObject = 1F7D638319C466CE00A7C3A6 /* Project object */; 503 | } 504 | -------------------------------------------------------------------------------- /Swizzle.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Swizzle.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Swizzle.xcodeproj/xcshareddata/xcschemes/Swizzle.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 65 | 71 | 72 | 73 | 74 | 75 | 76 | 82 | 83 | 89 | 90 | 91 | 92 | 94 | 95 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /Swizzle/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 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSHumanReadableCopyright 24 | Copyright © 2014年 Yasuhiro Inami. All rights reserved. 25 | NSPrincipalClass 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /Swizzle/Swizzle.h: -------------------------------------------------------------------------------- 1 | // 2 | // Swizzle.h 3 | // Swizzle 4 | // 5 | // Created by Yasuhiro Inami on 2014/09/14. 6 | // Copyright (c) 2014年 Yasuhiro Inami. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for Swizzle. 12 | FOUNDATION_EXPORT double SwizzleVersionNumber; 13 | 14 | //! Project version string for Swizzle. 15 | FOUNDATION_EXPORT const unsigned char SwizzleVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /Swizzle/Swizzle.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Swizzle.swift 3 | // Swizzle 4 | // 5 | // Created by Yasuhiro Inami on 2014/09/14. 6 | // Copyright (c) 2014年 Yasuhiro Inami. All rights reserved. 7 | // 8 | 9 | import ObjectiveC 10 | 11 | private func _swizzleMethod(_ class_: AnyClass, from selector1: Selector, to selector2: Selector, isClassMethod: Bool) 12 | { 13 | let c: AnyClass 14 | if isClassMethod { 15 | guard let c_ = object_getClass(class_) else { 16 | return 17 | } 18 | c = c_ 19 | } 20 | else { 21 | c = class_ 22 | } 23 | 24 | guard let method1: Method = class_getInstanceMethod(c, selector1), 25 | let method2: Method = class_getInstanceMethod(c, selector2) else 26 | { 27 | return 28 | } 29 | 30 | if class_addMethod(c, selector1, method_getImplementation(method2), method_getTypeEncoding(method2)) { 31 | class_replaceMethod(c, selector2, method_getImplementation(method1), method_getTypeEncoding(method1)) 32 | } 33 | else { 34 | method_exchangeImplementations(method1, method2) 35 | } 36 | } 37 | 38 | /// Instance-method swizzling. 39 | public func swizzleInstanceMethod(_ class_: AnyClass, from sel1: Selector, to sel2: Selector) 40 | { 41 | _swizzleMethod(class_, from: sel1, to: sel2, isClassMethod: false) 42 | } 43 | 44 | /// Instance-method swizzling for unsafe raw-string. 45 | /// - Note: This is useful for non-`#selector`able methods e.g. `dealloc`, private ObjC methods. 46 | public func swizzleInstanceMethodString(_ class_: AnyClass, from sel1: String, to sel2: String) 47 | { 48 | swizzleInstanceMethod(class_, from: Selector(sel1), to: Selector(sel2)) 49 | } 50 | 51 | /// Class-method swizzling. 52 | public func swizzleClassMethod(_ class_: AnyClass, from sel1: Selector, to sel2: Selector) 53 | { 54 | _swizzleMethod(class_, from: sel1, to: sel2, isClassMethod: true) 55 | } 56 | 57 | /// Class-method swizzling for unsafe raw-string. 58 | public func swizzleClassMethodString(_ class_: AnyClass, from sel1: String, to sel2: String) 59 | { 60 | swizzleClassMethod(class_, from: Selector(sel1), to: Selector(sel2)) 61 | } 62 | -------------------------------------------------------------------------------- /SwizzleTests/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 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /SwizzleTests/NSObject+Dealloc.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+Dealloc.h 3 | // Swizzle 4 | // 5 | // Created by Yasuhiro Inami on 2014/10/05. 6 | // Copyright (c) 2014年 Yasuhiro Inami. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSObject (Dealloc) 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /SwizzleTests/NSObject+Dealloc.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+Dealloc.m 3 | // Swizzle 4 | // 5 | // Created by Yasuhiro Inami on 2014/10/05. 6 | // Copyright (c) 2014年 Yasuhiro Inami. All rights reserved. 7 | // 8 | 9 | #import "NSObject+Dealloc.h" 10 | 11 | @implementation NSObject (Dealloc) 12 | 13 | - (void)_objc_dealloc 14 | { 15 | NSLog(@"_objc_dealloc"); 16 | [self _objc_dealloc]; 17 | } 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /SwizzleTests/SwizzleTests-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Use this file to import your target's public headers that you would like to expose to Swift. 3 | // 4 | 5 | -------------------------------------------------------------------------------- /SwizzleTests/SwizzleTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwizzleTests.swift 3 | // SwizzleTests 4 | // 5 | // Created by Yasuhiro Inami on 2014/09/14. 6 | // Copyright (c) 2014年 Yasuhiro Inami. All rights reserved. 7 | // 8 | 9 | import Swizzle 10 | import XCTest 11 | 12 | class SwizzleTests: XCTestCase 13 | { 14 | func testSwizzleInstanceMethod() 15 | { 16 | let swizzle: () -> Void = { 17 | swizzleInstanceMethod(NSObject.self, from: #selector(NSObject.hello), to: #selector(NSObject.bye)) 18 | } 19 | 20 | let obj = NSObject() 21 | 22 | // original 23 | XCTAssertEqual(obj.hello(), "NSObject-hello") 24 | XCTAssertEqual(obj.bye(), "NSObject-bye") 25 | 26 | swizzle() 27 | 28 | // swizzled 29 | XCTAssertEqual(obj.hello(), "NSObject-bye") 30 | XCTAssertEqual(obj.bye(), "NSObject-hello") 31 | 32 | swizzle() // clean up 33 | 34 | // back to original 35 | XCTAssertEqual(obj.hello(), "NSObject-hello") 36 | XCTAssertEqual(obj.bye(), "NSObject-bye") 37 | } 38 | 39 | func testSwizzleClassMethod() 40 | { 41 | let swizzle: () -> Void = { 42 | swizzleClassMethod(NSObject.self, from: #selector(NSObject.hello), to: #selector(NSObject.bye)) 43 | } 44 | 45 | // original 46 | XCTAssertEqual(NSObject.hello(), "NSObject+hello") 47 | XCTAssertEqual(NSObject.bye(), "NSObject+bye") 48 | 49 | swizzle() 50 | 51 | // swizzled 52 | XCTAssertEqual(NSObject.hello(), "NSObject+bye") 53 | XCTAssertEqual(NSObject.bye(), "NSObject+hello") 54 | 55 | swizzle() // clean up 56 | 57 | // back to original 58 | XCTAssertEqual(NSObject.hello(), "NSObject+hello") 59 | XCTAssertEqual(NSObject.bye(), "NSObject+bye") 60 | } 61 | 62 | func testSubclass() 63 | { 64 | // NOTE: MyObject-hello is not implemented (uses super-method) 65 | 66 | let swizzle: () -> Void = { 67 | swizzleInstanceMethod(MyObject.self, from: #selector(MyObject.hello), to: #selector(MyObject.bonjour)) 68 | swizzleClassMethod(MyObject.self, from: #selector(MyObject.hello), to: #selector(MyObject.bonjour)) 69 | } 70 | 71 | let myObj = MyObject() 72 | 73 | // original 74 | XCTAssertEqual(myObj.hello(), "NSObject-hello") 75 | XCTAssertEqual(MyObject.hello(), "NSObject+hello") 76 | XCTAssertEqual(myObj.bonjour(), "MyObject-bonjour") 77 | XCTAssertEqual(MyObject.bonjour(), "MyObject+bonjour") 78 | 79 | swizzle() 80 | 81 | // swizzled 82 | XCTAssertEqual(myObj.hello(), "MyObject-bonjour") 83 | XCTAssertEqual(MyObject.hello(), "MyObject+bonjour") 84 | XCTAssertEqual(myObj.bonjour(), "NSObject-hello") 85 | XCTAssertEqual(MyObject.bonjour(), "NSObject+hello") 86 | 87 | swizzle() // clean up 88 | 89 | // back to original 90 | XCTAssertEqual(myObj.hello(), "NSObject-hello") 91 | XCTAssertEqual(MyObject.hello(), "NSObject+hello") 92 | XCTAssertEqual(myObj.bonjour(), "MyObject-bonjour") 93 | XCTAssertEqual(MyObject.bonjour(), "MyObject+bonjour") 94 | } 95 | 96 | func testSubclass_reversed() 97 | { 98 | // NOTE: MyObject-hello is not implemented (uses super-method) 99 | 100 | let swizzle: () -> Void = { 101 | swizzleInstanceMethod(MyObject.self, from: #selector(MyObject.bonjour), to: #selector(MyObject.hello)) // reversed 102 | swizzleClassMethod(MyObject.self, from: #selector(MyObject.bonjour), to: #selector(MyObject.hello)) // reversed 103 | } 104 | 105 | let myObj = MyObject() 106 | 107 | // original 108 | XCTAssertEqual(myObj.hello(), "NSObject-hello") 109 | XCTAssertEqual(MyObject.hello(), "NSObject+hello") 110 | XCTAssertEqual(myObj.bonjour(), "MyObject-bonjour") 111 | XCTAssertEqual(MyObject.bonjour(), "MyObject+bonjour") 112 | 113 | swizzle() 114 | 115 | // swizzled 116 | XCTAssertEqual(myObj.hello(), "MyObject-bonjour") 117 | XCTAssertEqual(MyObject.hello(), "MyObject+bonjour") 118 | XCTAssertEqual(myObj.bonjour(), "NSObject-hello") 119 | XCTAssertEqual(MyObject.bonjour(), "NSObject+hello") 120 | 121 | swizzle() // clean up 122 | 123 | // back to original 124 | XCTAssertEqual(myObj.hello(), "NSObject-hello") 125 | XCTAssertEqual(MyObject.hello(), "NSObject+hello") 126 | XCTAssertEqual(myObj.bonjour(), "MyObject-bonjour") 127 | XCTAssertEqual(MyObject.bonjour(), "MyObject+bonjour") 128 | } 129 | 130 | func testDealloc() 131 | { 132 | let swizzle: () -> Void = { 133 | // swizzleInstanceMethodString(MyObject.self, "dealloc", "_swift_dealloc") // comment-out: doesn't work 134 | swizzleInstanceMethodString(MyObject.self, from: "dealloc", to: "_objc_dealloc") // NOTE: swizzled_dealloc must be implemented as ObjC code 135 | } 136 | 137 | swizzle() 138 | 139 | let expect = self.expectation(description: #function) 140 | 141 | let _ = MyObject() { // deinitClosure 142 | expect.fulfill() 143 | } 144 | 145 | self.waitForExpectations(timeout: 1, handler: nil) 146 | } 147 | 148 | } 149 | -------------------------------------------------------------------------------- /SwizzleTests/SwizzleUITests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwizzleTests.swift 3 | // SwizzleTests 4 | // 5 | // Created by Yasuhiro Inami on 2014/09/14. 6 | // Copyright (c) 2014年 Yasuhiro Inami. All rights reserved. 7 | // 8 | 9 | import Swizzle 10 | import AppKit 11 | import XCTest 12 | 13 | private let _key = UnsafeMutablePointer.allocate(capacity: 1) 14 | 15 | class SwizzleUITests: XCTestCase 16 | { 17 | func testHoge() 18 | { 19 | let swizzle: () -> Void = { 20 | swizzleInstanceMethod( 21 | NSView.self, 22 | from: #selector(getter: NSView.alphaValue), 23 | to: #selector(getter: NSView.__alphaValue) 24 | ) 25 | } 26 | 27 | let view = NSView() 28 | 29 | // original 30 | XCTAssertEqual(view.alphaValue, 1) 31 | 32 | swizzle() 33 | 34 | // swizzled 35 | XCTAssertEqual(view.alphaValue, 0.5) 36 | 37 | // NOTE: Setter is not swizzled. 38 | view.alphaValue = 0.6 39 | 40 | XCTAssertEqual(view.alphaValue, 0.1, accuracy: 0.0001) 41 | 42 | swizzle() // clean up 43 | 44 | XCTAssertEqual(view.alphaValue, 0.6) 45 | 46 | view.alphaValue = 1 47 | 48 | XCTAssertEqual(view.alphaValue, 1) 49 | } 50 | 51 | func testHoge2() 52 | { 53 | let swizzle: () -> Void = { 54 | swizzleInstanceMethod( 55 | NSView.self, 56 | from: #selector(getter: NSView.alphaValue), 57 | to: #selector(getter: NSView.__alphaValue2) 58 | ) 59 | 60 | swizzleInstanceMethod( 61 | NSView.self, 62 | from: #selector(setter: NSView.alphaValue), 63 | to: #selector(NSView.__setAlphaValue2(_:)) 64 | ) 65 | } 66 | 67 | let view = NSView() 68 | 69 | // original 70 | XCTAssertEqual(view.alphaValue, 1) 71 | 72 | swizzle() 73 | 74 | // swizzled 75 | XCTAssertEqual(view.alphaValue, -1) 76 | 77 | // NOTE: Setter is not swizzled. 78 | view.alphaValue = 0.6 79 | 80 | XCTAssertEqual(view.alphaValue, 0.6) 81 | 82 | swizzle() // clean up 83 | 84 | XCTAssertEqual(view.alphaValue, 0.6) 85 | 86 | view.alphaValue = 1 87 | 88 | XCTAssertEqual(view.alphaValue, 1) 89 | } 90 | } 91 | 92 | // MARK: - Private 93 | 94 | extension NSView 95 | { 96 | @objc fileprivate var __alphaValue: CGFloat 97 | { 98 | return self.__alphaValue - 0.5 99 | } 100 | 101 | @objc fileprivate var __alphaValue2: CGFloat 102 | { 103 | if let value = objc_getAssociatedObject(self, _key) as? CGFloat { 104 | return value 105 | } 106 | else { 107 | return -1 // default value 108 | } 109 | } 110 | 111 | @objc fileprivate func __setAlphaValue2(_ alpha: CGFloat) 112 | { 113 | self.__setAlphaValue2(alpha) 114 | objc_setAssociatedObject(self, _key, alpha, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /SwizzleTests/_TestObject.swift: -------------------------------------------------------------------------------- 1 | // 2 | // _TestObject.swift 3 | // SwizzleTests 4 | // 5 | // Created by Yasuhiro Inami on 2014/09/14. 6 | // Copyright (c) 2014年 Yasuhiro Inami. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension NSObject 12 | { 13 | @objc func hello() -> String 14 | { 15 | return "NSObject-hello" 16 | } 17 | 18 | @objc func bye() -> String 19 | { 20 | return "NSObject-bye" 21 | } 22 | 23 | @objc class func hello() -> String 24 | { 25 | return "NSObject+hello" 26 | } 27 | 28 | @objc class func bye() -> String 29 | { 30 | return "NSObject+bye" 31 | } 32 | } 33 | 34 | class MyObject: NSObject 35 | { 36 | // NOTE: dynamic is required for method-swizzling 37 | @objc dynamic func bonjour() -> String 38 | { 39 | return "MyObject-bonjour" 40 | } 41 | 42 | @objc dynamic class func bonjour() -> String 43 | { 44 | return "MyObject+bonjour" 45 | } 46 | 47 | let deinitClosure: (() -> Void)? 48 | 49 | init(deinitClosure: (() -> Void)? = nil) 50 | { 51 | self.deinitClosure = deinitClosure 52 | super.init() 53 | 54 | print("[init] \(self)") 55 | } 56 | 57 | deinit 58 | { 59 | print("[deinit] \(self)") 60 | 61 | self.deinitClosure?() 62 | } 63 | 64 | // WARNING: swizzling `dealloc` in Swift won't work 65 | @objc dynamic func _swift_dealloc() 66 | { 67 | print("_swift_dealloc") 68 | self._swift_dealloc() 69 | } 70 | } 71 | --------------------------------------------------------------------------------