├── Example ├── Example.xcodeproj │ └── project.pbxproj └── Example │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Base.lproj │ └── Main.storyboard │ ├── DummyClass.h │ ├── DummyClass.m │ ├── Example-Info.plist │ ├── Example-Prefix.pch │ ├── Images.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── LaunchImage.launchimage │ │ └── Contents.json │ ├── SecondViewController.h │ ├── SecondViewController.m │ ├── ViewController.h │ ├── ViewController.m │ ├── en.lproj │ └── InfoPlist.strings │ └── main.m ├── INTUWeakForwarder.h ├── INTUWeakForwarder.m ├── LICENSE └── README.md /Example/Example.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 7F32F9F818E394FE00BF3FF4 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F32F9F718E394FE00BF3FF4 /* Foundation.framework */; }; 11 | 7F32F9FA18E394FE00BF3FF4 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F32F9F918E394FE00BF3FF4 /* CoreGraphics.framework */; }; 12 | 7F32F9FC18E394FE00BF3FF4 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F32F9FB18E394FE00BF3FF4 /* UIKit.framework */; }; 13 | 7F32FA0218E394FE00BF3FF4 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 7F32FA0018E394FE00BF3FF4 /* InfoPlist.strings */; }; 14 | 7F32FA0418E394FE00BF3FF4 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F32FA0318E394FE00BF3FF4 /* main.m */; }; 15 | 7F32FA0818E394FE00BF3FF4 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F32FA0718E394FE00BF3FF4 /* AppDelegate.m */; }; 16 | 7F32FA0B18E394FE00BF3FF4 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7F32FA0918E394FE00BF3FF4 /* Main.storyboard */; }; 17 | 7F32FA0E18E394FE00BF3FF4 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F32FA0D18E394FE00BF3FF4 /* ViewController.m */; }; 18 | 7F32FA1018E394FE00BF3FF4 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7F32FA0F18E394FE00BF3FF4 /* Images.xcassets */; }; 19 | 7F32FA2E18E3957D00BF3FF4 /* SecondViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F32FA2D18E3957D00BF3FF4 /* SecondViewController.m */; }; 20 | 7F32FA3418E3973E00BF3FF4 /* DummyClass.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F32FA3318E3973E00BF3FF4 /* DummyClass.m */; }; 21 | 7F6B6DC618E6016300678510 /* INTUWeakForwarder.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F6B6DC518E6016300678510 /* INTUWeakForwarder.m */; }; 22 | /* End PBXBuildFile section */ 23 | 24 | /* Begin PBXFileReference section */ 25 | 7F32F9F418E394FE00BF3FF4 /* Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Example.app; sourceTree = BUILT_PRODUCTS_DIR; }; 26 | 7F32F9F718E394FE00BF3FF4 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 27 | 7F32F9F918E394FE00BF3FF4 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 28 | 7F32F9FB18E394FE00BF3FF4 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 29 | 7F32F9FF18E394FE00BF3FF4 /* Example-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Example-Info.plist"; sourceTree = ""; }; 30 | 7F32FA0118E394FE00BF3FF4 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 31 | 7F32FA0318E394FE00BF3FF4 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 32 | 7F32FA0518E394FE00BF3FF4 /* Example-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Example-Prefix.pch"; sourceTree = ""; }; 33 | 7F32FA0618E394FE00BF3FF4 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 34 | 7F32FA0718E394FE00BF3FF4 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 35 | 7F32FA0A18E394FE00BF3FF4 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 36 | 7F32FA0C18E394FE00BF3FF4 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 37 | 7F32FA0D18E394FE00BF3FF4 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 38 | 7F32FA0F18E394FE00BF3FF4 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 39 | 7F32FA1618E394FE00BF3FF4 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; 40 | 7F32FA2C18E3957D00BF3FF4 /* SecondViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecondViewController.h; sourceTree = ""; }; 41 | 7F32FA2D18E3957D00BF3FF4 /* SecondViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SecondViewController.m; sourceTree = ""; }; 42 | 7F32FA3218E3973E00BF3FF4 /* DummyClass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DummyClass.h; sourceTree = ""; }; 43 | 7F32FA3318E3973E00BF3FF4 /* DummyClass.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DummyClass.m; sourceTree = ""; }; 44 | 7F6B6DC418E6016300678510 /* INTUWeakForwarder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = INTUWeakForwarder.h; path = ../INTUWeakForwarder.h; sourceTree = ""; }; 45 | 7F6B6DC518E6016300678510 /* INTUWeakForwarder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = INTUWeakForwarder.m; path = ../INTUWeakForwarder.m; sourceTree = ""; }; 46 | /* End PBXFileReference section */ 47 | 48 | /* Begin PBXFrameworksBuildPhase section */ 49 | 7F32F9F118E394FE00BF3FF4 /* Frameworks */ = { 50 | isa = PBXFrameworksBuildPhase; 51 | buildActionMask = 2147483647; 52 | files = ( 53 | 7F32F9FA18E394FE00BF3FF4 /* CoreGraphics.framework in Frameworks */, 54 | 7F32F9FC18E394FE00BF3FF4 /* UIKit.framework in Frameworks */, 55 | 7F32F9F818E394FE00BF3FF4 /* Foundation.framework in Frameworks */, 56 | ); 57 | runOnlyForDeploymentPostprocessing = 0; 58 | }; 59 | /* End PBXFrameworksBuildPhase section */ 60 | 61 | /* Begin PBXGroup section */ 62 | 7F32F9EB18E394FE00BF3FF4 = { 63 | isa = PBXGroup; 64 | children = ( 65 | 7F6B6DC418E6016300678510 /* INTUWeakForwarder.h */, 66 | 7F6B6DC518E6016300678510 /* INTUWeakForwarder.m */, 67 | 7F32F9FD18E394FE00BF3FF4 /* Example */, 68 | 7F32F9F618E394FE00BF3FF4 /* Frameworks */, 69 | 7F32F9F518E394FE00BF3FF4 /* Products */, 70 | ); 71 | sourceTree = ""; 72 | }; 73 | 7F32F9F518E394FE00BF3FF4 /* Products */ = { 74 | isa = PBXGroup; 75 | children = ( 76 | 7F32F9F418E394FE00BF3FF4 /* Example.app */, 77 | ); 78 | name = Products; 79 | sourceTree = ""; 80 | }; 81 | 7F32F9F618E394FE00BF3FF4 /* Frameworks */ = { 82 | isa = PBXGroup; 83 | children = ( 84 | 7F32F9F718E394FE00BF3FF4 /* Foundation.framework */, 85 | 7F32F9F918E394FE00BF3FF4 /* CoreGraphics.framework */, 86 | 7F32F9FB18E394FE00BF3FF4 /* UIKit.framework */, 87 | 7F32FA1618E394FE00BF3FF4 /* XCTest.framework */, 88 | ); 89 | name = Frameworks; 90 | sourceTree = ""; 91 | }; 92 | 7F32F9FD18E394FE00BF3FF4 /* Example */ = { 93 | isa = PBXGroup; 94 | children = ( 95 | 7F32FA0618E394FE00BF3FF4 /* AppDelegate.h */, 96 | 7F32FA0718E394FE00BF3FF4 /* AppDelegate.m */, 97 | 7F32FA0918E394FE00BF3FF4 /* Main.storyboard */, 98 | 7F32FA0C18E394FE00BF3FF4 /* ViewController.h */, 99 | 7F32FA0D18E394FE00BF3FF4 /* ViewController.m */, 100 | 7F32FA2C18E3957D00BF3FF4 /* SecondViewController.h */, 101 | 7F32FA2D18E3957D00BF3FF4 /* SecondViewController.m */, 102 | 7F32FA3218E3973E00BF3FF4 /* DummyClass.h */, 103 | 7F32FA3318E3973E00BF3FF4 /* DummyClass.m */, 104 | 7F32FA0F18E394FE00BF3FF4 /* Images.xcassets */, 105 | 7F32F9FE18E394FE00BF3FF4 /* Supporting Files */, 106 | ); 107 | path = Example; 108 | sourceTree = ""; 109 | }; 110 | 7F32F9FE18E394FE00BF3FF4 /* Supporting Files */ = { 111 | isa = PBXGroup; 112 | children = ( 113 | 7F32F9FF18E394FE00BF3FF4 /* Example-Info.plist */, 114 | 7F32FA0018E394FE00BF3FF4 /* InfoPlist.strings */, 115 | 7F32FA0318E394FE00BF3FF4 /* main.m */, 116 | 7F32FA0518E394FE00BF3FF4 /* Example-Prefix.pch */, 117 | ); 118 | name = "Supporting Files"; 119 | sourceTree = ""; 120 | }; 121 | /* End PBXGroup section */ 122 | 123 | /* Begin PBXNativeTarget section */ 124 | 7F32F9F318E394FE00BF3FF4 /* Example */ = { 125 | isa = PBXNativeTarget; 126 | buildConfigurationList = 7F32FA2618E394FE00BF3FF4 /* Build configuration list for PBXNativeTarget "Example" */; 127 | buildPhases = ( 128 | 7F32F9F018E394FE00BF3FF4 /* Sources */, 129 | 7F32F9F118E394FE00BF3FF4 /* Frameworks */, 130 | 7F32F9F218E394FE00BF3FF4 /* Resources */, 131 | ); 132 | buildRules = ( 133 | ); 134 | dependencies = ( 135 | ); 136 | name = Example; 137 | productName = Example; 138 | productReference = 7F32F9F418E394FE00BF3FF4 /* Example.app */; 139 | productType = "com.apple.product-type.application"; 140 | }; 141 | /* End PBXNativeTarget section */ 142 | 143 | /* Begin PBXProject section */ 144 | 7F32F9EC18E394FE00BF3FF4 /* Project object */ = { 145 | isa = PBXProject; 146 | attributes = { 147 | LastUpgradeCheck = 0510; 148 | ORGANIZATIONNAME = Intuit; 149 | }; 150 | buildConfigurationList = 7F32F9EF18E394FE00BF3FF4 /* Build configuration list for PBXProject "Example" */; 151 | compatibilityVersion = "Xcode 3.2"; 152 | developmentRegion = English; 153 | hasScannedForEncodings = 0; 154 | knownRegions = ( 155 | en, 156 | Base, 157 | ); 158 | mainGroup = 7F32F9EB18E394FE00BF3FF4; 159 | productRefGroup = 7F32F9F518E394FE00BF3FF4 /* Products */; 160 | projectDirPath = ""; 161 | projectRoot = ""; 162 | targets = ( 163 | 7F32F9F318E394FE00BF3FF4 /* Example */, 164 | ); 165 | }; 166 | /* End PBXProject section */ 167 | 168 | /* Begin PBXResourcesBuildPhase section */ 169 | 7F32F9F218E394FE00BF3FF4 /* Resources */ = { 170 | isa = PBXResourcesBuildPhase; 171 | buildActionMask = 2147483647; 172 | files = ( 173 | 7F32FA1018E394FE00BF3FF4 /* Images.xcassets in Resources */, 174 | 7F32FA0218E394FE00BF3FF4 /* InfoPlist.strings in Resources */, 175 | 7F32FA0B18E394FE00BF3FF4 /* Main.storyboard in Resources */, 176 | ); 177 | runOnlyForDeploymentPostprocessing = 0; 178 | }; 179 | /* End PBXResourcesBuildPhase section */ 180 | 181 | /* Begin PBXSourcesBuildPhase section */ 182 | 7F32F9F018E394FE00BF3FF4 /* Sources */ = { 183 | isa = PBXSourcesBuildPhase; 184 | buildActionMask = 2147483647; 185 | files = ( 186 | 7F32FA2E18E3957D00BF3FF4 /* SecondViewController.m in Sources */, 187 | 7F32FA0E18E394FE00BF3FF4 /* ViewController.m in Sources */, 188 | 7F6B6DC618E6016300678510 /* INTUWeakForwarder.m in Sources */, 189 | 7F32FA0818E394FE00BF3FF4 /* AppDelegate.m in Sources */, 190 | 7F32FA3418E3973E00BF3FF4 /* DummyClass.m in Sources */, 191 | 7F32FA0418E394FE00BF3FF4 /* main.m in Sources */, 192 | ); 193 | runOnlyForDeploymentPostprocessing = 0; 194 | }; 195 | /* End PBXSourcesBuildPhase section */ 196 | 197 | /* Begin PBXVariantGroup section */ 198 | 7F32FA0018E394FE00BF3FF4 /* InfoPlist.strings */ = { 199 | isa = PBXVariantGroup; 200 | children = ( 201 | 7F32FA0118E394FE00BF3FF4 /* en */, 202 | ); 203 | name = InfoPlist.strings; 204 | sourceTree = ""; 205 | }; 206 | 7F32FA0918E394FE00BF3FF4 /* Main.storyboard */ = { 207 | isa = PBXVariantGroup; 208 | children = ( 209 | 7F32FA0A18E394FE00BF3FF4 /* Base */, 210 | ); 211 | name = Main.storyboard; 212 | sourceTree = ""; 213 | }; 214 | /* End PBXVariantGroup section */ 215 | 216 | /* Begin XCBuildConfiguration section */ 217 | 7F32FA2418E394FE00BF3FF4 /* Debug */ = { 218 | isa = XCBuildConfiguration; 219 | buildSettings = { 220 | ALWAYS_SEARCH_USER_PATHS = NO; 221 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 222 | CLANG_CXX_LIBRARY = "libc++"; 223 | CLANG_ENABLE_MODULES = YES; 224 | CLANG_ENABLE_OBJC_ARC = YES; 225 | CLANG_WARN_BOOL_CONVERSION = YES; 226 | CLANG_WARN_CONSTANT_CONVERSION = YES; 227 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 228 | CLANG_WARN_EMPTY_BODY = YES; 229 | CLANG_WARN_ENUM_CONVERSION = YES; 230 | CLANG_WARN_INT_CONVERSION = YES; 231 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 232 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 233 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 234 | COPY_PHASE_STRIP = NO; 235 | GCC_C_LANGUAGE_STANDARD = gnu99; 236 | GCC_DYNAMIC_NO_PIC = NO; 237 | GCC_OPTIMIZATION_LEVEL = 0; 238 | GCC_PREPROCESSOR_DEFINITIONS = ( 239 | "DEBUG=1", 240 | "$(inherited)", 241 | ); 242 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 243 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 244 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 245 | GCC_WARN_UNDECLARED_SELECTOR = YES; 246 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 247 | GCC_WARN_UNUSED_FUNCTION = YES; 248 | GCC_WARN_UNUSED_VARIABLE = YES; 249 | IPHONEOS_DEPLOYMENT_TARGET = 7.1; 250 | ONLY_ACTIVE_ARCH = YES; 251 | SDKROOT = iphoneos; 252 | }; 253 | name = Debug; 254 | }; 255 | 7F32FA2518E394FE00BF3FF4 /* 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__DUPLICATE_METHOD_MATCH = YES; 271 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 272 | COPY_PHASE_STRIP = YES; 273 | ENABLE_NS_ASSERTIONS = NO; 274 | GCC_C_LANGUAGE_STANDARD = gnu99; 275 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 276 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 277 | GCC_WARN_UNDECLARED_SELECTOR = YES; 278 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 279 | GCC_WARN_UNUSED_FUNCTION = YES; 280 | GCC_WARN_UNUSED_VARIABLE = YES; 281 | IPHONEOS_DEPLOYMENT_TARGET = 7.1; 282 | SDKROOT = iphoneos; 283 | VALIDATE_PRODUCT = YES; 284 | }; 285 | name = Release; 286 | }; 287 | 7F32FA2718E394FE00BF3FF4 /* Debug */ = { 288 | isa = XCBuildConfiguration; 289 | buildSettings = { 290 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 291 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 292 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 293 | GCC_PREFIX_HEADER = "Example/Example-Prefix.pch"; 294 | INFOPLIST_FILE = "Example/Example-Info.plist"; 295 | PRODUCT_NAME = "$(TARGET_NAME)"; 296 | WRAPPER_EXTENSION = app; 297 | }; 298 | name = Debug; 299 | }; 300 | 7F32FA2818E394FE00BF3FF4 /* Release */ = { 301 | isa = XCBuildConfiguration; 302 | buildSettings = { 303 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 304 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 305 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 306 | GCC_PREFIX_HEADER = "Example/Example-Prefix.pch"; 307 | INFOPLIST_FILE = "Example/Example-Info.plist"; 308 | PRODUCT_NAME = "$(TARGET_NAME)"; 309 | WRAPPER_EXTENSION = app; 310 | }; 311 | name = Release; 312 | }; 313 | /* End XCBuildConfiguration section */ 314 | 315 | /* Begin XCConfigurationList section */ 316 | 7F32F9EF18E394FE00BF3FF4 /* Build configuration list for PBXProject "Example" */ = { 317 | isa = XCConfigurationList; 318 | buildConfigurations = ( 319 | 7F32FA2418E394FE00BF3FF4 /* Debug */, 320 | 7F32FA2518E394FE00BF3FF4 /* Release */, 321 | ); 322 | defaultConfigurationIsVisible = 0; 323 | defaultConfigurationName = Release; 324 | }; 325 | 7F32FA2618E394FE00BF3FF4 /* Build configuration list for PBXNativeTarget "Example" */ = { 326 | isa = XCConfigurationList; 327 | buildConfigurations = ( 328 | 7F32FA2718E394FE00BF3FF4 /* Debug */, 329 | 7F32FA2818E394FE00BF3FF4 /* Release */, 330 | ); 331 | defaultConfigurationIsVisible = 0; 332 | defaultConfigurationName = Release; 333 | }; 334 | /* End XCConfigurationList section */ 335 | }; 336 | rootObject = 7F32F9EC18E394FE00BF3FF4 /* Project object */; 337 | } 338 | -------------------------------------------------------------------------------- /Example/Example/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // Example 4 | // 5 | // Created by Jeff Shulman on 3/26/14. 6 | // Copyright (c) 2014 Intuit Inc 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining 9 | // a copy of this software and associated documentation files (the 10 | // "Software"), to deal in the Software without restriction, including 11 | // without limitation the rights to use, copy, modify, merge, publish, 12 | // distribute, sublicense, and/or sell copies of the Software, and to 13 | // permit persons to whom the Software is furnished to do so, subject to 14 | // the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be 17 | // included in all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 23 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 24 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 25 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 | 27 | #import 28 | 29 | @interface AppDelegate : UIResponder 30 | 31 | @property (strong, nonatomic) UIWindow *window; 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /Example/Example/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // Example 4 | // 5 | // Created by Jeff Shulman on 3/26/14. 6 | // Copyright (c) 2014 Intuit Inc 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining 9 | // a copy of this software and associated documentation files (the 10 | // "Software"), to deal in the Software without restriction, including 11 | // without limitation the rights to use, copy, modify, merge, publish, 12 | // distribute, sublicense, and/or sell copies of the Software, and to 13 | // permit persons to whom the Software is furnished to do so, subject to 14 | // the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be 17 | // included in all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 23 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 24 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 25 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 | 27 | #import "AppDelegate.h" 28 | 29 | @implementation AppDelegate 30 | 31 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 32 | { 33 | // Override point for customization after application launch. 34 | return YES; 35 | } 36 | 37 | - (void)applicationWillResignActive:(UIApplication *)application 38 | { 39 | // 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. 40 | // 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. 41 | } 42 | 43 | - (void)applicationDidEnterBackground:(UIApplication *)application 44 | { 45 | // 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. 46 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 47 | } 48 | 49 | - (void)applicationWillEnterForeground:(UIApplication *)application 50 | { 51 | // 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. 52 | } 53 | 54 | - (void)applicationDidBecomeActive:(UIApplication *)application 55 | { 56 | // 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. 57 | } 58 | 59 | - (void)applicationWillTerminate:(UIApplication *)application 60 | { 61 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 62 | } 63 | 64 | @end 65 | -------------------------------------------------------------------------------- /Example/Example/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /Example/Example/DummyClass.h: -------------------------------------------------------------------------------- 1 | // 2 | // DummyClass.h 3 | // Example 4 | // 5 | // Created by Jeff Shulman on 3/26/14. 6 | // Copyright (c) 2014 Intuit Inc 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining 9 | // a copy of this software and associated documentation files (the 10 | // "Software"), to deal in the Software without restriction, including 11 | // without limitation the rights to use, copy, modify, merge, publish, 12 | // distribute, sublicense, and/or sell copies of the Software, and to 13 | // permit persons to whom the Software is furnished to do so, subject to 14 | // the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be 17 | // included in all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 23 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 24 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 25 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 | // 27 | // This is a dummy class whose delegate declared unsafe_unretained like most of the iOS 28 | // SDK framework classes. 29 | 30 | #import 31 | 32 | @protocol DummyClassDelegate 33 | 34 | -(void)logMessage:(NSString*)msg; 35 | 36 | @end 37 | 38 | @interface DummyClass : NSObject 39 | 40 | @property (nonatomic, unsafe_unretained) id delegate; 41 | 42 | -(void)doLogMessage:(NSString*)msg; 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /Example/Example/DummyClass.m: -------------------------------------------------------------------------------- 1 | // 2 | // DummyClass.m 3 | // Example 4 | // 5 | // Created by Jeff Shulman on 3/26/14. 6 | // Copyright (c) 2014 Intuit Inc 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining 9 | // a copy of this software and associated documentation files (the 10 | // "Software"), to deal in the Software without restriction, including 11 | // without limitation the rights to use, copy, modify, merge, publish, 12 | // distribute, sublicense, and/or sell copies of the Software, and to 13 | // permit persons to whom the Software is furnished to do so, subject to 14 | // the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be 17 | // included in all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 23 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 24 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 25 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 | 27 | #import "DummyClass.h" 28 | 29 | @implementation DummyClass 30 | 31 | -(void)doLogMessage:(NSString*)msg 32 | { 33 | NSLog(@"doLogMessage: Calling delegate logMessage"); 34 | [self.delegate logMessage:msg]; 35 | } 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /Example/Example/Example-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | com.intuit.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Example/Example/Example-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #import 8 | 9 | #ifndef __IPHONE_5_0 10 | #warning "This project uses features only available in iOS SDK 5.0 and later." 11 | #endif 12 | 13 | #ifdef __OBJC__ 14 | #import 15 | #import 16 | #endif 17 | -------------------------------------------------------------------------------- /Example/Example/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "40x40", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "60x60", 16 | "scale" : "2x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /Example/Example/Images.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "orientation" : "portrait", 5 | "idiom" : "iphone", 6 | "extent" : "full-screen", 7 | "minimum-system-version" : "7.0", 8 | "scale" : "2x" 9 | }, 10 | { 11 | "orientation" : "portrait", 12 | "idiom" : "iphone", 13 | "subtype" : "retina4", 14 | "extent" : "full-screen", 15 | "minimum-system-version" : "7.0", 16 | "scale" : "2x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /Example/Example/SecondViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // SecondViewController.h 3 | // Example 4 | // 5 | // Created by Jeff Shulman on 3/26/14. 6 | // Copyright (c) 2014 Intuit Inc 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining 9 | // a copy of this software and associated documentation files (the 10 | // "Software"), to deal in the Software without restriction, including 11 | // without limitation the rights to use, copy, modify, merge, publish, 12 | // distribute, sublicense, and/or sell copies of the Software, and to 13 | // permit persons to whom the Software is furnished to do so, subject to 14 | // the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be 17 | // included in all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 23 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 24 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 25 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 | 27 | #import 28 | #import "DummyClass.h" 29 | 30 | @interface SecondViewController : UIViewController 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /Example/Example/SecondViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // SecondViewController.m 3 | // Example 4 | // 5 | // Created by Jeff Shulman on 3/26/14. 6 | // Copyright (c) 2014 Intuit Inc 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining 9 | // a copy of this software and associated documentation files (the 10 | // "Software"), to deal in the Software without restriction, including 11 | // without limitation the rights to use, copy, modify, merge, publish, 12 | // distribute, sublicense, and/or sell copies of the Software, and to 13 | // permit persons to whom the Software is furnished to do so, subject to 14 | // the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be 17 | // included in all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 23 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 24 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 25 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 | 27 | #import "SecondViewController.h" 28 | 29 | @implementation SecondViewController 30 | 31 | #pragma mark - Lifecycle 32 | 33 | // We'll just log when we've been dealloc'ed 34 | -(void)dealloc 35 | { 36 | NSLog(@"SecondViewController dealloc"); 37 | } 38 | 39 | #pragma mark - DummyClassDelegate 40 | 41 | -(void)logMessage:(NSString *)msg 42 | { 43 | NSLog(@"logMessage: %@", msg); 44 | } 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /Example/Example/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // Example 4 | // 5 | // Created by Jeff Shulman on 3/26/14. 6 | // Copyright (c) 2014 Intuit Inc 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining 9 | // a copy of this software and associated documentation files (the 10 | // "Software"), to deal in the Software without restriction, including 11 | // without limitation the rights to use, copy, modify, merge, publish, 12 | // distribute, sublicense, and/or sell copies of the Software, and to 13 | // permit persons to whom the Software is furnished to do so, subject to 14 | // the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be 17 | // included in all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 23 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 24 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 25 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 | 27 | #import 28 | 29 | @interface ViewController : UIViewController 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /Example/Example/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // Example 4 | // 5 | // Created by Jeff Shulman on 3/26/14. 6 | // Copyright (c) 2014 Intuit Inc 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining 9 | // a copy of this software and associated documentation files (the 10 | // "Software"), to deal in the Software without restriction, including 11 | // without limitation the rights to use, copy, modify, merge, publish, 12 | // distribute, sublicense, and/or sell copies of the Software, and to 13 | // permit persons to whom the Software is furnished to do so, subject to 14 | // the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be 17 | // included in all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 23 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 24 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 25 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 | 27 | #import "INTUWeakForwarder.h" 28 | #import "ViewController.h" 29 | #import "SecondViewController.h" 30 | 31 | @interface ViewController () 32 | 33 | @property (nonatomic, strong) DummyClass* dummy; 34 | 35 | @end 36 | 37 | @implementation ViewController 38 | 39 | -(instancetype)initWithCoder:(NSCoder *)aDecoder 40 | { 41 | self = [super initWithCoder:aDecoder]; 42 | if ( self ) { 43 | _dummy = [[DummyClass alloc] init]; 44 | } 45 | 46 | return self; 47 | } 48 | 49 | -(void)viewDidAppear:(BOOL)animated 50 | { 51 | [super viewDidAppear:animated]; 52 | 53 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 54 | NSLog(@"After viewDidAppear"); 55 | 56 | // Note after we pop back to this view controller the system will have dealloc'ed the 57 | // second view controller leaving our unsuspecting dummy class with a deallocated 58 | // delegate but not a nil reference since it was unsafe_unretained. 59 | // 60 | // So without using INTUWeakForwarder this next line would cause a crash. 61 | [self.dummy doLogMessage:@"viewDidAppear"]; 62 | }); 63 | } 64 | 65 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender 66 | { 67 | SecondViewController* vc = [segue destinationViewController]; 68 | 69 | // Instead of setting dummy's delegate directly to vc (the second view controller) we will set it to 70 | // the weak forwarder which will create a NSProxy object that will stick around as long as "dummy" 71 | // does but will automatically, due to a true weak reference, nil out the forwarded to object (vc here.) 72 | self.dummy.delegate = [INTUWeakForwarder forwardTo:vc associatedWith:self.dummy]; 73 | 74 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 75 | NSLog(@"After prepareForSegue"); 76 | [self.dummy doLogMessage:@"from prepareForSegue"]; 77 | }); 78 | } 79 | 80 | @end 81 | -------------------------------------------------------------------------------- /Example/Example/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Example/Example/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // Example 4 | // 5 | // Created by Jeff Shulman on 3/26/14. 6 | // Copyright (c) 2014 Intuit. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "AppDelegate.h" 12 | 13 | int main(int argc, char * argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /INTUWeakForwarder.h: -------------------------------------------------------------------------------- 1 | // 2 | // INTUWeakForwarder.h 3 | // 4 | // Created by Jeff Shulman and Dan Rowley on 3/14/14. 5 | // Copyright (c) 2014 Intuit Inc 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining 8 | // a copy of this software and associated documentation files (the 9 | // "Software"), to deal in the Software without restriction, including 10 | // without limitation the rights to use, copy, modify, merge, publish, 11 | // distribute, sublicense, and/or sell copies of the Software, and to 12 | // permit persons to whom the Software is furnished to do so, subject to 13 | // the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be 16 | // included in all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 22 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 24 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | // 26 | // "weak" references are great to use for delegate properties since they will automatically 27 | // get nil'ed out when the delegate object goes away. Alas it turns out Apple doesn't use 28 | // real weak references in its SDK but has all delegate properties as unsafe-unretained. 29 | // 30 | // This means the app will crash should the programmer forget to nil out all the delegate 31 | // properties on dealloc and that delegate is called. 32 | // 33 | // So what this little NSProxy class does is store the delegate as a *real* weak reference 34 | // and forwards all method invocations to it as long as it exists. When the delegate is 35 | // dealloc'ed the real weak reference will be nil and nothing will be forwarded along. 36 | // 37 | // The NSProxy instance is stored using an associated object on the delegatee so when that goes 38 | // away the proxy instance will too. So generally this should be the object you are setting 39 | // the delegate property of. 40 | // 41 | // Instead of writing: 42 | // 43 | // .delegate = self; 44 | // 45 | // you write: 46 | // 47 | // .delegate = [INTUWeakForwarder forwardTo:self associatedWith:]; 48 | // 49 | // E.g.: 50 | // 51 | // UIScrollView *scrollView = ...; 52 | // scrollView.delegate = [INTUWeakForwarder forwardTo:self associatedWith:scrollView]; 53 | 54 | #import 55 | 56 | @interface INTUWeakForwarder : NSProxy 57 | 58 | /// Factory for NSProxy forwarding object 59 | /// 60 | /// @param theRealDelegate The delegate instance object 61 | /// @param object The object to tie the lifetime of the proxy object to 62 | /// @return The proxy object to assign as the delegate object 63 | 64 | +(id)forwardTo:(id)theRealDelegate associatedWith:(id)object; 65 | 66 | @end 67 | -------------------------------------------------------------------------------- /INTUWeakForwarder.m: -------------------------------------------------------------------------------- 1 | // 2 | // INTUWeakForwarder.m 3 | // 4 | // Created by Jeff Shulman and Dan Rowley on 3/14/14. 5 | // Copyright (c) 2014 Intuit Inc 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining 8 | // a copy of this software and associated documentation files (the 9 | // "Software"), to deal in the Software without restriction, including 10 | // without limitation the rights to use, copy, modify, merge, publish, 11 | // distribute, sublicense, and/or sell copies of the Software, and to 12 | // permit persons to whom the Software is furnished to do so, subject to 13 | // the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be 16 | // included in all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 22 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 24 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | 26 | #import "INTUWeakForwarder.h" 27 | #import 28 | 29 | @interface INTUWeakForwarder () 30 | 31 | /// Save the "real" delegates Class to return the proper signature for it when the reference is nil. 32 | @property (nonatomic, strong) Class realDelegateClass; 33 | 34 | /// Contains the weak reference to the delegate which is what will nil out when the delegate is dealloc'ed 35 | @property (nonatomic, weak) id realDelegate; 36 | 37 | @end 38 | 39 | @implementation INTUWeakForwarder 40 | 41 | +(id)forwardTo:(id)theRealDelegate associatedWith:(id)object 42 | { 43 | NSAssert(theRealDelegate, @"Trying to forward to a nil object"); 44 | NSAssert(object, @"Trying associate forwarder to a nil object"); 45 | 46 | // Create the NSProxy subclass to do the forwarding 47 | INTUWeakForwarder* forwarder = [INTUWeakForwarder alloc]; 48 | forwarder.realDelegate = theRealDelegate; 49 | forwarder.realDelegateClass = [theRealDelegate class]; 50 | 51 | // We need to keep this proxy object around for the lifetime of the associated object. 52 | // To do this we associate the proxy with the object using the address of the created proxy 53 | // object as the unique key here. When object goes away so will the forwarder. 54 | objc_setAssociatedObject(object, (__bridge const void *)(forwarder), forwarder, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 55 | 56 | return forwarder; 57 | } 58 | 59 | - (void)forwardInvocation:(NSInvocation *)anInvocation 60 | { 61 | // If we still have the real delegate around then forward it on, otherwise drop it. 62 | if ( self.realDelegate ) { 63 | [anInvocation setTarget:self.realDelegate]; 64 | [anInvocation invoke]; 65 | } 66 | } 67 | 68 | -(NSMethodSignature*)methodSignatureForSelector:(SEL)sel 69 | { 70 | if ( self.realDelegate ) { 71 | // We still have the delegate so have it return the selector signature 72 | return [self.realDelegate methodSignatureForSelector:sel]; 73 | } 74 | else { 75 | // Delegate has been dealloc'ed. Return the signature using the class so we don't throw an exception 76 | return [self.realDelegateClass instanceMethodSignatureForSelector:sel]; 77 | } 78 | } 79 | 80 | @end 81 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Intuit Inc 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | INTUWeakForwarder 2 | ================ 3 | 4 | "weak" references are great to use for delegate properties since they will automatically 5 | get nil'ed out when the delegate object goes away. Alas it turns out Apple doesn't use 6 | real weak references in its SDK but has all delegate properties as unsafe-unretained. 7 | 8 | This means the app will crash should the programmer forget to nil out all the delegate 9 | properties on dealloc and that delegate is called. 10 | 11 | So what this little NSProxy class does is store the delegate as a *real* weak reference 12 | and forwards all method invocations to it as long as it exists. When the delegate is 13 | dealloc'ed the real weak reference will be nil and nothing will be forwarded along. 14 | 15 | The NSProxy instance is stored using an associated object on the delegatee so when that goes 16 | away the proxy instance will too. So generally this should be the object you are setting 17 | the delegate property of. 18 | 19 | Instead of writing: 20 | 21 | .delegate = self; 22 | 23 | you write: 24 | 25 | .delegate = [INTUWeakForwarder forwardTo:self associatedWith:]; 26 | 27 | E.g.: 28 | 29 | UIScrollView *scrollView = ...; 30 | scrollView.delegate = [INTUWeakForwarder forwardTo:self associatedWith:scrollView]; 31 | --------------------------------------------------------------------------------