├── .gitignore ├── LICENSE ├── PLWeakCompatibility-iOS-TestRunner ├── PLAppDelegate.h ├── PLAppDelegate.m ├── PLWeakCompatibility-iOS-TestRunner-Info.plist ├── PLWeakCompatibility-iOS-TestRunner-Prefix.pch ├── en.lproj │ └── InfoPlist.strings └── main.m ├── PLWeakCompatibility-iOS-Tests ├── PLWeakCompatibility-iOS-TestRunnerTests-Info.plist └── en.lproj │ └── InfoPlist.strings ├── PLWeakCompatibility.xcodeproj └── project.pbxproj ├── PLWeakCompatibility ├── MAZeroingWeakRef.h ├── MAZeroingWeakRef.m ├── MAZeroingWeakRefNativeZWRNotAllowedTable.h ├── PLWeakCompatibility-Info.plist ├── PLWeakCompatibility-Prefix.pch ├── PLWeakCompatibilityStubs.h ├── PLWeakCompatibilityStubs.m ├── en.lproj │ └── InfoPlist.strings └── main.m ├── PLWeakCompatibilityTests ├── PLWeakCompatibilityTests-Info.plist ├── PLWeakCompatibilityTests.h ├── PLWeakCompatibilityTests.m └── en.lproj │ └── InfoPlist.strings └── README.markdown /.gitignore: -------------------------------------------------------------------------------- 1 | *.xcworkspace 2 | xcuserdata 3 | build 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Plausible Labs Cooperative, Inc. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 1. Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | 3. Neither the name of the copyright holders nor the names of any 13 | contributors may be used to endorse or promote products derived 14 | from this software without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 20 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /PLWeakCompatibility-iOS-TestRunner/PLAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // PLAppDelegate.h 3 | // PLWeakCompatibility-iOS-TestRunner 4 | // 5 | // Created by Landon Fuller on 3/30/12. 6 | // Copyright (c) 2012 Plausible Labs Cooperative, Inc. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface PLAppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /PLWeakCompatibility-iOS-TestRunner/PLAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // PLAppDelegate.m 3 | // PLWeakCompatibility-iOS-TestRunner 4 | // 5 | // Created by Landon Fuller on 3/30/12. 6 | // Copyright (c) 2012 Plausible Labs Cooperative, Inc. All rights reserved. 7 | // 8 | 9 | #import "PLAppDelegate.h" 10 | 11 | @implementation PLAppDelegate 12 | 13 | @synthesize window = _window; 14 | 15 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 16 | { 17 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 18 | // Override point for customization after application launch. 19 | self.window.backgroundColor = [UIColor whiteColor]; 20 | [self.window makeKeyAndVisible]; 21 | return YES; 22 | } 23 | 24 | - (void)applicationWillResignActive:(UIApplication *)application 25 | { 26 | // 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. 27 | // 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. 28 | } 29 | 30 | - (void)applicationDidEnterBackground:(UIApplication *)application 31 | { 32 | // 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. 33 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 34 | } 35 | 36 | - (void)applicationWillEnterForeground:(UIApplication *)application 37 | { 38 | // 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. 39 | } 40 | 41 | - (void)applicationDidBecomeActive:(UIApplication *)application 42 | { 43 | // 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. 44 | } 45 | 46 | - (void)applicationWillTerminate:(UIApplication *)application 47 | { 48 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 49 | } 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /PLWeakCompatibility-iOS-TestRunner/PLWeakCompatibility-iOS-TestRunner-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | coop.plausible.${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 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /PLWeakCompatibility-iOS-TestRunner/PLWeakCompatibility-iOS-TestRunner-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'PLWeakCompatibility-iOS-TestRunner' target in the 'PLWeakCompatibility-iOS-TestRunner' project 3 | // 4 | 5 | #import 6 | 7 | #ifndef __IPHONE_3_0 8 | #warning "This project uses features only available in iOS SDK 3.0 and later." 9 | #endif 10 | 11 | #ifdef __OBJC__ 12 | #import 13 | #import 14 | #endif 15 | -------------------------------------------------------------------------------- /PLWeakCompatibility-iOS-TestRunner/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /PLWeakCompatibility-iOS-TestRunner/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // PLWeakCompatibility-iOS-TestRunner 4 | // 5 | // Created by Landon Fuller on 3/30/12. 6 | // Copyright (c) 2012 Plausible Labs Cooperative, Inc. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "PLAppDelegate.h" 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([PLAppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /PLWeakCompatibility-iOS-Tests/PLWeakCompatibility-iOS-TestRunnerTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | coop.plausible.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /PLWeakCompatibility-iOS-Tests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /PLWeakCompatibility.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 0501743F15265D2B001DFA82 /* MAZeroingWeakRef.m in Sources */ = {isa = PBXBuildFile; fileRef = C2CB835F1523D91500E8AC00 /* MAZeroingWeakRef.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 11 | 05286A981524D85F00FD0AD7 /* PLWeakCompatibilityStubs.m in Sources */ = {isa = PBXBuildFile; fileRef = C2CB835F1523D91500E8ABFC /* PLWeakCompatibilityStubs.m */; }; 12 | 053887C71523F6F700CDC1DF /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C2CB83311523D8F300E8ABFC /* Foundation.framework */; }; 13 | 053888261523F7A500CDC1DF /* PLWeakCompatibilityStubs.m in Sources */ = {isa = PBXBuildFile; fileRef = C2CB835F1523D91500E8ABFC /* PLWeakCompatibilityStubs.m */; }; 14 | 053888271523F7A900CDC1DF /* PLWeakCompatibilityStubs.m in Sources */ = {isa = PBXBuildFile; fileRef = C2CB835F1523D91500E8ABFC /* PLWeakCompatibilityStubs.m */; }; 15 | 053888771523FFC700CDC1DF /* PLWeakCompatibilityStubs.h in Headers */ = {isa = PBXBuildFile; fileRef = C2CB835E1523D91500E8ABFC /* PLWeakCompatibilityStubs.h */; settings = {ATTRIBUTES = (Public, ); }; }; 16 | 053888811524028F00CDC1DF /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C2CB83311523D8F300E8ABFC /* Foundation.framework */; }; 17 | 0573A94F1526484200D0D884 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0573A94E1526484200D0D884 /* UIKit.framework */; }; 18 | 0573A9501526484200D0D884 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C2CB83311523D8F300E8ABFC /* Foundation.framework */; }; 19 | 0573A9521526484200D0D884 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0573A9511526484200D0D884 /* CoreGraphics.framework */; }; 20 | 0573A9581526484200D0D884 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 0573A9561526484200D0D884 /* InfoPlist.strings */; }; 21 | 0573A95A1526484200D0D884 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 0573A9591526484200D0D884 /* main.m */; }; 22 | 0573A95E1526484200D0D884 /* PLAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 0573A95D1526484200D0D884 /* PLAppDelegate.m */; }; 23 | 0573A9651526484200D0D884 /* SenTestingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C2CB83471523D8F300E8ABFC /* SenTestingKit.framework */; }; 24 | 0573A9661526484200D0D884 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0573A94E1526484200D0D884 /* UIKit.framework */; }; 25 | 0573A9671526484200D0D884 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C2CB83311523D8F300E8ABFC /* Foundation.framework */; }; 26 | 0573A96F1526484200D0D884 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 0573A96D1526484200D0D884 /* InfoPlist.strings */; }; 27 | 0573A97B1526485600D0D884 /* libPLWeakCompatibility-iOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 053887C61523F6F700CDC1DF /* libPLWeakCompatibility-iOS.a */; }; 28 | 0573A97C1526486A00D0D884 /* PLWeakCompatibilityTests.m in Sources */ = {isa = PBXBuildFile; fileRef = C2CB83541523D8F400E8ABFC /* PLWeakCompatibilityTests.m */; }; 29 | C26653231524DA8B0076E2EA /* PLWeakCompatibility.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 053887991523F6CD00CDC1DF /* PLWeakCompatibility.framework */; }; 30 | C2CB83481523D8F300E8ABFC /* SenTestingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C2CB83471523D8F300E8ABFC /* SenTestingKit.framework */; }; 31 | C2CB834A1523D8F300E8ABFC /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C2CB83311523D8F300E8ABFC /* Foundation.framework */; }; 32 | C2CB83521523D8F400E8ABFC /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = C2CB83501523D8F400E8ABFC /* InfoPlist.strings */; }; 33 | C2CB83551523D8F400E8ABFC /* PLWeakCompatibilityTests.m in Sources */ = {isa = PBXBuildFile; fileRef = C2CB83541523D8F400E8ABFC /* PLWeakCompatibilityTests.m */; }; 34 | C2CB835F1523D91500E8ABFE /* MAZeroingWeakRef.h in Headers */ = {isa = PBXBuildFile; fileRef = C2CB835F1523D91500E8ABFD /* MAZeroingWeakRef.h */; }; 35 | C2CB835F1523D91500E8ABFF /* MAZeroingWeakRef.h in Headers */ = {isa = PBXBuildFile; fileRef = C2CB835F1523D91500E8ABFD /* MAZeroingWeakRef.h */; }; 36 | C2CB835F1523D91500E8AC03 /* MAZeroingWeakRef.m in Sources */ = {isa = PBXBuildFile; fileRef = C2CB835F1523D91500E8AC00 /* MAZeroingWeakRef.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 37 | /* End PBXBuildFile section */ 38 | 39 | /* Begin PBXContainerItemProxy section */ 40 | 0573A9681526484200D0D884 /* PBXContainerItemProxy */ = { 41 | isa = PBXContainerItemProxy; 42 | containerPortal = C2CB83221523D8F300E8ABFC /* Project object */; 43 | proxyType = 1; 44 | remoteGlobalIDString = 0573A94B1526484200D0D884; 45 | remoteInfo = "PLWeakCompatibility-iOS-TestRunner"; 46 | }; 47 | 0573A9791526485000D0D884 /* PBXContainerItemProxy */ = { 48 | isa = PBXContainerItemProxy; 49 | containerPortal = C2CB83221523D8F300E8ABFC /* Project object */; 50 | proxyType = 1; 51 | remoteGlobalIDString = 053887C51523F6F700CDC1DF; 52 | remoteInfo = "PLWeakCompatibility-iOS"; 53 | }; 54 | 0573A97D152648DE00D0D884 /* PBXContainerItemProxy */ = { 55 | isa = PBXContainerItemProxy; 56 | containerPortal = C2CB83221523D8F300E8ABFC /* Project object */; 57 | proxyType = 1; 58 | remoteGlobalIDString = 053887C51523F6F700CDC1DF; 59 | remoteInfo = "PLWeakCompatibility-iOS"; 60 | }; 61 | /* End PBXContainerItemProxy section */ 62 | 63 | /* Begin PBXCopyFilesBuildPhase section */ 64 | 0538887D1524025B00CDC1DF /* Copy Frameworks */ = { 65 | isa = PBXCopyFilesBuildPhase; 66 | buildActionMask = 2147483647; 67 | dstPath = ""; 68 | dstSubfolderSpec = 10; 69 | files = ( 70 | ); 71 | name = "Copy Frameworks"; 72 | runOnlyForDeploymentPostprocessing = 0; 73 | }; 74 | /* End PBXCopyFilesBuildPhase section */ 75 | 76 | /* Begin PBXFileReference section */ 77 | 053887991523F6CD00CDC1DF /* PLWeakCompatibility.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = PLWeakCompatibility.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 78 | 0538879D1523F6CD00CDC1DF /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; 79 | 0538879E1523F6CD00CDC1DF /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; 80 | 0538879F1523F6CD00CDC1DF /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 81 | 053887C61523F6F700CDC1DF /* libPLWeakCompatibility-iOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPLWeakCompatibility-iOS.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 82 | 053888281523F7EA00CDC1DF /* PLWeakCompatibility-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "PLWeakCompatibility-Info.plist"; sourceTree = ""; }; 83 | 0573A94C1526484200D0D884 /* PLWeakCompatibility-iOS-TestRunner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "PLWeakCompatibility-iOS-TestRunner.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 84 | 0573A94E1526484200D0D884 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; }; 85 | 0573A9511526484200D0D884 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = Library/Frameworks/CoreGraphics.framework; sourceTree = DEVELOPER_DIR; }; 86 | 0573A9551526484200D0D884 /* PLWeakCompatibility-iOS-TestRunner-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "PLWeakCompatibility-iOS-TestRunner-Info.plist"; sourceTree = ""; }; 87 | 0573A9571526484200D0D884 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 88 | 0573A9591526484200D0D884 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 89 | 0573A95B1526484200D0D884 /* PLWeakCompatibility-iOS-TestRunner-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "PLWeakCompatibility-iOS-TestRunner-Prefix.pch"; sourceTree = ""; }; 90 | 0573A95C1526484200D0D884 /* PLAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PLAppDelegate.h; sourceTree = ""; }; 91 | 0573A95D1526484200D0D884 /* PLAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PLAppDelegate.m; sourceTree = ""; }; 92 | 0573A9641526484200D0D884 /* PLWeakCompatibility-iOS-Tests.octest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "PLWeakCompatibility-iOS-Tests.octest"; sourceTree = BUILT_PRODUCTS_DIR; }; 93 | 0573A96C1526484200D0D884 /* PLWeakCompatibility-iOS-TestRunnerTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "PLWeakCompatibility-iOS-TestRunnerTests-Info.plist"; sourceTree = ""; }; 94 | 0573A96E1526484200D0D884 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 95 | C212358A15263C410082CE88 /* README.markdown */ = {isa = PBXFileReference; lastKnownFileType = text; path = README.markdown; sourceTree = ""; }; 96 | C2123595152647A50082CE88 /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE; sourceTree = ""; }; 97 | C2CB83311523D8F300E8ABFC /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 98 | C2CB83391523D8F300E8ABFC /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 99 | C2CB833B1523D8F300E8ABFC /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 100 | C2CB833D1523D8F300E8ABFC /* PLWeakCompatibility-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "PLWeakCompatibility-Prefix.pch"; sourceTree = ""; }; 101 | C2CB83461523D8F300E8ABFC /* PLWeakCompatibility-MacOSX-Tests.octest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "PLWeakCompatibility-MacOSX-Tests.octest"; sourceTree = BUILT_PRODUCTS_DIR; }; 102 | C2CB83471523D8F300E8ABFC /* SenTestingKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SenTestingKit.framework; path = Library/Frameworks/SenTestingKit.framework; sourceTree = DEVELOPER_DIR; }; 103 | C2CB834F1523D8F400E8ABFC /* PLWeakCompatibilityTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "PLWeakCompatibilityTests-Info.plist"; sourceTree = ""; }; 104 | C2CB83511523D8F400E8ABFC /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 105 | C2CB83531523D8F400E8ABFC /* PLWeakCompatibilityTests.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PLWeakCompatibilityTests.h; sourceTree = ""; }; 106 | C2CB83541523D8F400E8ABFC /* PLWeakCompatibilityTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PLWeakCompatibilityTests.m; sourceTree = ""; }; 107 | C2CB835E1523D91500E8ABFC /* PLWeakCompatibilityStubs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PLWeakCompatibilityStubs.h; sourceTree = ""; }; 108 | C2CB835F1523D91500E8ABFC /* PLWeakCompatibilityStubs.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PLWeakCompatibilityStubs.m; sourceTree = ""; }; 109 | C2CB835F1523D91500E8ABFD /* MAZeroingWeakRef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MAZeroingWeakRef.h; sourceTree = ""; }; 110 | C2CB835F1523D91500E8AC00 /* MAZeroingWeakRef.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MAZeroingWeakRef.m; sourceTree = ""; }; 111 | C2CB835F1523D91500E8AC05 /* MAZeroingWeakRefNativeZWRNotAllowedTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MAZeroingWeakRefNativeZWRNotAllowedTable.h; sourceTree = ""; }; 112 | /* End PBXFileReference section */ 113 | 114 | /* Begin PBXFrameworksBuildPhase section */ 115 | 053887951523F6CD00CDC1DF /* Frameworks */ = { 116 | isa = PBXFrameworksBuildPhase; 117 | buildActionMask = 2147483647; 118 | files = ( 119 | 053888811524028F00CDC1DF /* Foundation.framework in Frameworks */, 120 | ); 121 | runOnlyForDeploymentPostprocessing = 0; 122 | }; 123 | 053887C31523F6F700CDC1DF /* Frameworks */ = { 124 | isa = PBXFrameworksBuildPhase; 125 | buildActionMask = 2147483647; 126 | files = ( 127 | 053887C71523F6F700CDC1DF /* Foundation.framework in Frameworks */, 128 | ); 129 | runOnlyForDeploymentPostprocessing = 0; 130 | }; 131 | 0573A9491526484200D0D884 /* Frameworks */ = { 132 | isa = PBXFrameworksBuildPhase; 133 | buildActionMask = 2147483647; 134 | files = ( 135 | 0573A94F1526484200D0D884 /* UIKit.framework in Frameworks */, 136 | 0573A9501526484200D0D884 /* Foundation.framework in Frameworks */, 137 | 0573A9521526484200D0D884 /* CoreGraphics.framework in Frameworks */, 138 | 0573A97B1526485600D0D884 /* libPLWeakCompatibility-iOS.a in Frameworks */, 139 | ); 140 | runOnlyForDeploymentPostprocessing = 0; 141 | }; 142 | 0573A9601526484200D0D884 /* Frameworks */ = { 143 | isa = PBXFrameworksBuildPhase; 144 | buildActionMask = 2147483647; 145 | files = ( 146 | 0573A9651526484200D0D884 /* SenTestingKit.framework in Frameworks */, 147 | 0573A9661526484200D0D884 /* UIKit.framework in Frameworks */, 148 | 0573A9671526484200D0D884 /* Foundation.framework in Frameworks */, 149 | ); 150 | runOnlyForDeploymentPostprocessing = 0; 151 | }; 152 | C2CB83421523D8F300E8ABFC /* Frameworks */ = { 153 | isa = PBXFrameworksBuildPhase; 154 | buildActionMask = 2147483647; 155 | files = ( 156 | C2CB83481523D8F300E8ABFC /* SenTestingKit.framework in Frameworks */, 157 | C2CB834A1523D8F300E8ABFC /* Foundation.framework in Frameworks */, 158 | C26653231524DA8B0076E2EA /* PLWeakCompatibility.framework in Frameworks */, 159 | ); 160 | runOnlyForDeploymentPostprocessing = 0; 161 | }; 162 | /* End PBXFrameworksBuildPhase section */ 163 | 164 | /* Begin PBXGroup section */ 165 | 05305D68152514DE00069F78 /* Optional MAZeroingWeakRef */ = { 166 | isa = PBXGroup; 167 | children = ( 168 | C2CB835F1523D91500E8AC05 /* MAZeroingWeakRefNativeZWRNotAllowedTable.h */, 169 | C2CB835F1523D91500E8AC00 /* MAZeroingWeakRef.m */, 170 | C2CB835F1523D91500E8ABFD /* MAZeroingWeakRef.h */, 171 | ); 172 | name = "Optional MAZeroingWeakRef"; 173 | sourceTree = ""; 174 | }; 175 | 0538879C1523F6CD00CDC1DF /* Other Frameworks */ = { 176 | isa = PBXGroup; 177 | children = ( 178 | 0538879D1523F6CD00CDC1DF /* AppKit.framework */, 179 | 0538879E1523F6CD00CDC1DF /* CoreData.framework */, 180 | 0538879F1523F6CD00CDC1DF /* Foundation.framework */, 181 | ); 182 | name = "Other Frameworks"; 183 | sourceTree = ""; 184 | }; 185 | 0573A9531526484200D0D884 /* PLWeakCompatibility-iOS-TestRunner */ = { 186 | isa = PBXGroup; 187 | children = ( 188 | 0573A95C1526484200D0D884 /* PLAppDelegate.h */, 189 | 0573A95D1526484200D0D884 /* PLAppDelegate.m */, 190 | 0573A9541526484200D0D884 /* Supporting Files */, 191 | ); 192 | path = "PLWeakCompatibility-iOS-TestRunner"; 193 | sourceTree = ""; 194 | }; 195 | 0573A9541526484200D0D884 /* Supporting Files */ = { 196 | isa = PBXGroup; 197 | children = ( 198 | 0573A9551526484200D0D884 /* PLWeakCompatibility-iOS-TestRunner-Info.plist */, 199 | 0573A9561526484200D0D884 /* InfoPlist.strings */, 200 | 0573A9591526484200D0D884 /* main.m */, 201 | 0573A95B1526484200D0D884 /* PLWeakCompatibility-iOS-TestRunner-Prefix.pch */, 202 | ); 203 | name = "Supporting Files"; 204 | sourceTree = ""; 205 | }; 206 | 0573A96A1526484200D0D884 /* PLWeakCompatibility-iOS-TestTests */ = { 207 | isa = PBXGroup; 208 | children = ( 209 | 0573A96B1526484200D0D884 /* Supporting Files */, 210 | ); 211 | name = "PLWeakCompatibility-iOS-TestTests"; 212 | path = "PLWeakCompatibility-iOS-Tests"; 213 | sourceTree = ""; 214 | }; 215 | 0573A96B1526484200D0D884 /* Supporting Files */ = { 216 | isa = PBXGroup; 217 | children = ( 218 | 0573A96C1526484200D0D884 /* PLWeakCompatibility-iOS-TestRunnerTests-Info.plist */, 219 | 0573A96D1526484200D0D884 /* InfoPlist.strings */, 220 | ); 221 | name = "Supporting Files"; 222 | sourceTree = ""; 223 | }; 224 | C2CB83201523D8F300E8ABFC = { 225 | isa = PBXGroup; 226 | children = ( 227 | C2123595152647A50082CE88 /* LICENSE */, 228 | C212358A15263C410082CE88 /* README.markdown */, 229 | C2CB83351523D8F300E8ABFC /* PLWeakCompatibility */, 230 | C2CB834D1523D8F400E8ABFC /* PLWeakCompatibilityTests */, 231 | 0573A9531526484200D0D884 /* PLWeakCompatibility-iOS-TestRunner */, 232 | 0573A96A1526484200D0D884 /* PLWeakCompatibility-iOS-TestTests */, 233 | C2CB832E1523D8F300E8ABFC /* Frameworks */, 234 | C2CB832C1523D8F300E8ABFC /* Products */, 235 | ); 236 | sourceTree = ""; 237 | }; 238 | C2CB832C1523D8F300E8ABFC /* Products */ = { 239 | isa = PBXGroup; 240 | children = ( 241 | C2CB83461523D8F300E8ABFC /* PLWeakCompatibility-MacOSX-Tests.octest */, 242 | 053887991523F6CD00CDC1DF /* PLWeakCompatibility.framework */, 243 | 053887C61523F6F700CDC1DF /* libPLWeakCompatibility-iOS.a */, 244 | 0573A94C1526484200D0D884 /* PLWeakCompatibility-iOS-TestRunner.app */, 245 | 0573A9641526484200D0D884 /* PLWeakCompatibility-iOS-Tests.octest */, 246 | ); 247 | name = Products; 248 | sourceTree = ""; 249 | }; 250 | C2CB832E1523D8F300E8ABFC /* Frameworks */ = { 251 | isa = PBXGroup; 252 | children = ( 253 | C2CB83311523D8F300E8ABFC /* Foundation.framework */, 254 | C2CB83471523D8F300E8ABFC /* SenTestingKit.framework */, 255 | 0573A94E1526484200D0D884 /* UIKit.framework */, 256 | 0573A9511526484200D0D884 /* CoreGraphics.framework */, 257 | 0538879C1523F6CD00CDC1DF /* Other Frameworks */, 258 | ); 259 | name = Frameworks; 260 | sourceTree = ""; 261 | }; 262 | C2CB83351523D8F300E8ABFC /* PLWeakCompatibility */ = { 263 | isa = PBXGroup; 264 | children = ( 265 | 05305D68152514DE00069F78 /* Optional MAZeroingWeakRef */, 266 | C2CB835E1523D91500E8ABFC /* PLWeakCompatibilityStubs.h */, 267 | C2CB835F1523D91500E8ABFC /* PLWeakCompatibilityStubs.m */, 268 | C2CB83361523D8F300E8ABFC /* Supporting Files */, 269 | ); 270 | path = PLWeakCompatibility; 271 | sourceTree = ""; 272 | }; 273 | C2CB83361523D8F300E8ABFC /* Supporting Files */ = { 274 | isa = PBXGroup; 275 | children = ( 276 | 053888281523F7EA00CDC1DF /* PLWeakCompatibility-Info.plist */, 277 | C2CB83381523D8F300E8ABFC /* InfoPlist.strings */, 278 | C2CB833B1523D8F300E8ABFC /* main.m */, 279 | C2CB833D1523D8F300E8ABFC /* PLWeakCompatibility-Prefix.pch */, 280 | ); 281 | name = "Supporting Files"; 282 | sourceTree = ""; 283 | }; 284 | C2CB834D1523D8F400E8ABFC /* PLWeakCompatibilityTests */ = { 285 | isa = PBXGroup; 286 | children = ( 287 | C2CB83531523D8F400E8ABFC /* PLWeakCompatibilityTests.h */, 288 | C2CB83541523D8F400E8ABFC /* PLWeakCompatibilityTests.m */, 289 | C2CB834E1523D8F400E8ABFC /* Supporting Files */, 290 | ); 291 | path = PLWeakCompatibilityTests; 292 | sourceTree = ""; 293 | }; 294 | C2CB834E1523D8F400E8ABFC /* Supporting Files */ = { 295 | isa = PBXGroup; 296 | children = ( 297 | C2CB834F1523D8F400E8ABFC /* PLWeakCompatibilityTests-Info.plist */, 298 | C2CB83501523D8F400E8ABFC /* InfoPlist.strings */, 299 | ); 300 | name = "Supporting Files"; 301 | sourceTree = ""; 302 | }; 303 | /* End PBXGroup section */ 304 | 305 | /* Begin PBXHeadersBuildPhase section */ 306 | 053887961523F6CD00CDC1DF /* Headers */ = { 307 | isa = PBXHeadersBuildPhase; 308 | buildActionMask = 2147483647; 309 | files = ( 310 | 053888771523FFC700CDC1DF /* PLWeakCompatibilityStubs.h in Headers */, 311 | C2CB835F1523D91500E8ABFE /* MAZeroingWeakRef.h in Headers */, 312 | ); 313 | runOnlyForDeploymentPostprocessing = 0; 314 | }; 315 | 053887C41523F6F700CDC1DF /* Headers */ = { 316 | isa = PBXHeadersBuildPhase; 317 | buildActionMask = 2147483647; 318 | files = ( 319 | C2CB835F1523D91500E8ABFF /* MAZeroingWeakRef.h in Headers */, 320 | ); 321 | runOnlyForDeploymentPostprocessing = 0; 322 | }; 323 | /* End PBXHeadersBuildPhase section */ 324 | 325 | /* Begin PBXNativeTarget section */ 326 | 053887981523F6CD00CDC1DF /* PLWeakCompatibility-MacOSX */ = { 327 | isa = PBXNativeTarget; 328 | buildConfigurationList = 053887AC1523F6CD00CDC1DF /* Build configuration list for PBXNativeTarget "PLWeakCompatibility-MacOSX" */; 329 | buildPhases = ( 330 | 053887941523F6CD00CDC1DF /* Sources */, 331 | 053887951523F6CD00CDC1DF /* Frameworks */, 332 | 053887961523F6CD00CDC1DF /* Headers */, 333 | 053887971523F6CD00CDC1DF /* Resources */, 334 | 0538887D1524025B00CDC1DF /* Copy Frameworks */, 335 | ); 336 | buildRules = ( 337 | ); 338 | dependencies = ( 339 | ); 340 | name = "PLWeakCompatibility-MacOSX"; 341 | productName = "PLWeakCompatibility-MacOSX"; 342 | productReference = 053887991523F6CD00CDC1DF /* PLWeakCompatibility.framework */; 343 | productType = "com.apple.product-type.framework"; 344 | }; 345 | 053887C51523F6F700CDC1DF /* PLWeakCompatibility-iOS */ = { 346 | isa = PBXNativeTarget; 347 | buildConfigurationList = 053887E31523F6F700CDC1DF /* Build configuration list for PBXNativeTarget "PLWeakCompatibility-iOS" */; 348 | buildPhases = ( 349 | 053887C21523F6F700CDC1DF /* Sources */, 350 | 053887C31523F6F700CDC1DF /* Frameworks */, 351 | 053887C41523F6F700CDC1DF /* Headers */, 352 | ); 353 | buildRules = ( 354 | ); 355 | dependencies = ( 356 | ); 357 | name = "PLWeakCompatibility-iOS"; 358 | productName = "PLWeakCompatibility-iOS-Device"; 359 | productReference = 053887C61523F6F700CDC1DF /* libPLWeakCompatibility-iOS.a */; 360 | productType = "com.apple.product-type.library.static"; 361 | }; 362 | 0573A94B1526484200D0D884 /* PLWeakCompatibility-iOS-TestRunner */ = { 363 | isa = PBXNativeTarget; 364 | buildConfigurationList = 0573A9731526484200D0D884 /* Build configuration list for PBXNativeTarget "PLWeakCompatibility-iOS-TestRunner" */; 365 | buildPhases = ( 366 | 0573A9481526484200D0D884 /* Sources */, 367 | 0573A9491526484200D0D884 /* Frameworks */, 368 | 0573A94A1526484200D0D884 /* Resources */, 369 | ); 370 | buildRules = ( 371 | ); 372 | dependencies = ( 373 | 0573A97A1526485000D0D884 /* PBXTargetDependency */, 374 | ); 375 | name = "PLWeakCompatibility-iOS-TestRunner"; 376 | productName = "PLWeakCompatibility-iOS-TestRunner"; 377 | productReference = 0573A94C1526484200D0D884 /* PLWeakCompatibility-iOS-TestRunner.app */; 378 | productType = "com.apple.product-type.application"; 379 | }; 380 | 0573A9631526484200D0D884 /* PLWeakCompatibility-iOS-Tests */ = { 381 | isa = PBXNativeTarget; 382 | buildConfigurationList = 0573A9761526484200D0D884 /* Build configuration list for PBXNativeTarget "PLWeakCompatibility-iOS-Tests" */; 383 | buildPhases = ( 384 | 0573A95F1526484200D0D884 /* Sources */, 385 | 0573A9601526484200D0D884 /* Frameworks */, 386 | 0573A9611526484200D0D884 /* Resources */, 387 | 0573A9621526484200D0D884 /* ShellScript */, 388 | ); 389 | buildRules = ( 390 | ); 391 | dependencies = ( 392 | 0573A9691526484200D0D884 /* PBXTargetDependency */, 393 | 0573A97E152648DE00D0D884 /* PBXTargetDependency */, 394 | ); 395 | name = "PLWeakCompatibility-iOS-Tests"; 396 | productName = "PLWeakCompatibility-iOS-TestRunnerTests"; 397 | productReference = 0573A9641526484200D0D884 /* PLWeakCompatibility-iOS-Tests.octest */; 398 | productType = "com.apple.product-type.bundle"; 399 | }; 400 | C2CB83451523D8F300E8ABFC /* PLWeakCompatibility-MacOSX-Tests */ = { 401 | isa = PBXNativeTarget; 402 | buildConfigurationList = C2CB835B1523D8F400E8ABFC /* Build configuration list for PBXNativeTarget "PLWeakCompatibility-MacOSX-Tests" */; 403 | buildPhases = ( 404 | C2CB83411523D8F300E8ABFC /* Sources */, 405 | C2CB83421523D8F300E8ABFC /* Frameworks */, 406 | C2CB83431523D8F300E8ABFC /* Resources */, 407 | C2CB83441523D8F300E8ABFC /* ShellScript */, 408 | ); 409 | buildRules = ( 410 | ); 411 | dependencies = ( 412 | ); 413 | name = "PLWeakCompatibility-MacOSX-Tests"; 414 | productName = PLWeakCompatibilityTests; 415 | productReference = C2CB83461523D8F300E8ABFC /* PLWeakCompatibility-MacOSX-Tests.octest */; 416 | productType = "com.apple.product-type.bundle"; 417 | }; 418 | /* End PBXNativeTarget section */ 419 | 420 | /* Begin PBXProject section */ 421 | C2CB83221523D8F300E8ABFC /* Project object */ = { 422 | isa = PBXProject; 423 | attributes = { 424 | CLASSPREFIX = PL; 425 | LastUpgradeCheck = 0430; 426 | }; 427 | buildConfigurationList = C2CB83251523D8F300E8ABFC /* Build configuration list for PBXProject "PLWeakCompatibility" */; 428 | compatibilityVersion = "Xcode 3.2"; 429 | developmentRegion = English; 430 | hasScannedForEncodings = 0; 431 | knownRegions = ( 432 | en, 433 | ); 434 | mainGroup = C2CB83201523D8F300E8ABFC; 435 | productRefGroup = C2CB832C1523D8F300E8ABFC /* Products */; 436 | projectDirPath = ""; 437 | projectRoot = ""; 438 | targets = ( 439 | 053887981523F6CD00CDC1DF /* PLWeakCompatibility-MacOSX */, 440 | 053887C51523F6F700CDC1DF /* PLWeakCompatibility-iOS */, 441 | C2CB83451523D8F300E8ABFC /* PLWeakCompatibility-MacOSX-Tests */, 442 | 0573A94B1526484200D0D884 /* PLWeakCompatibility-iOS-TestRunner */, 443 | 0573A9631526484200D0D884 /* PLWeakCompatibility-iOS-Tests */, 444 | ); 445 | }; 446 | /* End PBXProject section */ 447 | 448 | /* Begin PBXResourcesBuildPhase section */ 449 | 053887971523F6CD00CDC1DF /* Resources */ = { 450 | isa = PBXResourcesBuildPhase; 451 | buildActionMask = 2147483647; 452 | files = ( 453 | ); 454 | runOnlyForDeploymentPostprocessing = 0; 455 | }; 456 | 0573A94A1526484200D0D884 /* Resources */ = { 457 | isa = PBXResourcesBuildPhase; 458 | buildActionMask = 2147483647; 459 | files = ( 460 | 0573A9581526484200D0D884 /* InfoPlist.strings in Resources */, 461 | ); 462 | runOnlyForDeploymentPostprocessing = 0; 463 | }; 464 | 0573A9611526484200D0D884 /* Resources */ = { 465 | isa = PBXResourcesBuildPhase; 466 | buildActionMask = 2147483647; 467 | files = ( 468 | 0573A96F1526484200D0D884 /* InfoPlist.strings in Resources */, 469 | ); 470 | runOnlyForDeploymentPostprocessing = 0; 471 | }; 472 | C2CB83431523D8F300E8ABFC /* Resources */ = { 473 | isa = PBXResourcesBuildPhase; 474 | buildActionMask = 2147483647; 475 | files = ( 476 | C2CB83521523D8F400E8ABFC /* InfoPlist.strings in Resources */, 477 | ); 478 | runOnlyForDeploymentPostprocessing = 0; 479 | }; 480 | /* End PBXResourcesBuildPhase section */ 481 | 482 | /* Begin PBXShellScriptBuildPhase section */ 483 | 0573A9621526484200D0D884 /* ShellScript */ = { 484 | isa = PBXShellScriptBuildPhase; 485 | buildActionMask = 2147483647; 486 | files = ( 487 | ); 488 | inputPaths = ( 489 | ); 490 | outputPaths = ( 491 | ); 492 | runOnlyForDeploymentPostprocessing = 0; 493 | shellPath = /bin/sh; 494 | shellScript = "# Run the unit tests in this test bundle.\n\"${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests\"\n"; 495 | }; 496 | C2CB83441523D8F300E8ABFC /* ShellScript */ = { 497 | isa = PBXShellScriptBuildPhase; 498 | buildActionMask = 2147483647; 499 | files = ( 500 | ); 501 | inputPaths = ( 502 | ); 503 | outputPaths = ( 504 | ); 505 | runOnlyForDeploymentPostprocessing = 0; 506 | shellPath = /bin/sh; 507 | shellScript = "# Run the unit tests in this test bundle.\n\"${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests\"\n"; 508 | }; 509 | /* End PBXShellScriptBuildPhase section */ 510 | 511 | /* Begin PBXSourcesBuildPhase section */ 512 | 053887941523F6CD00CDC1DF /* Sources */ = { 513 | isa = PBXSourcesBuildPhase; 514 | buildActionMask = 2147483647; 515 | files = ( 516 | 053888261523F7A500CDC1DF /* PLWeakCompatibilityStubs.m in Sources */, 517 | ); 518 | runOnlyForDeploymentPostprocessing = 0; 519 | }; 520 | 053887C21523F6F700CDC1DF /* Sources */ = { 521 | isa = PBXSourcesBuildPhase; 522 | buildActionMask = 2147483647; 523 | files = ( 524 | 053888271523F7A900CDC1DF /* PLWeakCompatibilityStubs.m in Sources */, 525 | ); 526 | runOnlyForDeploymentPostprocessing = 0; 527 | }; 528 | 0573A9481526484200D0D884 /* Sources */ = { 529 | isa = PBXSourcesBuildPhase; 530 | buildActionMask = 2147483647; 531 | files = ( 532 | 0501743F15265D2B001DFA82 /* MAZeroingWeakRef.m in Sources */, 533 | 0573A95A1526484200D0D884 /* main.m in Sources */, 534 | 0573A95E1526484200D0D884 /* PLAppDelegate.m in Sources */, 535 | ); 536 | runOnlyForDeploymentPostprocessing = 0; 537 | }; 538 | 0573A95F1526484200D0D884 /* Sources */ = { 539 | isa = PBXSourcesBuildPhase; 540 | buildActionMask = 2147483647; 541 | files = ( 542 | 0573A97C1526486A00D0D884 /* PLWeakCompatibilityTests.m in Sources */, 543 | ); 544 | runOnlyForDeploymentPostprocessing = 0; 545 | }; 546 | C2CB83411523D8F300E8ABFC /* Sources */ = { 547 | isa = PBXSourcesBuildPhase; 548 | buildActionMask = 2147483647; 549 | files = ( 550 | 05286A981524D85F00FD0AD7 /* PLWeakCompatibilityStubs.m in Sources */, 551 | C2CB83551523D8F400E8ABFC /* PLWeakCompatibilityTests.m in Sources */, 552 | C2CB835F1523D91500E8AC03 /* MAZeroingWeakRef.m in Sources */, 553 | ); 554 | runOnlyForDeploymentPostprocessing = 0; 555 | }; 556 | /* End PBXSourcesBuildPhase section */ 557 | 558 | /* Begin PBXTargetDependency section */ 559 | 0573A9691526484200D0D884 /* PBXTargetDependency */ = { 560 | isa = PBXTargetDependency; 561 | target = 0573A94B1526484200D0D884 /* PLWeakCompatibility-iOS-TestRunner */; 562 | targetProxy = 0573A9681526484200D0D884 /* PBXContainerItemProxy */; 563 | }; 564 | 0573A97A1526485000D0D884 /* PBXTargetDependency */ = { 565 | isa = PBXTargetDependency; 566 | target = 053887C51523F6F700CDC1DF /* PLWeakCompatibility-iOS */; 567 | targetProxy = 0573A9791526485000D0D884 /* PBXContainerItemProxy */; 568 | }; 569 | 0573A97E152648DE00D0D884 /* PBXTargetDependency */ = { 570 | isa = PBXTargetDependency; 571 | target = 053887C51523F6F700CDC1DF /* PLWeakCompatibility-iOS */; 572 | targetProxy = 0573A97D152648DE00D0D884 /* PBXContainerItemProxy */; 573 | }; 574 | /* End PBXTargetDependency section */ 575 | 576 | /* Begin PBXVariantGroup section */ 577 | 0573A9561526484200D0D884 /* InfoPlist.strings */ = { 578 | isa = PBXVariantGroup; 579 | children = ( 580 | 0573A9571526484200D0D884 /* en */, 581 | ); 582 | name = InfoPlist.strings; 583 | sourceTree = ""; 584 | }; 585 | 0573A96D1526484200D0D884 /* InfoPlist.strings */ = { 586 | isa = PBXVariantGroup; 587 | children = ( 588 | 0573A96E1526484200D0D884 /* en */, 589 | ); 590 | name = InfoPlist.strings; 591 | sourceTree = ""; 592 | }; 593 | C2CB83381523D8F300E8ABFC /* InfoPlist.strings */ = { 594 | isa = PBXVariantGroup; 595 | children = ( 596 | C2CB83391523D8F300E8ABFC /* en */, 597 | ); 598 | name = InfoPlist.strings; 599 | sourceTree = ""; 600 | }; 601 | C2CB83501523D8F400E8ABFC /* InfoPlist.strings */ = { 602 | isa = PBXVariantGroup; 603 | children = ( 604 | C2CB83511523D8F400E8ABFC /* en */, 605 | ); 606 | name = InfoPlist.strings; 607 | sourceTree = ""; 608 | }; 609 | /* End PBXVariantGroup section */ 610 | 611 | /* Begin XCBuildConfiguration section */ 612 | 053887AA1523F6CD00CDC1DF /* Debug */ = { 613 | isa = XCBuildConfiguration; 614 | buildSettings = { 615 | ARCHS = "$(ARCHS_STANDARD_64_BIT)"; 616 | DYLIB_COMPATIBILITY_VERSION = 1; 617 | DYLIB_CURRENT_VERSION = 1; 618 | FRAMEWORK_SEARCH_PATHS = ( 619 | "$(inherited)", 620 | "\"$(SYSTEM_APPS_DIR)/Xcode.app/Contents/Developer/Library/Frameworks\"", 621 | "\"$(SRCROOT)/PLBlockIMP/Mac\"", 622 | ); 623 | FRAMEWORK_VERSION = A; 624 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 625 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 626 | INFOPLIST_FILE = "PLWeakCompatibility/PLWeakCompatibility-Info.plist"; 627 | MACOSX_DEPLOYMENT_TARGET = 10.7; 628 | ONLY_ACTIVE_ARCH = YES; 629 | PRODUCT_NAME = PLWeakCompatibility; 630 | SDKROOT = macosx; 631 | WRAPPER_EXTENSION = framework; 632 | }; 633 | name = Debug; 634 | }; 635 | 053887AB1523F6CD00CDC1DF /* Release */ = { 636 | isa = XCBuildConfiguration; 637 | buildSettings = { 638 | ARCHS = "$(ARCHS_STANDARD_64_BIT)"; 639 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 640 | DYLIB_COMPATIBILITY_VERSION = 1; 641 | DYLIB_CURRENT_VERSION = 1; 642 | FRAMEWORK_SEARCH_PATHS = ( 643 | "$(inherited)", 644 | "\"$(SYSTEM_APPS_DIR)/Xcode.app/Contents/Developer/Library/Frameworks\"", 645 | "\"$(SRCROOT)/PLBlockIMP/Mac\"", 646 | ); 647 | FRAMEWORK_VERSION = A; 648 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 649 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 650 | INFOPLIST_FILE = "PLWeakCompatibility/PLWeakCompatibility-Info.plist"; 651 | MACOSX_DEPLOYMENT_TARGET = 10.7; 652 | PRODUCT_NAME = PLWeakCompatibility; 653 | SDKROOT = macosx; 654 | WRAPPER_EXTENSION = framework; 655 | }; 656 | name = Release; 657 | }; 658 | 053887E41523F6F700CDC1DF /* Debug */ = { 659 | isa = XCBuildConfiguration; 660 | buildSettings = { 661 | ARCHS = ( 662 | armv7, 663 | armv6, 664 | ); 665 | DSTROOT = /tmp/PLWeakCompatibility_iOS_Device.dst; 666 | FRAMEWORK_SEARCH_PATHS = ( 667 | "$(inherited)", 668 | "\"$(SRCROOT)/PLBlockIMP/iOS\"", 669 | ); 670 | GCC_THUMB_SUPPORT = NO; 671 | IPHONEOS_DEPLOYMENT_TARGET = 4.0; 672 | OTHER_LDFLAGS = "-ObjC"; 673 | PRODUCT_NAME = "$(TARGET_NAME)"; 674 | SDKROOT = iphoneos; 675 | SKIP_INSTALL = YES; 676 | TARGETED_DEVICE_FAMILY = "1,2"; 677 | }; 678 | name = Debug; 679 | }; 680 | 053887E51523F6F700CDC1DF /* Release */ = { 681 | isa = XCBuildConfiguration; 682 | buildSettings = { 683 | ARCHS = ( 684 | armv7, 685 | armv6, 686 | ); 687 | DSTROOT = /tmp/PLWeakCompatibility_iOS_Device.dst; 688 | FRAMEWORK_SEARCH_PATHS = ( 689 | "$(inherited)", 690 | "\"$(SRCROOT)/PLBlockIMP/iOS\"", 691 | ); 692 | GCC_THUMB_SUPPORT = NO; 693 | IPHONEOS_DEPLOYMENT_TARGET = 4.0; 694 | OTHER_LDFLAGS = "-ObjC"; 695 | PRODUCT_NAME = "$(TARGET_NAME)"; 696 | SDKROOT = iphoneos; 697 | SKIP_INSTALL = YES; 698 | TARGETED_DEVICE_FAMILY = "1,2"; 699 | }; 700 | name = Release; 701 | }; 702 | 0573A9741526484200D0D884 /* Debug */ = { 703 | isa = XCBuildConfiguration; 704 | buildSettings = { 705 | ARCHS = ( 706 | armv7, 707 | armv6, 708 | ); 709 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 710 | DEAD_CODE_STRIPPING = NO; 711 | FRAMEWORK_SEARCH_PATHS = ( 712 | "$(inherited)", 713 | "\"$(SYSTEM_APPS_DIR)/Xcode.app/Contents/Developer/Library/Frameworks\"", 714 | ); 715 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 716 | GCC_PREFIX_HEADER = "PLWeakCompatibility-iOS-TestRunner/PLWeakCompatibility-iOS-TestRunner-Prefix.pch"; 717 | INFOPLIST_FILE = "PLWeakCompatibility-iOS-TestRunner/PLWeakCompatibility-iOS-TestRunner-Info.plist"; 718 | IPHONEOS_DEPLOYMENT_TARGET = 4.0; 719 | OTHER_LDFLAGS = ( 720 | "-ObjC", 721 | "-all_load", 722 | ); 723 | PRODUCT_NAME = "$(TARGET_NAME)"; 724 | SDKROOT = iphoneos; 725 | TARGETED_DEVICE_FAMILY = "1,2"; 726 | WRAPPER_EXTENSION = app; 727 | }; 728 | name = Debug; 729 | }; 730 | 0573A9751526484200D0D884 /* Release */ = { 731 | isa = XCBuildConfiguration; 732 | buildSettings = { 733 | ARCHS = ( 734 | armv7, 735 | armv6, 736 | ); 737 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 738 | DEAD_CODE_STRIPPING = NO; 739 | FRAMEWORK_SEARCH_PATHS = ( 740 | "$(inherited)", 741 | "\"$(SYSTEM_APPS_DIR)/Xcode.app/Contents/Developer/Library/Frameworks\"", 742 | ); 743 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 744 | GCC_PREFIX_HEADER = "PLWeakCompatibility-iOS-TestRunner/PLWeakCompatibility-iOS-TestRunner-Prefix.pch"; 745 | INFOPLIST_FILE = "PLWeakCompatibility-iOS-TestRunner/PLWeakCompatibility-iOS-TestRunner-Info.plist"; 746 | IPHONEOS_DEPLOYMENT_TARGET = 4.0; 747 | OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; 748 | OTHER_LDFLAGS = ( 749 | "-ObjC", 750 | "-all_load", 751 | ); 752 | PRODUCT_NAME = "$(TARGET_NAME)"; 753 | SDKROOT = iphoneos; 754 | TARGETED_DEVICE_FAMILY = "1,2"; 755 | WRAPPER_EXTENSION = app; 756 | }; 757 | name = Release; 758 | }; 759 | 0573A9771526484200D0D884 /* Debug */ = { 760 | isa = XCBuildConfiguration; 761 | buildSettings = { 762 | ARCHS = ( 763 | armv7, 764 | armv6, 765 | ); 766 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/PLWeakCompatibility-iOS-TestRunner.app/PLWeakCompatibility-iOS-TestRunner"; 767 | FRAMEWORK_SEARCH_PATHS = ( 768 | "$(SDKROOT)/Developer/Library/Frameworks", 769 | "$(DEVELOPER_LIBRARY_DIR)/Frameworks", 770 | ); 771 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 772 | GCC_PREFIX_HEADER = "PLWeakCompatibility-iOS-TestRunner/PLWeakCompatibility-iOS-TestRunner-Prefix.pch"; 773 | INFOPLIST_FILE = "PLWeakCompatibility-iOS-Tests/PLWeakCompatibility-iOS-TestRunnerTests-Info.plist"; 774 | IPHONEOS_DEPLOYMENT_TARGET = 4.0; 775 | PRODUCT_NAME = "$(TARGET_NAME)"; 776 | SDKROOT = iphoneos; 777 | TEST_HOST = "$(BUNDLE_LOADER)"; 778 | WRAPPER_EXTENSION = octest; 779 | }; 780 | name = Debug; 781 | }; 782 | 0573A9781526484200D0D884 /* Release */ = { 783 | isa = XCBuildConfiguration; 784 | buildSettings = { 785 | ARCHS = ( 786 | armv7, 787 | armv6, 788 | ); 789 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/PLWeakCompatibility-iOS-TestRunner.app/PLWeakCompatibility-iOS-TestRunner"; 790 | FRAMEWORK_SEARCH_PATHS = ( 791 | "$(SDKROOT)/Developer/Library/Frameworks", 792 | "$(DEVELOPER_LIBRARY_DIR)/Frameworks", 793 | ); 794 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 795 | GCC_PREFIX_HEADER = "PLWeakCompatibility-iOS-TestRunner/PLWeakCompatibility-iOS-TestRunner-Prefix.pch"; 796 | INFOPLIST_FILE = "PLWeakCompatibility-iOS-Tests/PLWeakCompatibility-iOS-TestRunnerTests-Info.plist"; 797 | IPHONEOS_DEPLOYMENT_TARGET = 4.0; 798 | PRODUCT_NAME = "$(TARGET_NAME)"; 799 | SDKROOT = iphoneos; 800 | TEST_HOST = "$(BUNDLE_LOADER)"; 801 | WRAPPER_EXTENSION = octest; 802 | }; 803 | name = Release; 804 | }; 805 | C2CB83561523D8F400E8ABFC /* Debug */ = { 806 | isa = XCBuildConfiguration; 807 | buildSettings = { 808 | ALWAYS_SEARCH_USER_PATHS = NO; 809 | ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; 810 | CLANG_ENABLE_OBJC_ARC = YES; 811 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 812 | COPY_PHASE_STRIP = NO; 813 | CURRENT_PROJECT_VERSION = "1.0-beta1"; 814 | GCC_C_LANGUAGE_STANDARD = gnu99; 815 | GCC_DYNAMIC_NO_PIC = NO; 816 | GCC_OPTIMIZATION_LEVEL = 0; 817 | GCC_PREPROCESSOR_DEFINITIONS = ( 818 | "DEBUG=1", 819 | "$(inherited)", 820 | ); 821 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 822 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 823 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 824 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 825 | GCC_WARN_UNUSED_VARIABLE = YES; 826 | MACOSX_DEPLOYMENT_TARGET = 10.6; 827 | "OTHER_CFLAGS[arch=*]" = ( 828 | "-Xclang", 829 | "-fobjc-runtime-has-weak", 830 | ); 831 | SDKROOT = macosx; 832 | }; 833 | name = Debug; 834 | }; 835 | C2CB83571523D8F400E8ABFC /* Release */ = { 836 | isa = XCBuildConfiguration; 837 | buildSettings = { 838 | ALWAYS_SEARCH_USER_PATHS = NO; 839 | ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; 840 | CLANG_ENABLE_OBJC_ARC = YES; 841 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 842 | COPY_PHASE_STRIP = YES; 843 | CURRENT_PROJECT_VERSION = "1.0-beta1"; 844 | GCC_C_LANGUAGE_STANDARD = gnu99; 845 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 846 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 847 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 848 | GCC_WARN_UNUSED_VARIABLE = YES; 849 | MACOSX_DEPLOYMENT_TARGET = 10.6; 850 | OTHER_CFLAGS = ( 851 | "-Xclang", 852 | "-fobjc-runtime-has-weak", 853 | "-DNS_BLOCK_ASSERTIONS=1", 854 | ); 855 | "OTHER_CFLAGS[arch=*]" = ( 856 | "-DNS_BLOCK_ASSERTIONS=1", 857 | "-Xclang", 858 | "-fobjc-runtime-has-weak", 859 | ); 860 | SDKROOT = macosx; 861 | VALIDATE_PRODUCT = YES; 862 | }; 863 | name = Release; 864 | }; 865 | C2CB835C1523D8F400E8ABFC /* Debug */ = { 866 | isa = XCBuildConfiguration; 867 | buildSettings = { 868 | ARCHS = "$(ARCHS_STANDARD_64_BIT)"; 869 | FRAMEWORK_SEARCH_PATHS = "$(DEVELOPER_LIBRARY_DIR)/Frameworks"; 870 | INFOPLIST_FILE = "PLWeakCompatibilityTests/PLWeakCompatibilityTests-Info.plist"; 871 | PRODUCT_NAME = "$(TARGET_NAME)"; 872 | TEST_AFTER_BUILD = YES; 873 | WRAPPER_EXTENSION = octest; 874 | }; 875 | name = Debug; 876 | }; 877 | C2CB835D1523D8F400E8ABFC /* Release */ = { 878 | isa = XCBuildConfiguration; 879 | buildSettings = { 880 | ARCHS = "$(ARCHS_STANDARD_64_BIT)"; 881 | FRAMEWORK_SEARCH_PATHS = "$(DEVELOPER_LIBRARY_DIR)/Frameworks"; 882 | INFOPLIST_FILE = "PLWeakCompatibilityTests/PLWeakCompatibilityTests-Info.plist"; 883 | PRODUCT_NAME = "$(TARGET_NAME)"; 884 | TEST_AFTER_BUILD = YES; 885 | WRAPPER_EXTENSION = octest; 886 | }; 887 | name = Release; 888 | }; 889 | /* End XCBuildConfiguration section */ 890 | 891 | /* Begin XCConfigurationList section */ 892 | 053887AC1523F6CD00CDC1DF /* Build configuration list for PBXNativeTarget "PLWeakCompatibility-MacOSX" */ = { 893 | isa = XCConfigurationList; 894 | buildConfigurations = ( 895 | 053887AA1523F6CD00CDC1DF /* Debug */, 896 | 053887AB1523F6CD00CDC1DF /* Release */, 897 | ); 898 | defaultConfigurationIsVisible = 0; 899 | defaultConfigurationName = Release; 900 | }; 901 | 053887E31523F6F700CDC1DF /* Build configuration list for PBXNativeTarget "PLWeakCompatibility-iOS" */ = { 902 | isa = XCConfigurationList; 903 | buildConfigurations = ( 904 | 053887E41523F6F700CDC1DF /* Debug */, 905 | 053887E51523F6F700CDC1DF /* Release */, 906 | ); 907 | defaultConfigurationIsVisible = 0; 908 | defaultConfigurationName = Release; 909 | }; 910 | 0573A9731526484200D0D884 /* Build configuration list for PBXNativeTarget "PLWeakCompatibility-iOS-TestRunner" */ = { 911 | isa = XCConfigurationList; 912 | buildConfigurations = ( 913 | 0573A9741526484200D0D884 /* Debug */, 914 | 0573A9751526484200D0D884 /* Release */, 915 | ); 916 | defaultConfigurationIsVisible = 0; 917 | defaultConfigurationName = Release; 918 | }; 919 | 0573A9761526484200D0D884 /* Build configuration list for PBXNativeTarget "PLWeakCompatibility-iOS-Tests" */ = { 920 | isa = XCConfigurationList; 921 | buildConfigurations = ( 922 | 0573A9771526484200D0D884 /* Debug */, 923 | 0573A9781526484200D0D884 /* Release */, 924 | ); 925 | defaultConfigurationIsVisible = 0; 926 | defaultConfigurationName = Release; 927 | }; 928 | C2CB83251523D8F300E8ABFC /* Build configuration list for PBXProject "PLWeakCompatibility" */ = { 929 | isa = XCConfigurationList; 930 | buildConfigurations = ( 931 | C2CB83561523D8F400E8ABFC /* Debug */, 932 | C2CB83571523D8F400E8ABFC /* Release */, 933 | ); 934 | defaultConfigurationIsVisible = 0; 935 | defaultConfigurationName = Release; 936 | }; 937 | C2CB835B1523D8F400E8ABFC /* Build configuration list for PBXNativeTarget "PLWeakCompatibility-MacOSX-Tests" */ = { 938 | isa = XCConfigurationList; 939 | buildConfigurations = ( 940 | C2CB835C1523D8F400E8ABFC /* Debug */, 941 | C2CB835D1523D8F400E8ABFC /* Release */, 942 | ); 943 | defaultConfigurationIsVisible = 0; 944 | defaultConfigurationName = Release; 945 | }; 946 | /* End XCConfigurationList section */ 947 | }; 948 | rootObject = C2CB83221523D8F300E8ABFC /* Project object */; 949 | } 950 | -------------------------------------------------------------------------------- /PLWeakCompatibility/MAZeroingWeakRef.h: -------------------------------------------------------------------------------- 1 | // 2 | // MAZeroingWeakRef.h 3 | // ZeroingWeakRef 4 | // 5 | // Created by Michael Ash on 7/5/10. 6 | // 7 | 8 | #import 9 | 10 | 11 | @interface MAZeroingWeakRef : NSObject 12 | { 13 | id _target; 14 | BOOL _nativeZWR; 15 | #if NS_BLOCKS_AVAILABLE 16 | void (^_cleanupBlock)(id target); 17 | #endif 18 | } 19 | 20 | + (BOOL)canRefCoreFoundationObjects; 21 | 22 | + (id)refWithTarget: (id)target; 23 | 24 | - (id)initWithTarget: (id)target; 25 | 26 | #if NS_BLOCKS_AVAILABLE 27 | // ON 10.7: 28 | // cleanup block runs while the target's memory is still 29 | // allocated but after all dealloc methods have run 30 | // (it runs at associated object cleanup time) 31 | // you can use the target's pointer value but don't 32 | // manipulate its contents! 33 | 34 | // ON 10.6 AND BELOW: 35 | // cleanup block runs while the global ZWR lock is held 36 | // so make it short and sweet! 37 | // use GCD or something to schedule execution later 38 | // if you need to do something that may take a while 39 | // 40 | // it is unsafe to call -target on the weak ref from 41 | // inside the cleanup block, which is why the target 42 | // is passed in as a parameter 43 | // note that you must not resurrect the target at this point! 44 | - (void)setCleanupBlock: (void (^)(id target))block; 45 | #endif 46 | 47 | - (id)target; 48 | 49 | @end 50 | 51 | #ifndef __has_feature 52 | #define __has_feature(feature) 0 53 | #endif 54 | 55 | #define MAWeakVar(var) __weak_ ## var 56 | 57 | #if __has_feature(objc_arc_weak) 58 | 59 | #define MAWeakDeclare(var) __weak __typeof__((var)) MAWeakVar(var) = var 60 | #define MAWeakImport(var) __typeof__((MAWeakVar(var))) var = MAWeakVar(var) 61 | #define MAWeakImportReturn(var) MAWeakImport(var); do { if(var == nil) return; } while(NO) 62 | 63 | #else 64 | 65 | #define MAWeakDeclare(var) __typeof__((var)) MAWeakVar(var) = (id)[MAZeroingWeakRef refWithTarget:var] 66 | #define MAWeakImport(var) __typeof__((MAWeakVar(var))) var = [(MAZeroingWeakRef *)MAWeakVar(var) target] 67 | #define MAWeakImportReturn(var) MAWeakImport(var); do { if(var == nil) return; } while(NO) 68 | 69 | #endif 70 | 71 | #define MAWeakSelfDeclare() MAWeakDeclare(self) 72 | #define MAWeakSelfImport() MAWeakImport(self) 73 | #define MAWeakSelfImportReturn() MAWeakImportReturn(self) 74 | -------------------------------------------------------------------------------- /PLWeakCompatibility/MAZeroingWeakRef.m: -------------------------------------------------------------------------------- 1 | // 2 | // MAZeroingWeakRef.m 3 | // ZeroingWeakRef 4 | // 5 | // Created by Michael Ash on 7/5/10. 6 | // 7 | 8 | #import "MAZeroingWeakRef.h" 9 | 10 | #import "MAZeroingWeakRefNativeZWRNotAllowedTable.h" 11 | 12 | #import 13 | 14 | #import 15 | #import 16 | #import 17 | #import 18 | #import 19 | #import 20 | 21 | 22 | /* 23 | The COREFOUNDATION_HACK_LEVEL macro allows you to control how much horrible CF 24 | hackery is enabled. The following levels are defined: 25 | 26 | 3 - Completely insane hackery allows weak references to CF objects, deallocates 27 | them asynchronously in another thread to eliminate resurrection-related race 28 | condition and crash. 29 | 30 | 2 - Full hackery allows weak references to CF objects by doing horrible 31 | things with the private CF class table. Extremely small risk of resurrection- 32 | related race condition leading to a crash. 33 | 34 | 1 - Mild hackery allows foolproof identification of CF objects and will assert 35 | if trying to make a ZWR to one. 36 | 37 | 0 - No hackery, checks for an "NSCF" prefix in the class name to identify CF 38 | objects and will assert if trying to make a ZWR to one 39 | */ 40 | #ifndef COREFOUNDATION_HACK_LEVEL 41 | #define COREFOUNDATION_HACK_LEVEL 0 42 | #endif 43 | 44 | /* 45 | The KVO_HACK_LEVEL macro allows similar control over the amount of KVO hackery. 46 | 47 | 1 - Use the private _isKVOA method to check for a KVO dynamic subclass. 48 | 49 | 0 - No hackery, uses the KVO overridden -class to check. 50 | */ 51 | #ifndef KVO_HACK_LEVEL 52 | #define KVO_HACK_LEVEL 1 53 | #endif 54 | 55 | /* 56 | The USE_BLOCKS_BASED_LOCKING macro allows control on the code structure used 57 | during lock checking. You want to disable blocks if you want your app to work 58 | on iOS 3.x devices. iOS 4.x and above can use blocks. 59 | 60 | 1 - Use blocks for lock checks. 61 | 62 | 0 - Don't use blocks for lock checks. 63 | */ 64 | #ifndef USE_BLOCKS_BASED_LOCKING 65 | #define USE_BLOCKS_BASED_LOCKING 1 66 | #endif 67 | 68 | #if KVO_HACK_LEVEL >= 1 69 | @interface NSObject (KVOPrivateMethod) 70 | 71 | - (BOOL)_isKVOA; 72 | 73 | @end 74 | #endif 75 | 76 | 77 | @interface MAZeroingWeakRef () 78 | 79 | - (void)_zeroTarget; 80 | - (void)_executeCleanupBlockWithTarget: (id)target; 81 | 82 | @end 83 | 84 | 85 | static id (*objc_loadWeak_fptr)(id *location); 86 | static id (*objc_storeWeak_fptr)(id *location, id obj); 87 | 88 | @interface _MAZeroingWeakRefCleanupHelper : NSObject 89 | { 90 | MAZeroingWeakRef *_ref; 91 | id _target; 92 | } 93 | 94 | - (id)initWithRef: (MAZeroingWeakRef *)ref target: (id)target; 95 | 96 | @end 97 | 98 | @implementation _MAZeroingWeakRefCleanupHelper 99 | 100 | - (id)initWithRef: (MAZeroingWeakRef *)ref target: (id)target 101 | { 102 | if((self = [self init])) 103 | { 104 | objc_storeWeak_fptr(&_ref, ref); 105 | _target = target; 106 | } 107 | return self; 108 | } 109 | 110 | - (void)dealloc 111 | { 112 | MAZeroingWeakRef *ref = objc_loadWeak_fptr(&_ref); 113 | [ref _executeCleanupBlockWithTarget: _target]; 114 | objc_storeWeak_fptr(&_ref, nil); 115 | 116 | [super dealloc]; 117 | } 118 | 119 | @end 120 | 121 | 122 | @implementation MAZeroingWeakRef 123 | 124 | #if COREFOUNDATION_HACK_LEVEL >= 2 125 | 126 | typedef struct __CFRuntimeClass { // Version 0 struct 127 | CFIndex version; 128 | const char *className; 129 | void (*init)(CFTypeRef cf); 130 | CFTypeRef (*copy)(CFAllocatorRef allocator, CFTypeRef cf); 131 | void (*finalize)(CFTypeRef cf); 132 | Boolean (*equal)(CFTypeRef cf1, CFTypeRef cf2); 133 | CFHashCode (*hash)(CFTypeRef cf); 134 | CFStringRef (*copyFormattingDesc)(CFTypeRef cf, CFDictionaryRef formatOptions); // str with retain 135 | CFStringRef (*copyDebugDesc)(CFTypeRef cf); // str with retain 136 | void (*reclaim)(CFTypeRef cf); 137 | } CFRuntimeClass; 138 | 139 | extern CFRuntimeClass * _CFRuntimeGetClassWithTypeID(CFTypeID typeID); 140 | 141 | typedef void (*CFFinalizeFptr)(CFTypeRef); 142 | static CFFinalizeFptr *gCFOriginalFinalizes; 143 | static size_t gCFOriginalFinalizesSize; 144 | 145 | #endif 146 | 147 | #if COREFOUNDATION_HACK_LEVEL >= 1 148 | 149 | extern Class *__CFRuntimeObjCClassTable; 150 | 151 | #endif 152 | 153 | static pthread_mutex_t gMutex; 154 | 155 | static CFMutableDictionaryRef gObjectWeakRefsMap; // maps (non-retained) objects to CFMutableSetRefs containing weak refs 156 | 157 | static NSMutableSet *gCustomSubclasses; 158 | static NSMutableDictionary *gCustomSubclassMap; // maps regular classes to their custom subclasses 159 | 160 | #if COREFOUNDATION_HACK_LEVEL >= 3 161 | static CFMutableSetRef gCFWeakTargets; 162 | static NSOperationQueue *gCFDelayedDestructionQueue; 163 | #endif 164 | 165 | + (void)initialize 166 | { 167 | if(self == [MAZeroingWeakRef class]) 168 | { 169 | pthread_mutexattr_t mutexattr; 170 | pthread_mutexattr_init(&mutexattr); 171 | pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_RECURSIVE); 172 | pthread_mutex_init(&gMutex, &mutexattr); 173 | pthread_mutexattr_destroy(&mutexattr); 174 | 175 | gObjectWeakRefsMap = CFDictionaryCreateMutable(NULL, 0, NULL, &kCFTypeDictionaryValueCallBacks); 176 | gCustomSubclasses = [[NSMutableSet alloc] init]; 177 | gCustomSubclassMap = [[NSMutableDictionary alloc] init]; 178 | 179 | // see if the 10.7 ZWR runtime functions are available 180 | // nothing special about objc_allocateClassPair, it just 181 | // seems like a reasonable and safe choice for finding 182 | // the runtime functions 183 | Dl_info info; 184 | int success = dladdr(objc_allocateClassPair, &info); 185 | if(success) 186 | { 187 | // note: we leak the handle because it's inconsequential 188 | // and technically, the fptrs would be invalid after a dlclose 189 | void *handle = dlopen(info.dli_fname, RTLD_LAZY | RTLD_GLOBAL); 190 | if(handle) 191 | { 192 | objc_loadWeak_fptr = dlsym(handle, "objc_loadWeak"); 193 | objc_storeWeak_fptr = dlsym(handle, "objc_storeWeak"); 194 | 195 | // if either one failed, make sure both are zeroed out 196 | // this is probably unnecessary, but good paranoia 197 | if(!objc_loadWeak_fptr || !objc_storeWeak_fptr) 198 | { 199 | objc_loadWeak_fptr = NULL; 200 | objc_storeWeak_fptr = NULL; 201 | } 202 | } 203 | } 204 | 205 | #if COREFOUNDATION_HACK_LEVEL >= 3 206 | gCFWeakTargets = CFSetCreateMutable(NULL, 0, NULL); 207 | gCFDelayedDestructionQueue = [[NSOperationQueue alloc] init]; 208 | #endif 209 | } 210 | } 211 | 212 | #if USE_BLOCKS_BASED_LOCKING 213 | #define BLOCK_QUALIFIER __block 214 | static void WhileLocked(void (^block)(void)) 215 | { 216 | pthread_mutex_lock(&gMutex); 217 | block(); 218 | pthread_mutex_unlock(&gMutex); 219 | } 220 | #define WhileLocked(block) WhileLocked(^block) 221 | #else 222 | #define BLOCK_QUALIFIER 223 | #define WhileLocked(block) do { \ 224 | pthread_mutex_lock(&gMutex); \ 225 | block \ 226 | pthread_mutex_unlock(&gMutex); \ 227 | } while(0) 228 | #endif 229 | 230 | static void AddWeakRefToObject(id obj, MAZeroingWeakRef *ref) 231 | { 232 | CFMutableSetRef set = (void *)CFDictionaryGetValue(gObjectWeakRefsMap, obj); 233 | if(!set) 234 | { 235 | set = CFSetCreateMutable(NULL, 0, NULL); 236 | CFDictionarySetValue(gObjectWeakRefsMap, obj, set); 237 | CFRelease(set); 238 | } 239 | CFSetAddValue(set, ref); 240 | } 241 | 242 | static void RemoveWeakRefFromObject(id obj, MAZeroingWeakRef *ref) 243 | { 244 | CFMutableSetRef set = (void *)CFDictionaryGetValue(gObjectWeakRefsMap, obj); 245 | CFSetRemoveValue(set, ref); 246 | } 247 | 248 | static void ClearWeakRefsForObject(id obj) 249 | { 250 | CFMutableSetRef set = (void *)CFDictionaryGetValue(gObjectWeakRefsMap, obj); 251 | if(set) 252 | { 253 | NSSet *setCopy = [[NSSet alloc] initWithSet: (NSSet *)set]; 254 | [setCopy makeObjectsPerformSelector: @selector(_zeroTarget)]; 255 | [setCopy makeObjectsPerformSelector: @selector(_executeCleanupBlockWithTarget:) withObject: obj]; 256 | [setCopy release]; 257 | CFDictionaryRemoveValue(gObjectWeakRefsMap, obj); 258 | } 259 | } 260 | 261 | static Class GetCustomSubclass(id obj) 262 | { 263 | Class class = object_getClass(obj); 264 | while(class && ![gCustomSubclasses containsObject: class]) 265 | class = class_getSuperclass(class); 266 | return class; 267 | } 268 | 269 | static Class GetRealSuperclass(id obj) 270 | { 271 | Class class = GetCustomSubclass(obj); 272 | NSCAssert1(class, @"Coudn't find ZeroingWeakRef subclass in hierarchy starting from %@, should never happen", object_getClass(obj)); 273 | return class_getSuperclass(class); 274 | } 275 | 276 | static void CustomSubclassRelease(id self, SEL _cmd) 277 | { 278 | Class superclass = GetRealSuperclass(self); 279 | IMP superRelease = class_getMethodImplementation(superclass, @selector(release)); 280 | WhileLocked({ 281 | ((void (*)(id, SEL))superRelease)(self, _cmd); 282 | }); 283 | } 284 | 285 | static void CustomSubclassDealloc(id self, SEL _cmd) 286 | { 287 | ClearWeakRefsForObject(self); 288 | Class superclass = GetRealSuperclass(self); 289 | IMP superDealloc = class_getMethodImplementation(superclass, @selector(dealloc)); 290 | ((void (*)(id, SEL))superDealloc)(self, _cmd); 291 | } 292 | 293 | static Class CustomSubclassClassForCoder(id self, SEL _cmd) 294 | { 295 | Class class = GetCustomSubclass(self); 296 | Class superclass = class_getSuperclass(class); 297 | IMP superClassForCoder = class_getMethodImplementation(superclass, @selector(classForCoder)); 298 | Class classForCoder = ((id (*)(id, SEL))superClassForCoder)(self, _cmd); 299 | if(classForCoder == class) 300 | classForCoder = superclass; 301 | return classForCoder; 302 | } 303 | 304 | static void KVOSubclassRelease(id self, SEL _cmd) 305 | { 306 | IMP originalRelease = class_getMethodImplementation(object_getClass(self), @selector(MAZeroingWeakRef_KVO_original_release)); 307 | WhileLocked({ 308 | ((void (*)(id, SEL))originalRelease)(self, _cmd); 309 | }); 310 | } 311 | 312 | static void KVOSubclassDealloc(id self, SEL _cmd) 313 | { 314 | ClearWeakRefsForObject(self); 315 | IMP originalDealloc = class_getMethodImplementation(object_getClass(self), @selector(MAZeroingWeakRef_KVO_original_dealloc)); 316 | ((void (*)(id, SEL))originalDealloc)(self, _cmd); 317 | } 318 | 319 | #if COREFOUNDATION_HACK_LEVEL >= 3 320 | 321 | static void CallCFReleaseLater(CFTypeRef cf) 322 | { 323 | mach_port_t thread = mach_thread_self(); // must "release" this 324 | 325 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 326 | SEL sel = @selector(releaseLater:fromThread:); 327 | NSInvocation *inv = [NSInvocation invocationWithMethodSignature: [MAZeroingWeakRef methodSignatureForSelector: sel]]; 328 | [inv setTarget: [MAZeroingWeakRef class]]; 329 | [inv setSelector: sel]; 330 | [inv setArgument: &cf atIndex: 2]; 331 | [inv setArgument: &thread atIndex: 3]; 332 | 333 | NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithInvocation: inv]; 334 | [gCFDelayedDestructionQueue addOperation: op]; 335 | [op release]; 336 | [pool release]; 337 | } 338 | 339 | static const void *kPCThreadExited = &kPCThreadExited; 340 | static const void *kPCError = NULL; 341 | 342 | static const void *GetPC(mach_port_t thread) 343 | { 344 | #if defined(__x86_64__) 345 | x86_thread_state64_t state; 346 | unsigned int count = x86_THREAD_STATE64_COUNT; 347 | thread_state_flavor_t flavor = x86_THREAD_STATE64; 348 | #define PC_REGISTER __rip 349 | #elif defined(__i386__) 350 | i386_thread_state_t state; 351 | unsigned int count = i386_THREAD_STATE_COUNT; 352 | thread_state_flavor_t flavor = i386_THREAD_STATE; 353 | #define PC_REGISTER __eip 354 | #elif defined(__arm__) 355 | arm_thread_state_t state; 356 | unsigned int count = ARM_THREAD_STATE_COUNT; 357 | thread_state_flavor_t flavor = ARM_THREAD_STATE; 358 | #define PC_REGISTER __pc 359 | #elif defined(__ppc__) 360 | ppc_thread_state_t state; 361 | unsigned int count = PPC_THREAD_STATE_COUNT; 362 | thread_state_flavor_t flavor = PPC_THREAD_STATE; 363 | #define PC_REGISTER __srr0 364 | #elif defined(__ppc64__) 365 | ppc_thread_state64_t state; 366 | unsigned int count = PPC_THREAD_STATE64_COUNT; 367 | thread_state_flavor_t flavor = PPC_THREAD_STATE64; 368 | #define PC_REGISTER __srr0 369 | #else 370 | #error don't know how to get PC for the current architecture! 371 | #endif 372 | 373 | kern_return_t ret = thread_get_state(thread, flavor, (thread_state_t)&state, &count); 374 | if(ret == KERN_SUCCESS) 375 | return (void *)state.PC_REGISTER; 376 | else if(ret == KERN_INVALID_ARGUMENT) 377 | return kPCThreadExited; 378 | else 379 | return kPCError; 380 | } 381 | 382 | static void CustomCFFinalize(CFTypeRef cf) 383 | { 384 | WhileLocked({ 385 | if(CFSetContainsValue(gCFWeakTargets, cf)) 386 | { 387 | if(CFGetRetainCount(cf) == 1) 388 | { 389 | ClearWeakRefsForObject((id)cf); 390 | CFSetRemoveValue(gCFWeakTargets, cf); 391 | CFRetain(cf); 392 | CallCFReleaseLater(cf); 393 | } 394 | } 395 | else 396 | { 397 | void (*fptr)(CFTypeRef) = gCFOriginalFinalizes[CFGetTypeID(cf)]; 398 | if(fptr) 399 | fptr(cf); 400 | } 401 | }); 402 | } 403 | 404 | #elif COREFOUNDATION_HACK_LEVEL >= 2 405 | 406 | static void CustomCFFinalize(CFTypeRef cf) 407 | { 408 | WhileLocked({ 409 | if(CFGetRetainCount(cf) == 1) 410 | { 411 | ClearWeakRefsForObject((id)cf); 412 | void (*fptr)(CFTypeRef) = gCFOriginalFinalizes[CFGetTypeID(cf)]; 413 | if(fptr) 414 | fptr(cf); 415 | } 416 | }); 417 | } 418 | #endif 419 | 420 | static BOOL IsTollFreeBridged(Class class, id obj) 421 | { 422 | #if COREFOUNDATION_HACK_LEVEL >= 1 423 | CFTypeID typeID = CFGetTypeID(obj); 424 | Class tfbClass = __CFRuntimeObjCClassTable[typeID]; 425 | return class == tfbClass; 426 | #else 427 | NSString *className = NSStringFromClass(class); 428 | return [className hasPrefix:@"NSCF"] || [className hasPrefix:@"__NSCF"]; 429 | #endif 430 | } 431 | 432 | static BOOL IsConstantObject(id obj) 433 | { 434 | unsigned int retainCount = [obj retainCount]; 435 | return retainCount == UINT_MAX || retainCount == INT_MAX; 436 | } 437 | 438 | #if COREFOUNDATION_HACK_LEVEL >= 3 439 | void _CFRelease(CFTypeRef cf); 440 | 441 | + (void)releaseLater: (CFTypeRef)cf fromThread: (mach_port_t)thread 442 | { 443 | BOOL retry = YES; 444 | 445 | while(retry) 446 | { 447 | BLOCK_QUALIFIER const void *pc; 448 | // ensure that the PC is outside our inner code when fetching it, 449 | // so we don't have to check for all the nested calls 450 | WhileLocked({ 451 | pc = GetPC(thread); 452 | }); 453 | 454 | if(pc != kPCError) 455 | { 456 | if(pc == kPCThreadExited || pc < (void *)CustomCFFinalize || pc > (void *)IsTollFreeBridged) 457 | { 458 | Dl_info info; 459 | int success = dladdr(pc, &info); 460 | if(success) 461 | { 462 | if(info.dli_saddr != _CFRelease) 463 | { 464 | retry = NO; // success! 465 | CFRelease(cf); 466 | mach_port_mod_refs(mach_task_self(), thread, MACH_PORT_RIGHT_SEND, -1 ); // "release" 467 | } 468 | } 469 | } 470 | } 471 | } 472 | } 473 | #endif 474 | 475 | static BOOL IsKVOSubclass(id obj) 476 | { 477 | #if KVO_HACK_LEVEL >= 1 478 | return [obj respondsToSelector: @selector(_isKVOA)] && [obj _isKVOA]; 479 | #else 480 | return [obj class] == class_getSuperclass(object_getClass(obj)); 481 | #endif 482 | } 483 | 484 | // The native ZWR capability table is conceptually a set of SHA1 hashes. 485 | // Hashes are used instead of class names because the table is large and 486 | // contains a lot of private classes. Embedding private class names in 487 | // the binary is likely to cause problems with app review. Manually 488 | // removing all private classes from the table is a lot of work. Using 489 | // hashes allows for reasonably quick checks and no private API names. 490 | // It's implemented as a tree of tables, where each individual table 491 | // maps to a single byte. The top level of the tree is a 256-entry table. 492 | // Table entries are a NULL pointer for leading bytes which aren't present 493 | // at all. Other table entries can either contain a pointer to another 494 | // table (in which case the process continues recursively), or they can 495 | // contain a pointer to a single hash. In this second case, this indicates 496 | // that this hash is the only one present in the table with that prefix 497 | // and so a simple comparison can be used to check for membership at 498 | // that point. 499 | static BOOL HashPresentInTable(unsigned char *hash, int length, struct _NativeZWRTableEntry *table) 500 | { 501 | while(length) 502 | { 503 | struct _NativeZWRTableEntry entry = table[hash[0]]; 504 | if(entry.ptr == NULL) 505 | { 506 | return NO; 507 | } 508 | else if(!entry.isTable) 509 | { 510 | return memcmp(entry.ptr, hash + 1, length - 1) == 0; 511 | } 512 | else 513 | { 514 | hash++; 515 | length--; 516 | table = entry.ptr; 517 | } 518 | } 519 | return NO; 520 | } 521 | 522 | static BOOL CanNativeZWRClass(Class c) 523 | { 524 | if(!c) 525 | return YES; 526 | 527 | const char *name = class_getName(c); 528 | unsigned char hash[CC_SHA1_DIGEST_LENGTH]; 529 | CC_SHA1(name, strlen(name), hash); 530 | 531 | if(HashPresentInTable(hash, CC_SHA1_DIGEST_LENGTH, _MAZeroingWeakRefClassNativeWeakReferenceNotAllowedTable)) 532 | return NO; 533 | else 534 | return CanNativeZWRClass(class_getSuperclass(c)); 535 | } 536 | 537 | static BOOL CanNativeZWR(id obj) 538 | { 539 | return CanNativeZWRClass(object_getClass(obj)); 540 | } 541 | 542 | static Class CreatePlainCustomSubclass(Class class) 543 | { 544 | NSString *newName = [NSString stringWithFormat: @"%s_MAZeroingWeakRefSubclass", class_getName(class)]; 545 | const char *newNameC = [newName UTF8String]; 546 | 547 | Class subclass = objc_allocateClassPair(class, newNameC, 0); 548 | 549 | Method release = class_getInstanceMethod(class, @selector(release)); 550 | Method dealloc = class_getInstanceMethod(class, @selector(dealloc)); 551 | Method classForCoder = class_getInstanceMethod(class, @selector(classForCoder)); 552 | class_addMethod(subclass, @selector(release), (IMP)CustomSubclassRelease, method_getTypeEncoding(release)); 553 | class_addMethod(subclass, @selector(dealloc), (IMP)CustomSubclassDealloc, method_getTypeEncoding(dealloc)); 554 | class_addMethod(subclass, @selector(classForCoder), (IMP)CustomSubclassClassForCoder, method_getTypeEncoding(classForCoder)); 555 | 556 | objc_registerClassPair(subclass); 557 | 558 | return subclass; 559 | } 560 | 561 | static void PatchKVOSubclass(Class class) 562 | { 563 | NSLog(@"Patching KVO class %s", class_getName(class)); 564 | Method release = class_getInstanceMethod(class, @selector(release)); 565 | Method dealloc = class_getInstanceMethod(class, @selector(dealloc)); 566 | 567 | class_addMethod(class, @selector(MAZeroingWeakRef_KVO_original_release), method_getImplementation(release), method_getTypeEncoding(release)); 568 | class_addMethod(class, @selector(MAZeroingWeakRef_KVO_original_dealloc), method_getImplementation(dealloc), method_getTypeEncoding(dealloc)); 569 | 570 | class_replaceMethod(class, @selector(release), (IMP)KVOSubclassRelease, method_getTypeEncoding(release)); 571 | class_replaceMethod(class, @selector(dealloc), (IMP)KVOSubclassDealloc, method_getTypeEncoding(dealloc)); 572 | } 573 | 574 | static void RegisterCustomSubclass(Class subclass, Class superclass) 575 | { 576 | [gCustomSubclassMap setObject: subclass forKey: (id)superclass]; 577 | [gCustomSubclasses addObject: subclass]; 578 | } 579 | 580 | static Class CreateCustomSubclass(Class class, id obj) 581 | { 582 | if(IsTollFreeBridged(class, obj)) 583 | { 584 | #if COREFOUNDATION_HACK_LEVEL >= 2 585 | CFTypeID typeID = CFGetTypeID(obj); 586 | CFRuntimeClass *cfclass = _CFRuntimeGetClassWithTypeID(typeID); 587 | 588 | if(typeID >= gCFOriginalFinalizesSize) 589 | { 590 | gCFOriginalFinalizesSize = typeID + 1; 591 | gCFOriginalFinalizes = realloc(gCFOriginalFinalizes, gCFOriginalFinalizesSize * sizeof(*gCFOriginalFinalizes)); 592 | } 593 | 594 | do { 595 | gCFOriginalFinalizes[typeID] = cfclass->finalize; 596 | } while(!OSAtomicCompareAndSwapPtrBarrier(gCFOriginalFinalizes[typeID], CustomCFFinalize, (void *)&cfclass->finalize)); 597 | #else 598 | NSCAssert2(0, @"Cannot create zeroing weak reference to object of type %@ with COREFOUNDATION_HACK_LEVEL set to %d", class, COREFOUNDATION_HACK_LEVEL); 599 | #endif 600 | return class; 601 | } 602 | else if(IsKVOSubclass(obj)) 603 | { 604 | PatchKVOSubclass(class); 605 | return class; 606 | } 607 | else 608 | { 609 | return CreatePlainCustomSubclass(class); 610 | } 611 | } 612 | 613 | static void EnsureCustomSubclass(id obj) 614 | { 615 | if(!GetCustomSubclass(obj) && !IsConstantObject(obj)) 616 | { 617 | Class class = object_getClass(obj); 618 | Class subclass = [gCustomSubclassMap objectForKey: class]; 619 | if(!subclass) 620 | { 621 | subclass = CreateCustomSubclass(class, obj); 622 | RegisterCustomSubclass(subclass, class); 623 | } 624 | 625 | // only set the class if the current one is its superclass 626 | // otherwise it's possible that it returns something farther up in the hierarchy 627 | // and so there's no need to set it then 628 | if(class_getSuperclass(subclass) == class) 629 | object_setClass(obj, subclass); 630 | } 631 | } 632 | 633 | static void RegisterRef(MAZeroingWeakRef *ref, id target) 634 | { 635 | WhileLocked({ 636 | EnsureCustomSubclass(target); 637 | AddWeakRefToObject(target, ref); 638 | #if COREFOUNDATION_HACK_LEVEL >= 3 639 | if(IsTollFreeBridged(object_getClass(target), target)) 640 | CFSetAddValue(gCFWeakTargets, target); 641 | #endif 642 | }); 643 | } 644 | 645 | static void UnregisterRef(MAZeroingWeakRef *ref) 646 | { 647 | WhileLocked({ 648 | id target = ref->_target; 649 | 650 | if(target) 651 | RemoveWeakRefFromObject(target, ref); 652 | }); 653 | } 654 | 655 | + (BOOL)canRefCoreFoundationObjects 656 | { 657 | return COREFOUNDATION_HACK_LEVEL >= 2 || objc_storeWeak_fptr; 658 | } 659 | 660 | + (id)refWithTarget: (id)target 661 | { 662 | return [[[self alloc] initWithTarget: target] autorelease]; 663 | } 664 | 665 | - (id)initWithTarget: (id)target 666 | { 667 | if((self = [self init])) 668 | { 669 | if(objc_storeWeak_fptr && CanNativeZWR(target)) 670 | { 671 | objc_storeWeak_fptr(&_target, target); 672 | _nativeZWR = YES; 673 | } 674 | else 675 | { 676 | _target = target; 677 | RegisterRef(self, target); 678 | } 679 | } 680 | return self; 681 | } 682 | 683 | - (void)dealloc 684 | { 685 | if(objc_storeWeak_fptr && _nativeZWR) 686 | objc_storeWeak_fptr(&_target, nil); 687 | else 688 | UnregisterRef(self); 689 | 690 | #if NS_BLOCKS_AVAILABLE 691 | [_cleanupBlock release]; 692 | #endif 693 | [super dealloc]; 694 | } 695 | 696 | - (NSString *)description 697 | { 698 | return [NSString stringWithFormat: @"<%@: %p -> %@>", [self class], self, [self target]]; 699 | } 700 | 701 | #if NS_BLOCKS_AVAILABLE 702 | - (void)setCleanupBlock: (void (^)(id target))block 703 | { 704 | block = [block copy]; 705 | [_cleanupBlock release]; 706 | _cleanupBlock = block; 707 | 708 | if(objc_loadWeak_fptr && _nativeZWR) 709 | { 710 | // wrap a pool around this code, otherwise it artificially extends 711 | // the lifetime of the target object 712 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 713 | 714 | id target = [self target]; 715 | if(target != nil) @synchronized(target) 716 | { 717 | static void *associatedKey = &associatedKey; 718 | NSMutableSet *cleanupHelpers = objc_getAssociatedObject(target, associatedKey); 719 | 720 | if(cleanupHelpers == nil) 721 | { 722 | cleanupHelpers = [NSMutableSet set]; 723 | objc_setAssociatedObject(target, associatedKey, cleanupHelpers, OBJC_ASSOCIATION_RETAIN); 724 | } 725 | 726 | _MAZeroingWeakRefCleanupHelper *helper = [[_MAZeroingWeakRefCleanupHelper alloc] initWithRef: self target: target]; 727 | [cleanupHelpers addObject:helper]; 728 | 729 | [helper release]; 730 | } 731 | 732 | [pool release]; 733 | } 734 | } 735 | #endif 736 | 737 | - (id)target 738 | { 739 | if(objc_loadWeak_fptr && _nativeZWR) 740 | { 741 | return objc_loadWeak_fptr(&_target); 742 | } 743 | else 744 | { 745 | BLOCK_QUALIFIER id ret; 746 | WhileLocked({ 747 | ret = [_target retain]; 748 | }); 749 | return [ret autorelease]; 750 | } 751 | } 752 | 753 | - (void)_zeroTarget 754 | { 755 | _target = nil; 756 | } 757 | 758 | - (void)_executeCleanupBlockWithTarget: (id)target 759 | { 760 | #if NS_BLOCKS_AVAILABLE 761 | if(_cleanupBlock) 762 | { 763 | _cleanupBlock(target); 764 | [_cleanupBlock release]; 765 | _cleanupBlock = nil; 766 | } 767 | #endif 768 | } 769 | 770 | @end 771 | -------------------------------------------------------------------------------- /PLWeakCompatibility/MAZeroingWeakRefNativeZWRNotAllowedTable.h: -------------------------------------------------------------------------------- 1 | static void *_MAZeroingWeakRefClassPresentToken = &_MAZeroingWeakRefClassPresentToken; 2 | struct _NativeZWRTableEntry { BOOL isTable; void *ptr; }; 3 | static struct _NativeZWRTableEntry _MAZeroingWeakRefClassNativeWeakReferenceNotAllowedTable[256] = { 4 | [0x3] = { 0, (unsigned char[]){ 0x5b, 0x81, 0x42, 0xa2, 0xe, 0x20, 0xd7, 0x39, 0xf1, 0xa4, 0xa8, 0x21, 0x86, 0x1d, 0xdc, 0xa5, 0xef, 0x9, 0x34 } }, // NSTableCellView 5 | [0x5] = { 1, (struct _NativeZWRTableEntry[256]) { // 1 6 | [0xa] = { 0, (unsigned char[]){ 0x5a, 0x2f, 0xc3, 0xa6, 0xd5, 0xfb, 0xcf, 0xcc, 0x85, 0xf2, 0x2f, 0xea, 0x16, 0xeb, 0xbf, 0xcf, 0x9e, 0x52 } }, // NSBlock 7 | [0x83] = { 0, (unsigned char[]){ 0xae, 0xc5, 0x56, 0x5, 0xce, 0xb3, 0xd5, 0x18, 0xe9, 0x30, 0xb7, 0x70, 0xf4, 0x78, 0xc9, 0xaf, 0xdd, 0x54 } }, // NSISNonNegativeVariableToBeMinimized 8 | }}, 9 | [0x7] = { 1, (struct _NativeZWRTableEntry[256]) { // 1 10 | [0xf] = { 0, (unsigned char[]){ 0x52, 0xec, 0xf7, 0xb1, 0xe5, 0x2a, 0x7c, 0x39, 0xd4, 0x61, 0x17, 0x76, 0x26, 0x8e, 0x7a, 0x5c, 0x8f, 0xb2 } }, // NSISObjectiveVariable 11 | [0x40] = { 0, (unsigned char[]){ 0x46, 0xca, 0xad, 0x6d, 0xcc, 0x49, 0x26, 0x3c, 0x81, 0xb8, 0xb, 0xe7, 0x21, 0xcc, 0x28, 0xcf, 0xc3, 0x24 } }, // NSATSGlyphStorage 12 | }}, 13 | [0x8] = { 0, (unsigned char[]){ 0x82, 0x50, 0x66, 0x55, 0x76, 0x98, 0xb5, 0xb8, 0x56, 0x20, 0xd6, 0x1c, 0x7, 0x55, 0x4e, 0x32, 0xe0, 0xb1, 0x33 } }, // NSViewHierarchyLock 14 | [0x9] = { 0, (unsigned char[]){ 0x11, 0x7b, 0x21, 0x90, 0x28, 0xc0, 0x39, 0x90, 0x9b, 0xc5, 0xa9, 0xf, 0xaf, 0x8, 0x43, 0x9e, 0xb9, 0x9d, 0xc3 } }, // NSTableOptions 15 | [0xf] = { 0, (unsigned char[]){ 0x7d, 0x56, 0x74, 0xad, 0x93, 0x48, 0xe2, 0xbd, 0x2b, 0x5c, 0xb4, 0xf6, 0xf8, 0xd2, 0xfc, 0x47, 0xc0, 0xf4, 0xb9 } }, // _NSQuickLookWrapperDocumentWindow 16 | [0x11] = { 0, (unsigned char[]){ 0xa3, 0x61, 0xe2, 0x7d, 0xb1, 0x3e, 0xe4, 0xe1, 0xd1, 0x7a, 0xd, 0xc4, 0x74, 0x52, 0x76, 0xb0, 0xb5, 0x7e, 0xb3 } }, // _NSScalarObjectID 17 | [0x1a] = { 1, (struct _NativeZWRTableEntry[256]) { // 1 18 | [0x44] = { 0, (unsigned char[]){ 0x3b, 0x91, 0x94, 0xd2, 0x34, 0x5e, 0x4a, 0x18, 0xd9, 0x71, 0x17, 0x2c, 0xc4, 0xfa, 0x5a, 0x71, 0x4c, 0xb5 } }, // NSCorrectionSubPanel 19 | [0xda] = { 0, (unsigned char[]){ 0x11, 0x4, 0xac, 0x59, 0xce, 0x58, 0x99, 0x8, 0x5, 0xae, 0xc7, 0x9f, 0x5f, 0x7c, 0x1e, 0xab, 0xf3, 0x12 } }, // NSISNonNegativeVariableWithDelegate 20 | }}, 21 | [0x1c] = { 0, (unsigned char[]){ 0x90, 0xdf, 0xd3, 0x6e, 0xb0, 0x87, 0xd6, 0xc4, 0xa4, 0x33, 0xd9, 0x9f, 0xf9, 0xde, 0x69, 0xf4, 0x80, 0x7d, 0xf4 } }, // NSCorrectionPanel 22 | [0x1d] = { 0, (unsigned char[]){ 0xfc, 0x3e, 0x70, 0x29, 0x9a, 0x6f, 0xbe, 0x9a, 0x3e, 0xe7, 0x56, 0x1e, 0x64, 0x13, 0xe9, 0x6a, 0xfd, 0xc9, 0xcd } }, // __NSSharedFontInstanceInfo 23 | [0x1f] = { 1, (struct _NativeZWRTableEntry[256]) { // 1 24 | [0x3a] = { 0, (unsigned char[]){ 0x80, 0xbb, 0xa7, 0xc1, 0x41, 0xc9, 0xa5, 0x87, 0x46, 0x6c, 0xe8, 0x53, 0xf, 0x31, 0x2c, 0xe4, 0x82, 0xed } }, // NSToolbarConfigPanel 25 | [0xf5] = { 0, (unsigned char[]){ 0x26, 0xc2, 0x40, 0xf7, 0x91, 0x16, 0x9f, 0x23, 0x4e, 0x23, 0xa4, 0xfd, 0xcf, 0xe0, 0xb7, 0x12, 0xbe, 0x5 } }, // _NSBrowserTableColumnViewController 26 | }}, 27 | [0x20] = { 0, (unsigned char[]){ 0x45, 0xd6, 0x66, 0x4e, 0xd3, 0x46, 0xa2, 0x31, 0xbc, 0xd4, 0x91, 0xbb, 0xc6, 0x7f, 0xaf, 0x9a, 0x16, 0xf3, 0x55 } }, // NSSpellingPanel 28 | [0x24] = { 0, (unsigned char[]){ 0x97, 0x38, 0x41, 0x2b, 0xe7, 0x18, 0x67, 0x62, 0x5, 0xdd, 0xdf, 0xc1, 0x57, 0x59, 0x49, 0xc4, 0x16, 0x32, 0x94 } }, // NSISVariableWithDelegate 29 | [0x2b] = { 0, (unsigned char[]){ 0x1, 0xdd, 0xee, 0xa6, 0x38, 0xdf, 0x45, 0x52, 0x1, 0xa3, 0x33, 0x18, 0x2a, 0x2e, 0x17, 0x5, 0x96, 0x81, 0x4a } }, // NSManagedObjectID 30 | [0x2d] = { 0, (unsigned char[]){ 0xb6, 0x84, 0x6b, 0x6a, 0xe6, 0x48, 0x56, 0xb4, 0xb8, 0xae, 0x9, 0x8f, 0x88, 0xd4, 0x9f, 0x71, 0x8d, 0x2b, 0xf4 } }, // NSSecureTextView 31 | [0x33] = { 0, (unsigned char[]){ 0x46, 0x16, 0x4e, 0xe1, 0x47, 0x1a, 0x32, 0x82, 0x6e, 0xae, 0x61, 0xed, 0xf8, 0xe, 0x27, 0xa8, 0x76, 0xda, 0x8 } }, // __NSFontTypefaceInfo 32 | [0x35] = { 0, (unsigned char[]){ 0xc2, 0x5e, 0x22, 0xd0, 0x4b, 0x59, 0x4a, 0xfe, 0xc7, 0xb2, 0xc, 0xb5, 0x8d, 0x7, 0x4b, 0xee, 0x4a, 0x35, 0x52 } }, // _NSFullScreenUnbufferedWindow 33 | [0x37] = { 1, (struct _NativeZWRTableEntry[256]) { // 1 34 | [0x6f] = { 0, (unsigned char[]){ 0x70, 0x43, 0x47, 0x3f, 0x14, 0x9b, 0xf8, 0x1e, 0x57, 0xcb, 0x40, 0xd6, 0x54, 0xd4, 0xd1, 0x6f, 0xc6, 0x5e } }, // _NSSlideAndCrossFadeAnimationProjectionWindow 35 | [0x72] = { 0, (unsigned char[]){ 0x9b, 0xcf, 0x5f, 0xcf, 0x88, 0x75, 0x72, 0x8e, 0xf1, 0x6c, 0xe5, 0xc8, 0x62, 0xc5, 0x5f, 0xe2, 0xcd, 0x5c } }, // NSNavNodeSharedServerController 36 | }}, 37 | [0x38] = { 0, (unsigned char[]){ 0x60, 0x5c, 0x3f, 0xa3, 0xb, 0xc3, 0x8d, 0x3e, 0x7, 0x33, 0x1e, 0x54, 0xf3, 0xed, 0x88, 0x29, 0xe, 0xaf, 0xc3 } }, // NSNavFilepathInputController 38 | [0x3a] = { 1, (struct _NativeZWRTableEntry[256]) { // 1 39 | [0x19] = { 0, (unsigned char[]){ 0x21, 0x87, 0xa7, 0x0, 0x57, 0xb5, 0x54, 0xdf, 0x53, 0x50, 0x57, 0xe7, 0x88, 0xf6, 0x85, 0x3d, 0x5e, 0x73 } }, // _NSBrowserMatrixColumnViewController 40 | [0x29] = { 0, (unsigned char[]){ 0x2f, 0x44, 0xd9, 0xeb, 0x81, 0x1e, 0x89, 0x21, 0x38, 0x1a, 0xd1, 0x36, 0xf5, 0x1b, 0xb1, 0xf, 0xe2, 0xa5 } }, // NSAttributeDictionary 41 | }}, 42 | [0x3d] = { 0, (unsigned char[]){ 0x84, 0x79, 0x16, 0x14, 0xdb, 0x72, 0x27, 0x5, 0xb1, 0x2b, 0x8c, 0xed, 0xfb, 0x1f, 0xe6, 0x65, 0x9b, 0xa3, 0x32 } }, // NSISVariable 43 | [0x42] = { 0, (unsigned char[]){ 0x6e, 0xba, 0xa0, 0x45, 0x15, 0x86, 0x37, 0x4b, 0x30, 0x48, 0xe, 0x7b, 0xaf, 0xa, 0xd2, 0x75, 0x43, 0x10, 0xfb } }, // NSTableOptionsPanel 44 | [0x43] = { 0, (unsigned char[]){ 0xac, 0xfb, 0xb9, 0xaa, 0xde, 0xc7, 0xe3, 0xe0, 0x91, 0x32, 0x60, 0xad, 0xfe, 0xd2, 0x44, 0xfe, 0x75, 0xbc, 0x6b } }, // NSAccessoryWindow 45 | [0x44] = { 0, (unsigned char[]){ 0xe4, 0x9e, 0x1b, 0x5, 0xa9, 0x34, 0xa9, 0xd9, 0xc5, 0xa7, 0x5, 0x16, 0x3d, 0x4f, 0x15, 0x41, 0xa8, 0x45, 0x24 } }, // __NSOperationInternal 46 | [0x45] = { 0, (unsigned char[]){ 0xb8, 0xcb, 0x9f, 0xea, 0x3a, 0xf2, 0xe3, 0x30, 0x9d, 0x53, 0xc5, 0x36, 0x95, 0x4a, 0x69, 0x55, 0xea, 0x85, 0xee } }, // NSNavSharedServerController 47 | [0x48] = { 0, (unsigned char[]){ 0x57, 0x8c, 0x37, 0xc5, 0x34, 0x5, 0x21, 0x89, 0x5c, 0x4b, 0x15, 0x7, 0x9c, 0xb8, 0xff, 0x7b, 0x6e, 0xf1, 0xae } }, // NSWindow 48 | [0x4a] = { 1, (struct _NativeZWRTableEntry[256]) { // 1 49 | [0xc] = { 0, (unsigned char[]){ 0xcd, 0x9e, 0xea, 0x1e, 0x8a, 0xea, 0xf, 0x0, 0xf3, 0xe7, 0x33, 0xb1, 0x6f, 0x5b, 0x42, 0x55, 0x55, 0x45 } }, // NSStringDrawingTextStorage 50 | [0x3e] = { 0, (unsigned char[]){ 0xc4, 0xeb, 0x56, 0x8b, 0x5, 0x8a, 0xbb, 0xbe, 0xa0, 0xdb, 0x58, 0xd2, 0x5b, 0x99, 0xef, 0xc, 0x36, 0xc0 } }, // NSDocumentRevisionsTimelineWindow 51 | }}, 52 | [0x4c] = { 0, (unsigned char[]){ 0x96, 0x73, 0x2, 0xb9, 0x44, 0xe3, 0x1f, 0xb, 0xaf, 0xab, 0xba, 0xf0, 0x1c, 0x1c, 0x12, 0x0, 0xb7, 0x86, 0xbf } }, // NSLocalWindowWrappingRemoteWindow 53 | [0x4d] = { 0, (unsigned char[]){ 0xb2, 0x61, 0xa9, 0x77, 0x21, 0xee, 0x44, 0x1c, 0x86, 0xdc, 0xcd, 0x68, 0x7c, 0x6f, 0x6d, 0xf2, 0x93, 0xed, 0x1e } }, // NSNavAdvancedSearchController 54 | [0x4e] = { 1, (struct _NativeZWRTableEntry[256]) { // 1 55 | [0xaa] = { 0, (unsigned char[]){ 0x67, 0xf8, 0xa5, 0xc8, 0x3e, 0x19, 0x3f, 0xc0, 0x9, 0x59, 0x79, 0x51, 0xa0, 0x8e, 0xeb, 0xfb, 0x77, 0x26 } }, // _CTNativeGlyphStorage 56 | [0xd7] = { 0, (unsigned char[]){ 0xfc, 0xdd, 0x19, 0x16, 0xed, 0x7e, 0x9e, 0x83, 0x8e, 0x25, 0x5c, 0xa6, 0xe6, 0xe, 0xe1, 0x36, 0xc3, 0xb1 } }, // NSTokenTextView 57 | }}, 58 | [0x50] = { 0, (unsigned char[]){ 0xb2, 0x2e, 0x2a, 0x97, 0xb4, 0x8, 0x61, 0xa9, 0x51, 0x72, 0x20, 0x74, 0xbf, 0x85, 0xe4, 0x54, 0xb3, 0x1a, 0x24 } }, // _NSCoreManagedObjectID 59 | [0x52] = { 0, (unsigned char[]){ 0xb4, 0xcf, 0x19, 0x47, 0xb8, 0xd5, 0x65, 0x56, 0x75, 0xc0, 0x46, 0xd4, 0x3c, 0x9a, 0xf2, 0x21, 0x2f, 0xc5, 0xca } }, // _PFManagedObjectReferenceQueue 60 | [0x53] = { 0, (unsigned char[]){ 0x4d, 0xe5, 0x8d, 0xa1, 0x40, 0xcb, 0x7a, 0x1a, 0x27, 0xd3, 0x89, 0x24, 0x39, 0xda, 0xd1, 0x46, 0x1c, 0xf0, 0x84 } }, // NSProgressPanel 61 | [0x54] = { 1, (struct _NativeZWRTableEntry[256]) { // 1 62 | [0x77] = { 0, (unsigned char[]){ 0x65, 0xbb, 0x28, 0x9e, 0xbd, 0x9f, 0x5d, 0xc, 0x39, 0x70, 0x5b, 0xe7, 0x65, 0xcc, 0x3c, 0xcc, 0x4a, 0x6 } }, // NSMessagePort 63 | [0xa4] = { 0, (unsigned char[]){ 0x4f, 0x92, 0x89, 0xe2, 0x3b, 0x49, 0x6e, 0x70, 0xe1, 0x75, 0x90, 0x79, 0xbb, 0x53, 0x5f, 0x4f, 0xcc, 0x3e } }, // NSColorPopoverController 64 | }}, 65 | [0x59] = { 0, (unsigned char[]){ 0xed, 0xef, 0x25, 0x8c, 0xc5, 0x35, 0xe7, 0xa3, 0xa7, 0x5a, 0xcc, 0xd3, 0x75, 0x8, 0x43, 0xb2, 0xa, 0xee, 0xb2 } }, // NSPort 66 | [0x5b] = { 0, (unsigned char[]){ 0x8a, 0x1d, 0xa9, 0x7e, 0x72, 0x5d, 0x70, 0x81, 0xcf, 0xc, 0xe0, 0xb8, 0x73, 0x8f, 0x5c, 0x85, 0xd6, 0xa1, 0xe1 } }, // _NSBrowserPreviewColumnViewController 67 | [0x5f] = { 1, (struct _NativeZWRTableEntry[256]) { // 1 68 | [0x22] = { 0, (unsigned char[]){ 0x72, 0x59, 0x13, 0xf8, 0x71, 0xdb, 0x3a, 0xbe, 0xa0, 0x1b, 0xaf, 0xed, 0x76, 0xb, 0x9a, 0xf3, 0x5e, 0xd8 } }, // NSBasicObjectID 69 | [0xc0] = { 0, (unsigned char[]){ 0x5e, 0x88, 0x3a, 0xb1, 0x91, 0x9c, 0xf9, 0x9d, 0x19, 0xfe, 0x79, 0xa9, 0x8f, 0x7a, 0x42, 0x3, 0x7c, 0x72 } }, // _NSSavePanelTextView 70 | }}, 71 | [0x67] = { 0, (unsigned char[]){ 0xae, 0xaf, 0x59, 0x8c, 0xa3, 0x4a, 0xf8, 0xe9, 0xa, 0xe8, 0x7c, 0x18, 0x48, 0x0, 0x34, 0xbc, 0x4a, 0x69, 0x40 } }, // NSRulerMarkerPanel 72 | [0x68] = { 0, (unsigned char[]){ 0x3a, 0x65, 0xf1, 0xba, 0x6a, 0x7f, 0xa7, 0xfb, 0x12, 0xe4, 0x1f, 0x53, 0x25, 0xad, 0x74, 0x88, 0xd, 0x73, 0x30 } }, // NSStatusBarWindow 73 | [0x69] = { 0, (unsigned char[]){ 0x20, 0xef, 0xa7, 0x58, 0xa2, 0x8c, 0xc3, 0x20, 0xa1, 0xb8, 0xcd, 0x75, 0x46, 0x40, 0xfc, 0x5, 0xae, 0x61, 0xa } }, // NSToolbarFullScreenWindow 74 | [0x6a] = { 1, (struct _NativeZWRTableEntry[256]) { // 1 75 | [0x16] = { 0, (unsigned char[]){ 0xaf, 0x44, 0x1, 0x18, 0x5e, 0x88, 0x4d, 0x10, 0x1c, 0x26, 0x2b, 0xf7, 0xca, 0xf4, 0x9, 0xb, 0x24, 0x8e } }, // NSCarbonWindow 76 | [0x72] = { 0, (unsigned char[]){ 0x94, 0xde, 0xb9, 0xc4, 0x93, 0x86, 0xcc, 0x88, 0x1e, 0x3, 0x8b, 0x7f, 0x72, 0x7c, 0x51, 0x96, 0xfb, 0xba } }, // NSPrintPreviewController 77 | }}, 78 | [0x6e] = { 0, (unsigned char[]){ 0x7, 0x4a, 0x8f, 0xd5, 0xad, 0xa6, 0xbf, 0x62, 0x15, 0x49, 0x9a, 0x98, 0xfb, 0x9e, 0x6c, 0x9a, 0x29, 0x5e, 0x45 } }, // NSTextView 79 | [0x6f] = { 1, (struct _NativeZWRTableEntry[256]) { // 1 80 | [0x34] = { 0, (unsigned char[]){ 0x15, 0x3d, 0x33, 0x27, 0xe2, 0x98, 0x15, 0x6b, 0xd, 0xc5, 0xb0, 0x9, 0x8e, 0x8b, 0x22, 0x40, 0x88, 0x9c } }, // __NSATSStringSegment 81 | [0xc5] = { 0, (unsigned char[]){ 0x6c, 0x2c, 0x2c, 0x37, 0xe2, 0x89, 0x72, 0x56, 0xb3, 0x7d, 0xb6, 0x2d, 0x67, 0x4c, 0xd0, 0x5f, 0x55, 0xc1 } }, // NSSubTextStorage 82 | }}, 83 | [0x72] = { 0, (unsigned char[]){ 0x8d, 0x27, 0x74, 0x97, 0x62, 0x6, 0x8b, 0x6b, 0xec, 0x92, 0x51, 0x4a, 0xbd, 0x43, 0xc8, 0xaa, 0x6c, 0x58, 0x9 } }, // NSTextViewCompletionWindow 84 | [0x73] = { 0, (unsigned char[]){ 0xb1, 0xc6, 0x4b, 0x54, 0xb0, 0x56, 0x42, 0x26, 0xd0, 0xc, 0xf4, 0x28, 0x23, 0x12, 0x37, 0xad, 0xb4, 0x7d, 0xac } }, // _NSFullScreenTransitionOverlayWindow 85 | [0x75] = { 0, (unsigned char[]){ 0x4b, 0xe3, 0x5c, 0xb0, 0x20, 0x14, 0xca, 0x8c, 0x61, 0x60, 0xdc, 0x7a, 0xee, 0xf, 0x88, 0x19, 0x9f, 0xa7, 0x68 } }, // _PFTask 86 | [0x76] = { 0, (unsigned char[]){ 0xf5, 0x2d, 0xe3, 0x23, 0x10, 0x98, 0x61, 0xac, 0x59, 0x99, 0x59, 0xda, 0x3d, 0x8d, 0xa6, 0xa, 0x67, 0x37, 0xc0 } }, // NSParagraphStyle 87 | [0x77] = { 0, (unsigned char[]){ 0xe0, 0xd5, 0x7, 0x83, 0xa7, 0x2e, 0x7e, 0xba, 0xac, 0x6a, 0xaa, 0x97, 0x47, 0x4f, 0xb4, 0x26, 0xe8, 0xd5, 0xca } }, // _NSOrderOutAnimationProxyWindow 88 | [0x7c] = { 0, (unsigned char[]){ 0xdd, 0x75, 0x76, 0xb0, 0xb1, 0xfc, 0xcb, 0x3e, 0xd7, 0x51, 0xe3, 0xf4, 0x93, 0x78, 0xd5, 0x27, 0xc2, 0x4c, 0xc4 } }, // NSPrintPanelOldAccessoryController 89 | [0x7d] = { 0, (unsigned char[]){ 0x76, 0x18, 0xf6, 0x67, 0x49, 0xf0, 0x27, 0xd0, 0x31, 0x14, 0xf3, 0xce, 0x4d, 0x6e, 0x95, 0x26, 0x95, 0xa1, 0xb9 } }, // NSNavProgressStatusViewController 90 | [0x7f] = { 1, (struct _NativeZWRTableEntry[256]) { // 1 91 | [0x18] = { 0, (unsigned char[]){ 0x3a, 0xe7, 0x3a, 0x47, 0xa1, 0x86, 0x5c, 0x8b, 0x3d, 0xad, 0x74, 0xe7, 0x7b, 0xa3, 0x71, 0xce, 0xb6, 0xed } }, // NSWindowController 92 | [0xb5] = { 0, (unsigned char[]){ 0x68, 0x7e, 0xc6, 0xa1, 0xb8, 0x14, 0xb3, 0x1b, 0xd2, 0xec, 0xce, 0x99, 0x3e, 0x3, 0x72, 0x1d, 0x17, 0xce } }, // NSTextTab 93 | }}, 94 | [0x83] = { 0, (unsigned char[]){ 0x11, 0x3f, 0x29, 0x8e, 0x75, 0xfa, 0x19, 0xca, 0x82, 0x5f, 0xc, 0xe6, 0x40, 0x60, 0x99, 0xa5, 0xcc, 0xb0, 0xd5 } }, // _NSFullScreenWindow 95 | [0x84] = { 0, (unsigned char[]){ 0x5d, 0x46, 0x99, 0xf2, 0x6f, 0x3e, 0x70, 0xd0, 0x7, 0x4, 0x32, 0x68, 0x82, 0x5d, 0xad, 0xdb, 0x5d, 0x96, 0x89 } }, // NSISNonNegativeMarkerVariable 96 | [0x89] = { 0, (unsigned char[]){ 0xe8, 0x30, 0xee, 0xf9, 0x87, 0x23, 0xd7, 0x55, 0x41, 0x71, 0xfe, 0xbd, 0x6a, 0x6a, 0x9, 0xf8, 0xa8, 0xa9, 0xb0 } }, // NSCarbonMenuWindow 97 | [0x8e] = { 0, (unsigned char[]){ 0x3c, 0x39, 0xef, 0xfb, 0x5e, 0xbf, 0xfc, 0x69, 0x9f, 0xdb, 0xd7, 0x4c, 0x97, 0xaf, 0x9f, 0xc7, 0xbf, 0xe7, 0x5 } }, // __NSFinalizingBlock 98 | [0x91] = { 0, (unsigned char[]){ 0x29, 0xe6, 0xff, 0x9c, 0xa8, 0x1b, 0x78, 0x33, 0x5e, 0xf5, 0xd6, 0xf6, 0xf3, 0x34, 0xa9, 0x27, 0x68, 0xdc, 0x48 } }, // NSISNonNegativeVariableWithDelegateToBeMinimized 99 | [0x93] = { 0, (unsigned char[]){ 0x6b, 0x15, 0xf9, 0xf2, 0xb9, 0xfb, 0x86, 0x42, 0xb2, 0x9d, 0x76, 0xaa, 0x9a, 0x3e, 0xaf, 0x47, 0x3b, 0x4b, 0x97 } }, // _NSDuplicateDocumentAnimationProjectionWindow 100 | [0x95] = { 1, (struct _NativeZWRTableEntry[256]) { // 1 101 | [0x1f] = { 0, (unsigned char[]){ 0xc2, 0x2d, 0x6b, 0x81, 0x8b, 0xc6, 0x6d, 0x62, 0x89, 0x92, 0x68, 0x5f, 0x4b, 0x54, 0x74, 0xbc, 0x1b, 0x43 } }, // NSExceptionAlertController 102 | [0xca] = { 0, (unsigned char[]){ 0x6b, 0x18, 0xe4, 0xc5, 0xf8, 0x35, 0xae, 0x2c, 0xc1, 0x2c, 0xdc, 0xcd, 0xec, 0x4e, 0xca, 0x76, 0x94, 0x6 } }, // NSColorSpace 103 | }}, 104 | [0x96] = { 0, (unsigned char[]){ 0x9f, 0x99, 0xf9, 0x49, 0x2a, 0xc, 0xfe, 0x8, 0x4e, 0xed, 0xd4, 0x2b, 0x69, 0x39, 0xef, 0x12, 0xba, 0x18, 0x2 } }, // NSToolTipPanel 105 | [0x97] = { 0, (unsigned char[]){ 0x20, 0x8, 0xb2, 0x87, 0x77, 0xe3, 0xa4, 0x7e, 0xbe, 0x34, 0x6f, 0x84, 0x29, 0xa6, 0x21, 0x2a, 0x7f, 0xcc, 0xe } }, // __NSAutoBlock 106 | [0x98] = { 1, (struct _NativeZWRTableEntry[256]) { // 1 107 | [0x4a] = { 0, (unsigned char[]){ 0xd, 0xf9, 0x7b, 0xf8, 0x20, 0x1c, 0xc6, 0x40, 0x43, 0x6, 0x7, 0x6c, 0x14, 0xd7, 0x25, 0x21, 0x25, 0xb7 } }, // NSSingleLineTypesetter 108 | [0xb2] = { 0, (unsigned char[]){ 0xb6, 0xb4, 0x58, 0x5d, 0x2a, 0x3c, 0xc, 0xc8, 0x27, 0xe7, 0x6e, 0x63, 0x7, 0x7e, 0x53, 0xb2, 0x50, 0x59 } }, // NSCollectionViewItem 109 | [0xdf] = { 0, (unsigned char[]){ 0xf3, 0x3a, 0x92, 0xb7, 0x1a, 0x77, 0x8f, 0xf7, 0x45, 0x92, 0xd0, 0x22, 0x18, 0xb0, 0xcc, 0xc5, 0x4f, 0x96 } }, // NSScalarObjectID64 110 | }}, 111 | [0x9a] = { 0, (unsigned char[]){ 0x57, 0xa6, 0xe7, 0x54, 0xa2, 0xbc, 0xe6, 0x20, 0x28, 0x42, 0x60, 0x93, 0x3, 0x14, 0x9d, 0xdf, 0xdb, 0xda, 0x4f } }, // NSSidebarImage 112 | [0x9d] = { 0, (unsigned char[]){ 0xb3, 0x81, 0xc4, 0xce, 0x4b, 0x48, 0x6d, 0x80, 0x6a, 0xf4, 0xe1, 0x31, 0xda, 0x8d, 0xc7, 0x83, 0xab, 0xc5, 0xa1 } }, // NSPanel 113 | [0xa0] = { 0, (unsigned char[]){ 0x63, 0xb, 0xc2, 0xb6, 0xbe, 0xf6, 0xc3, 0x86, 0x47, 0x7, 0xe, 0xd8, 0xef, 0xff, 0x92, 0xe5, 0x31, 0xe9, 0x0 } }, // NSComboBoxWindow 114 | [0xa2] = { 0, (unsigned char[]){ 0x83, 0x8d, 0xd0, 0xff, 0xa3, 0x36, 0x89, 0xef, 0x62, 0xbc, 0xb5, 0xd6, 0xbb, 0x7a, 0x4b, 0xf6, 0xf6, 0xb1, 0xfb } }, // NSViewController 115 | [0xa6] = { 0, (unsigned char[]){ 0xe8, 0x41, 0xe7, 0xac, 0x58, 0xf6, 0x21, 0x64, 0x82, 0xad, 0xa8, 0x65, 0x1a, 0x54, 0x58, 0x8c, 0xd3, 0x54, 0xa0 } }, // _NSNonretainedFullScreenWindow 116 | [0xa9] = { 0, (unsigned char[]){ 0x2f, 0xd9, 0xc0, 0xea, 0xae, 0x7d, 0x3, 0xd8, 0x5e, 0xbe, 0x67, 0xee, 0x5f, 0xb0, 0x60, 0xd0, 0x57, 0x7a, 0x5c } }, // _NSAutomaticFocusRingOverlayWindow 117 | [0xaa] = { 0, (unsigned char[]){ 0x9b, 0x75, 0x33, 0xf, 0xa8, 0xfa, 0xda, 0x8d, 0x4a, 0xd6, 0x4c, 0x43, 0x12, 0x47, 0x4d, 0x10, 0xb2, 0xc0, 0xa0 } }, // NSNavProgressWindowController 118 | [0xab] = { 0, (unsigned char[]){ 0xed, 0xd5, 0xe6, 0xe8, 0xac, 0x1, 0xd, 0x20, 0x57, 0x7f, 0x71, 0xfd, 0x18, 0xcc, 0x69, 0x72, 0xa, 0x1d, 0x42 } }, // _NSCachedAttributedString 119 | [0xac] = { 0, (unsigned char[]){ 0x62, 0xbc, 0xb9, 0x26, 0xdd, 0x24, 0x3d, 0x3f, 0xc4, 0x26, 0x47, 0x50, 0xc6, 0xbb, 0x6b, 0x56, 0x93, 0x16, 0x2c } }, // NSLineFragmentRenderingContext 120 | [0xad] = { 0, (unsigned char[]){ 0x75, 0xf9, 0xaa, 0x1b, 0xf9, 0x53, 0x93, 0x35, 0xe3, 0x16, 0x98, 0xfc, 0x7e, 0xe5, 0xec, 0x9b, 0xca, 0x64, 0xef } }, // NSFindPatternFieldEditor 121 | [0xae] = { 0, (unsigned char[]){ 0xd, 0x3, 0x25, 0x76, 0x1f, 0x1f, 0x45, 0x58, 0x25, 0xb8, 0x8f, 0xa8, 0x37, 0x72, 0xfd, 0xf5, 0xb7, 0xf1, 0x85 } }, // PBOXMenuWindow 122 | [0xb0] = { 0, (unsigned char[]){ 0x40, 0x9, 0xa1, 0xd9, 0xb4, 0xf, 0x4, 0xb6, 0x4, 0xd6, 0xd5, 0x7b, 0x9d, 0xdf, 0x9e, 0x8, 0xa2, 0xe4, 0xb7 } }, // NSMachPort 123 | [0xb1] = { 0, (unsigned char[]){ 0x7e, 0x84, 0xd, 0x23, 0x8f, 0x79, 0x56, 0xff, 0x92, 0x40, 0x76, 0xb0, 0x6b, 0x81, 0x76, 0x96, 0xf, 0xc1, 0xa } }, // __NSAutoBlock__ 124 | [0xb4] = { 0, (unsigned char[]){ 0x69, 0x23, 0xfd, 0xe9, 0xf, 0x24, 0x19, 0xb7, 0xa7, 0x92, 0xe1, 0xed, 0x1b, 0xd1, 0xa0, 0xae, 0x64, 0x85, 0x87 } }, // NSExternalRefCountedData 125 | [0xbc] = { 0, (unsigned char[]){ 0x7b, 0x3e, 0x3c, 0xe7, 0xe3, 0x14, 0x1b, 0x46, 0x77, 0x44, 0xdb, 0x43, 0xc3, 0xa4, 0xb9, 0x31, 0x66, 0x8, 0xc7 } }, // _NSFlippedImage 126 | [0xbe] = { 1, (struct _NativeZWRTableEntry[256]) { // 1 127 | [0x66] = { 0, (unsigned char[]){ 0x1a, 0x9f, 0x99, 0xf3, 0x4a, 0xb9, 0xa7, 0xb0, 0x6, 0xad, 0xc1, 0x81, 0xdf, 0xe2, 0x1e, 0x1, 0x8b, 0xf4 } }, // _NSBorderlessLayerTreeProjectionWindow 128 | [0xab] = { 0, (unsigned char[]){ 0x49, 0x7d, 0x5f, 0x63, 0xfe, 0xdc, 0xa7, 0x43, 0x43, 0xad, 0x24, 0x80, 0x6c, 0xeb, 0x36, 0x4, 0xd2, 0x9b } }, // NSFontPanel 129 | }}, 130 | [0xbf] = { 0, (unsigned char[]){ 0x83, 0x4b, 0x26, 0xf2, 0xc3, 0x24, 0xc5, 0x64, 0x5d, 0x4c, 0x96, 0x86, 0xed, 0x42, 0x1c, 0x83, 0x5, 0x34, 0x8c } }, // NSNavProgressErrorViewController 131 | [0xc1] = { 0, (unsigned char[]){ 0x94, 0xb4, 0x7c, 0xba, 0xa4, 0xf5, 0x3a, 0x43, 0x6, 0xa3, 0x84, 0x64, 0xeb, 0xf7, 0xe0, 0xe0, 0xb6, 0x98, 0x55 } }, // NSText 132 | [0xc3] = { 0, (unsigned char[]){ 0x2e, 0x12, 0x59, 0xba, 0x72, 0xd7, 0x51, 0x40, 0x73, 0xe3, 0xe1, 0xfb, 0x1e, 0x97, 0xb0, 0xc5, 0xc1, 0xe4, 0xeb } }, // _NSTextFinderOverlayWindow 133 | [0xcd] = { 1, (struct _NativeZWRTableEntry[256]) { // 1 134 | [0x1b] = { 0, (unsigned char[]){ 0x3b, 0x80, 0x3f, 0x14, 0x9c, 0xde, 0xad, 0x18, 0x4b, 0xe9, 0x44, 0xba, 0x1, 0x5f, 0x8, 0x98, 0xd6, 0x8c } }, // __NSStackBlock 135 | [0x81] = { 0, (unsigned char[]){ 0xa9, 0x68, 0x44, 0x6c, 0xfc, 0x5b, 0x40, 0xfe, 0x10, 0xb4, 0xc3, 0x4e, 0x19, 0xfd, 0x57, 0x68, 0x6c, 0xcb } }, // NSFindPanel 136 | }}, 137 | [0xd2] = { 0, (unsigned char[]){ 0x53, 0x40, 0xb2, 0xe9, 0xe7, 0xd8, 0xaa, 0xa9, 0x8c, 0x59, 0x99, 0x1, 0x9, 0x2b, 0xa9, 0x5a, 0x8c, 0x4, 0xa4 } }, // NSDocumentRevisionsWindow 138 | [0xd9] = { 0, (unsigned char[]){ 0x9, 0x12, 0x39, 0x4d, 0xa4, 0x3, 0x8b, 0x2, 0x13, 0x4a, 0xc6, 0x58, 0xd5, 0x9e, 0x50, 0x4a, 0xf0, 0x2, 0x36 } }, // NSISNonNegativeVariable 139 | [0xdb] = { 0, (unsigned char[]){ 0x1a, 0x27, 0xe4, 0x7, 0x22, 0xf5, 0x27, 0xc3, 0xcd, 0xc8, 0x2b, 0xb6, 0x2c, 0x25, 0x40, 0xf9, 0x46, 0xa4, 0x73 } }, // NSFont 140 | [0xdc] = { 1, (struct _NativeZWRTableEntry[256]) { // 1 141 | [0x6] = { 0, (unsigned char[]){ 0x59, 0x16, 0xd4, 0x5a, 0xea, 0x6f, 0x8e, 0x8, 0xac, 0x89, 0xac, 0xb, 0x73, 0x2c, 0x62, 0x67, 0xff, 0x0 } }, // __NSFinalizingBlock__ 142 | [0x10] = { 0, (unsigned char[]){ 0xab, 0x59, 0x12, 0x43, 0x64, 0x12, 0x79, 0xe0, 0x82, 0xb3, 0xf9, 0xcd, 0x3b, 0xf4, 0x4d, 0x7b, 0x94, 0x25 } }, // NSPersistentUIEncodedReference 143 | }}, 144 | [0xdd] = { 1, (struct _NativeZWRTableEntry[256]) { // 1 145 | [0x94] = { 0, (unsigned char[]){ 0x9b, 0xe, 0x2a, 0x0, 0x1b, 0x77, 0x4d, 0x1c, 0xe6, 0x22, 0x91, 0x1d, 0x0, 0xc4, 0xf2, 0x51, 0xaa, 0x77 } }, // NSFontManager 146 | [0x97] = { 0, (unsigned char[]){ 0x91, 0x5, 0x67, 0xd4, 0xed, 0x70, 0xac, 0xca, 0x54, 0x91, 0x52, 0x9a, 0x83, 0x97, 0xd2, 0x27, 0x32, 0x45 } }, // NSDockMiniViewWindow 147 | }}, 148 | [0xde] = { 1, (struct _NativeZWRTableEntry[256]) { // 1 149 | [0x5d] = { 0, (unsigned char[]){ 0x3d, 0x4e, 0xd6, 0x7a, 0x5c, 0x6b, 0xe7, 0x4a, 0x4c, 0xa, 0xbf, 0xbe, 0x5f, 0xdf, 0x48, 0x34, 0x80, 0xe8 } }, // NSBrowserColumnViewController 150 | [0x96] = { 0, (unsigned char[]){ 0xa9, 0x1e, 0x9e, 0x35, 0x8f, 0x86, 0x47, 0x74, 0xd3, 0x6b, 0x36, 0x41, 0x53, 0x70, 0x40, 0x52, 0xaf, 0xcb } }, // __NSStackBlock__ 151 | }}, 152 | [0xe1] = { 0, (unsigned char[]){ 0xbf, 0xae, 0xbb, 0x5e, 0xb3, 0x4f, 0xa1, 0xe6, 0x4e, 0xb0, 0xd7, 0x78, 0x96, 0xba, 0x99, 0x51, 0xc6, 0x14, 0xbe } }, // NSNavPreviewController 153 | [0xe5] = { 0, (unsigned char[]){ 0xf0, 0x45, 0x53, 0x1a, 0xc8, 0x5d, 0x6b, 0xec, 0x33, 0x26, 0xf6, 0x40, 0xbe, 0x49, 0x18, 0xab, 0xd1, 0x1d, 0xa8 } }, // NSPersistentUIWindowInfo 154 | [0xe6] = { 0, (unsigned char[]){ 0x4f, 0x4f, 0xa8, 0x1f, 0x86, 0x21, 0x2b, 0x2c, 0xea, 0xab, 0xc4, 0xd5, 0x21, 0x66, 0x4c, 0xd8, 0x5b, 0xa0, 0x93 } }, // NSTypeSelectPanel 155 | [0xe8] = { 1, (struct _NativeZWRTableEntry[256]) { // 1 156 | [0x58] = { 0, (unsigned char[]){ 0xc1, 0x9e, 0x22, 0x8f, 0x43, 0x27, 0xfc, 0xe4, 0x97, 0xfb, 0x26, 0xeb, 0x32, 0x7b, 0xaf, 0x83, 0xc1, 0x89 } }, // _NSMagnifierWindow 157 | [0x8c] = { 0, (unsigned char[]){ 0x19, 0x95, 0x99, 0x16, 0xe0, 0x53, 0x7, 0xfd, 0xe0, 0xde, 0x1c, 0x45, 0x44, 0x2f, 0xa3, 0xaf, 0xee, 0x90 } }, // NSScalarObjectID48 158 | }}, 159 | [0xe9] = { 0, (unsigned char[]){ 0xc6, 0x97, 0x40, 0x80, 0x2e, 0xc7, 0xd2, 0xbd, 0xc9, 0xd9, 0x7b, 0x21, 0x74, 0x23, 0x43, 0xf, 0xe1, 0x5a, 0x71 } }, // NSNavNodePreviewController 160 | [0xea] = { 0, (unsigned char[]){ 0x2f, 0x9f, 0x2c, 0xbf, 0x6b, 0xa7, 0x23, 0x7e, 0x64, 0x70, 0xcc, 0x75, 0x9c, 0xa9, 0xbd, 0x70, 0x2c, 0xd1, 0x66 } }, // NSATSTypesetter 161 | [0xec] = { 0, (unsigned char[]){ 0xd0, 0xc9, 0x57, 0xaf, 0xce, 0xfe, 0x15, 0xe7, 0xa3, 0xab, 0x2c, 0xda, 0x72, 0xae, 0xad, 0x17, 0x45, 0x86, 0xb1 } }, // _NSPopoverWindow 162 | [0xf1] = { 1, (struct _NativeZWRTableEntry[256]) { // 1 163 | [0xa5] = { 0, (unsigned char[]){ 0x56, 0x9f, 0x8e, 0xfd, 0x1c, 0xc1, 0x5a, 0x15, 0xc5, 0x2, 0xd, 0x56, 0xb4, 0x1b, 0x70, 0x10, 0xdf, 0xa } }, // NSSavePanel 164 | [0xf5] = { 0, (unsigned char[]){ 0xf3, 0x38, 0xe1, 0x77, 0x44, 0x43, 0x88, 0x4, 0x36, 0x2, 0x38, 0xfc, 0xfc, 0xfb, 0xa8, 0x17, 0x4c, 0xe } }, // _NSToolbarDefaultImageRepWindow 165 | }}, 166 | [0xf2] = { 0, (unsigned char[]){ 0xce, 0x71, 0x3f, 0x21, 0x3, 0x1b, 0x57, 0x65, 0x33, 0xbf, 0xe7, 0x23, 0x4d, 0x99, 0x82, 0x1b, 0xb9, 0xf6, 0x34 } }, // NSISPureMarkerVariable 167 | [0xf3] = { 1, (struct _NativeZWRTableEntry[256]) { // 1 168 | [0x66] = { 0, (unsigned char[]){ 0x95, 0xb6, 0xa7, 0x27, 0x66, 0x70, 0x2f, 0xc5, 0x4a, 0x38, 0xe6, 0x3b, 0x34, 0xd, 0x54, 0x21, 0x87, 0x8e } }, // NSTempAttributeDictionary 169 | [0xb8] = { 0, (unsigned char[]){ 0x8a, 0xcf, 0x23, 0xe6, 0x69, 0xe8, 0x76, 0x42, 0x9d, 0xb1, 0x4a, 0x2, 0xb1, 0x9f, 0x84, 0xa4, 0x39, 0x3e } }, // NSISNonNegativeMarkerVariableToBeMinimized 170 | [0xeb] = { 0, (unsigned char[]){ 0x5a, 0x8e, 0x70, 0xf6, 0xbf, 0x41, 0x37, 0x89, 0x2e, 0x94, 0x4b, 0x94, 0x23, 0x7d, 0x34, 0x6c, 0x46, 0xb4 } }, // NSOpenPanel 171 | }}, 172 | [0xf7] = { 0, (unsigned char[]){ 0xcc, 0x3b, 0x53, 0x10, 0x6b, 0x29, 0xa6, 0x2c, 0xbd, 0xb4, 0x33, 0x8f, 0xa2, 0x46, 0x50, 0x9f, 0x97, 0xe6, 0x77 } }, // NSImage 173 | [0xf9] = { 0, (unsigned char[]){ 0x89, 0x82, 0x91, 0xa7, 0xfc, 0x43, 0xee, 0x1b, 0x3, 0xef, 0xcc, 0x48, 0x8, 0x11, 0x51, 0x9b, 0x72, 0xe9, 0x14 } }, // NSNavNewFolderController 174 | [0xfa] = { 0, (unsigned char[]){ 0x2c, 0xb3, 0xa5, 0x1a, 0xe1, 0xa0, 0x3, 0x94, 0x42, 0xe2, 0x6c, 0xaa, 0xa1, 0xf8, 0x23, 0xb2, 0x12, 0x8e, 0xfd } }, // NSMutableParagraphStyle 175 | [0xfc] = { 1, (struct _NativeZWRTableEntry[256]) { // 1 176 | [0xd4] = { 0, (unsigned char[]){ 0x7f, 0xea, 0x1b, 0x11, 0xbf, 0xeb, 0x92, 0x57, 0x23, 0x70, 0x9, 0x12, 0x89, 0xaf, 0x84, 0xa2, 0xdf, 0x31 } }, // NSNavProgressWindow 177 | [0xd8] = { 0, (unsigned char[]){ 0x12, 0x31, 0x5f, 0x60, 0x61, 0x94, 0x7b, 0x74, 0xde, 0xd5, 0xf9, 0x34, 0x6a, 0x51, 0xff, 0x16, 0xef, 0x1e } }, // NSDrawerWindow 178 | }}, 179 | [0xff] = { 0, (unsigned char[]){ 0xd7, 0x9a, 0x4b, 0x94, 0x11, 0xb7, 0xbb, 0xb8, 0x25, 0x4d, 0x34, 0x60, 0x80, 0x46, 0xdc, 0x3a, 0x95, 0xed, 0xe3 } }, // NSLazyBrowserCell 180 | }; 181 | -------------------------------------------------------------------------------- /PLWeakCompatibility/PLWeakCompatibility-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | coop.plausible.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | FMWK 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | NSHumanReadableCopyright 26 | Copyright © 2012 Plausible Labs Cooperative, Inc. All rights reserved. 27 | NSPrincipalClass 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /PLWeakCompatibility/PLWeakCompatibility-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'PLWeakCompatibility' target in the 'PLWeakCompatibility' project 3 | // 4 | 5 | #import 6 | 7 | #ifndef __IPHONE_3_0 8 | #warning "This project uses features only available in iOS SDK 3.0 and later." 9 | #endif 10 | 11 | #ifdef __OBJC__ 12 | #import 13 | #import 14 | #endif 15 | -------------------------------------------------------------------------------- /PLWeakCompatibility/PLWeakCompatibilityStubs.h: -------------------------------------------------------------------------------- 1 | // 2 | // PLWeakCompatibilityStubs.h 3 | // PLWeakCompatibility 4 | // 5 | // Created by Michael Ash on 3/28/12. 6 | // Copyright (c) 2012 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | // A typedef used in place of id to prevent ARC from getting its hands dirty with 12 | // our object pointers. Even with __unsafe_unretained, ARC likes to do things like 13 | // retain and release intermediate values, which gets us into serious trouble. 14 | typedef void *PLObjectPtr; 15 | 16 | 17 | // These are prototypes of the various runtime functions the compiler calls to handle 18 | // __weak variables. If you import this header and these prototypes interfere with 19 | // the official ones (due to using PLObjectPtr instead of id), simply do 20 | // #define EXCLUDE_STUB_PROTOTYPES 1 immediately before the import statement to 21 | // exclude these. 22 | #if !EXCLUDE_STUB_PROTOTYPES 23 | PLObjectPtr objc_loadWeakRetained(PLObjectPtr *location); 24 | PLObjectPtr objc_initWeak(PLObjectPtr *addr, PLObjectPtr val); 25 | void objc_destroyWeak(PLObjectPtr *addr); 26 | void objc_copyWeak(PLObjectPtr *to, PLObjectPtr *from); 27 | void objc_moveWeak(PLObjectPtr *to, PLObjectPtr *from); 28 | PLObjectPtr objc_loadWeak(PLObjectPtr *location); 29 | PLObjectPtr objc_storeWeak(PLObjectPtr *location, PLObjectPtr obj); 30 | #endif 31 | 32 | // Enable or disable the use of MAZeroingWeakRef. If enabled is YES, then 33 | // MAZeroingWeakRef is used to implement the __weak functionality if present. 34 | // If MAZWR is not present in your process, then it falls back to its simpler 35 | // internal implementation. MAZWR use is enabled by default. Note that 36 | // changing this value after weak references have been manipulated is 37 | // extremely forbidden and will cause no end to havoc. 38 | void PLWeakCompatibilitySetMAZWREnabled(BOOL enabled); 39 | 40 | // Check whether MAZeroingWeakRef is in use. Returns YES if and only if 41 | // MAZeroingWeakRef is present in the process and its use is not disabled 42 | // with the above function. Returns NO if MAZWR is not present or its 43 | // use has been explicitly disabled. 44 | BOOL PLWeakCompatibilityHasMAZWR(void); 45 | 46 | // Enable or disable the use of native fallthroughs to built-in runtime functions 47 | // when present. When enabled, if the necessary weak reference functions are 48 | // present in the Objective-C runtime, they are called instead of the third-party 49 | // weak reference implementation. When disabled, the third-party implementation 50 | // is always used. This is enabled by default, and should not be disabled except 51 | // for testing purposes. Do not change this value after weak references have been 52 | // manipulated, or you will severely regret it. 53 | void PLWeakCompatibilitySetFallthroughEnabled(BOOL enabled); 54 | -------------------------------------------------------------------------------- /PLWeakCompatibility/PLWeakCompatibilityStubs.m: -------------------------------------------------------------------------------- 1 | // 2 | // PLWeakCompatibilityStubs.m 3 | // PLWeakCompatibility 4 | // 5 | // Created by Michael Ash on 3/28/12. 6 | // Copyright (c) 2012 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "PLWeakCompatibilityStubs.h" 10 | 11 | #import 12 | #import 13 | 14 | // We need our own prototypes for some functions to avoid conflicts, so disable the ones from the header 15 | #define object_getClass object_getClass_disabled_for_ARC_PLWeakCompatibilityStubs 16 | #define objc_loadWeak objc_loadWeak_disabled_for_ARC_PLWeakCompatibilityStubs 17 | #define objc_storeWeak objc_storeWeak_disabled_for_ARC_PLWeakCompatibilityStubs 18 | // Note to future self: associated objects are basically incompatible with older OSes due to 19 | // failed cleanup with isa-swizzled objects. So, don't try to use them. Thanks, past self. 20 | #import 21 | #undef object_getClass 22 | #undef objc_loadWeak 23 | #undef objc_storeWeak 24 | 25 | // MAZeroingWeakRef Support 26 | static Class MAZWR = Nil; 27 | static bool mazwrEnabled = true; 28 | static inline bool has_mazwr () { 29 | if (!mazwrEnabled) 30 | return false; 31 | 32 | static dispatch_once_t lookup_once = 0; 33 | dispatch_once(&lookup_once, ^{ 34 | MAZWR = NSClassFromString(@"MAZeroingWeakRef"); 35 | }); 36 | 37 | if (MAZWR != nil) 38 | return true; 39 | return false; 40 | } 41 | 42 | // Minimal MAZWR API that we rely on 43 | @interface MAZeroingWeakRef : NSObject 44 | - (id) initWithTarget: (PLObjectPtr) target; 45 | - (PLObjectPtr) target; 46 | @end 47 | 48 | void PLWeakCompatibilitySetMAZWREnabled(BOOL enabled) { 49 | mazwrEnabled = enabled; 50 | } 51 | 52 | BOOL PLWeakCompatibilityHasMAZWR(void) { 53 | return has_mazwr(); 54 | } 55 | 56 | // Runtime (or ARC compatibility) prototypes we use here. 57 | PLObjectPtr objc_release(PLObjectPtr obj); 58 | PLObjectPtr objc_autorelease(PLObjectPtr obj); 59 | PLObjectPtr objc_retain(PLObjectPtr obj); 60 | Class object_getClass(PLObjectPtr obj); 61 | 62 | // Primitive functions used to implement all weak stubs 63 | static PLObjectPtr PLLoadWeakRetained(PLObjectPtr *location); 64 | static void PLRegisterWeak(PLObjectPtr *location, PLObjectPtr obj); 65 | static void PLUnregisterWeak(PLObjectPtr *location); 66 | 67 | // Convenience for falling through to the system implementation. 68 | static BOOL fallthroughEnabled = YES; 69 | 70 | #define NEXT(name, ...) do { \ 71 | static dispatch_once_t fptrOnce; \ 72 | static __typeof__(&name) fptr; \ 73 | dispatch_once(&fptrOnce, ^{ fptr = dlsym(RTLD_NEXT, #name); });\ 74 | if (fallthroughEnabled && fptr != NULL) \ 75 | return fptr(__VA_ARGS__); \ 76 | } while(0) 77 | 78 | void PLWeakCompatibilitySetFallthroughEnabled(BOOL enabled) { 79 | fallthroughEnabled = enabled; 80 | } 81 | 82 | //////////////////// 83 | #pragma mark Stubs 84 | //////////////////// 85 | 86 | PLObjectPtr objc_loadWeakRetained(PLObjectPtr *location) { 87 | NEXT(objc_loadWeakRetained, location); 88 | 89 | return PLLoadWeakRetained(location); 90 | } 91 | 92 | PLObjectPtr objc_initWeak(PLObjectPtr *addr, PLObjectPtr val) { 93 | NEXT(objc_initWeak, addr, val); 94 | *addr = NULL; 95 | return objc_storeWeak(addr, val); 96 | } 97 | 98 | void objc_destroyWeak(PLObjectPtr *addr) { 99 | NEXT(objc_destroyWeak, addr); 100 | objc_storeWeak(addr, NULL); 101 | } 102 | 103 | void objc_copyWeak(PLObjectPtr *to, PLObjectPtr *from) { 104 | NEXT(objc_copyWeak, to, from); 105 | objc_initWeak(to, objc_loadWeak(from)); 106 | } 107 | 108 | void objc_moveWeak(PLObjectPtr *to, PLObjectPtr *from) { 109 | NEXT(objc_moveWeak, to, from); 110 | objc_copyWeak(to, from); 111 | objc_destroyWeak(from); 112 | } 113 | 114 | PLObjectPtr objc_loadWeak(PLObjectPtr *location) { 115 | NEXT(objc_loadWeak, location); 116 | return objc_autorelease(objc_loadWeakRetained(location)); 117 | } 118 | 119 | PLObjectPtr objc_storeWeak(PLObjectPtr *location, PLObjectPtr obj) { 120 | NEXT(objc_storeWeak, location, obj); 121 | 122 | PLUnregisterWeak(location); 123 | 124 | *location = obj; 125 | 126 | if (obj != nil) 127 | PLRegisterWeak(location, obj); 128 | 129 | return obj; 130 | } 131 | 132 | 133 | //////////////////// 134 | #pragma mark Internal Globals and Prototypes 135 | //////////////////// 136 | 137 | // This mutex protects all shared state 138 | static pthread_mutex_t gWeakMutex; 139 | 140 | // A map from objects to CFMutableSets containing weak addresses 141 | static CFMutableDictionaryRef gObjectToAddressesMap; 142 | 143 | // A list of all classes that have been swizzled 144 | static CFMutableSetRef gSwizzledClasses; 145 | 146 | // A list of all objects that are in the middle of being released 147 | static CFMutableBagRef gReleasingObjects; 148 | 149 | // Condition variable used to signal when releasing objects are done releasing 150 | static pthread_cond_t gReleasingObjectsCond; 151 | 152 | // Thread local storage key 153 | static pthread_key_t gTLSKey; 154 | 155 | // Thread local storage struct 156 | struct TLS { 157 | // Tables tracking the last class a swizzled method was sent to on an object 158 | CFMutableDictionaryRef lastReleaseClassTable; 159 | CFMutableDictionaryRef lastDeallocClassTable; 160 | }; 161 | 162 | // Ensure everything is properly initialized 163 | static void WeakInit(void); 164 | 165 | // Fetch the TLS struct for this thread 166 | static struct TLS *GetTLS(void); 167 | 168 | // Destroy the thread's TLS struct 169 | static void DestroyTLS(void *ptr); 170 | 171 | // Make sure the object's class is properly swizzled to clear weak refs on deallocation 172 | static void EnsureDeallocationTrigger(PLObjectPtr obj); 173 | 174 | // Selectors, for convenience and to work around ARC paranoia re: @selector(release) etc. 175 | static SEL releaseSEL; 176 | static SEL releaseSELSwizzled; 177 | static SEL deallocSEL; 178 | static SEL deallocSELSwizzled; 179 | 180 | 181 | //////////////////// 182 | #pragma mark Primitive Functions 183 | //////////////////// 184 | 185 | /** 186 | * Load a weak reference. 187 | * 188 | * @param location a pointer to the weak reference to load 189 | * @return the object stored at the weak reference, retained, or nil if none 190 | */ 191 | static PLObjectPtr PLLoadWeakRetained(PLObjectPtr *location) { 192 | /* Hand off to MAZWR */ 193 | if (has_mazwr()) { 194 | MAZeroingWeakRef *mazrw = (__bridge MAZeroingWeakRef *) *location; 195 | return objc_retain([mazrw target]); 196 | } 197 | 198 | WeakInit(); 199 | 200 | PLObjectPtr obj; 201 | pthread_mutex_lock(&gWeakMutex); { 202 | obj = *location; 203 | while (CFBagContainsValue(gReleasingObjects, obj)) { 204 | pthread_cond_wait(&gReleasingObjectsCond, &gWeakMutex); 205 | obj = *location; 206 | } 207 | objc_retain(obj); 208 | } 209 | pthread_mutex_unlock(&gWeakMutex); 210 | 211 | return obj; 212 | } 213 | 214 | /** 215 | * Register an object in a new weak reference. 216 | * 217 | * @param location a pointer to the weak reference where obj is being stored 218 | * @param the object being weakly referenced at this location 219 | */ 220 | static void PLRegisterWeak(PLObjectPtr *location, PLObjectPtr obj) { 221 | /* Hand off to MAZWR */ 222 | if (has_mazwr()) { 223 | MAZeroingWeakRef *ref = [[MAZWR alloc] initWithTarget: obj]; 224 | *location = (__bridge_retained PLObjectPtr) ref; 225 | return; 226 | } 227 | 228 | WeakInit(); 229 | 230 | // Add the location to the list of weak references pointing to the object. 231 | pthread_mutex_lock(&gWeakMutex); { 232 | CFMutableSetRef addresses = (CFMutableSetRef)CFDictionaryGetValue(gObjectToAddressesMap, obj); 233 | 234 | // If this is the first weak reference to this object, addresses won't exist yet, so create it. 235 | if (addresses == NULL) { 236 | addresses = CFSetCreateMutable(NULL, 0, NULL); 237 | CFDictionarySetValue(gObjectToAddressesMap, obj, addresses); 238 | CFRelease(addresses); 239 | } 240 | 241 | CFSetAddValue(addresses, location); 242 | 243 | // Make sure the appropriate swizzling has been done to obj's class. 244 | EnsureDeallocationTrigger(obj); 245 | } pthread_mutex_unlock(&gWeakMutex); 246 | } 247 | 248 | /** 249 | * Unregister an object from the given weak reference. 250 | * 251 | * @param location a pointer to the weak reference to unregister 252 | * @param obj the object to unregister 253 | */ 254 | static void PLUnregisterWeak(PLObjectPtr *location) { 255 | /* Hand off to MAZWR */ 256 | if (has_mazwr()) { 257 | if (*location != nil) 258 | objc_release(*location); 259 | return; 260 | } 261 | 262 | WeakInit(); 263 | 264 | pthread_mutex_lock(&gWeakMutex); { 265 | // Remove the location from the set of weakly referenced addresses. 266 | CFMutableSetRef addresses = (CFMutableSetRef)CFDictionaryGetValue(gObjectToAddressesMap, *location); 267 | if (addresses != NULL) 268 | CFSetRemoveValue(addresses, location); 269 | } pthread_mutex_unlock(&gWeakMutex); 270 | } 271 | 272 | 273 | //////////////////// 274 | #pragma mark Internal Functions 275 | //////////////////// 276 | 277 | /** 278 | * Initialize all weak reference global variables. 279 | */ 280 | static void WeakInit(void) { 281 | static dispatch_once_t pred; 282 | dispatch_once(&pred, ^{ 283 | pthread_mutexattr_t attr; 284 | pthread_mutexattr_init(&attr); 285 | pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); 286 | 287 | pthread_mutex_init(&gWeakMutex, &attr); 288 | 289 | pthread_mutexattr_destroy(&attr); 290 | 291 | gObjectToAddressesMap = CFDictionaryCreateMutable(NULL, 0, NULL, &kCFTypeDictionaryValueCallBacks); 292 | 293 | gSwizzledClasses = CFSetCreateMutable(NULL, 0, NULL); 294 | 295 | gReleasingObjects = CFBagCreateMutable(NULL, 0, NULL); 296 | pthread_cond_init(&gReleasingObjectsCond, NULL); 297 | 298 | int err = pthread_key_create(&gTLSKey, DestroyTLS); 299 | if (err != 0) { 300 | NSLog(@"Error calling pthread_key_create, we really can't recover from that: %s (%d)", strerror(err), err); 301 | abort(); 302 | } 303 | 304 | releaseSEL = sel_getUid("release"); 305 | releaseSELSwizzled = sel_getUid("release_PLWeakCompatibility_swizzled"); 306 | deallocSEL = sel_getUid("dealloc"); 307 | deallocSELSwizzled = sel_getUid("dealloc_PLWeakCompatibility_swizzled"); 308 | }); 309 | } 310 | 311 | /** 312 | * Get the thread local storage struct for this thread. 313 | */ 314 | static struct TLS *GetTLS(void) { 315 | struct TLS *tls = pthread_getspecific(gTLSKey); 316 | if (tls == NULL) { 317 | tls = calloc(1, sizeof(*tls)); 318 | tls->lastReleaseClassTable = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); 319 | tls->lastDeallocClassTable = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); 320 | pthread_setspecific(gTLSKey, tls); 321 | } 322 | return tls; 323 | } 324 | 325 | /** 326 | * Destroy the given TLS struct. 327 | */ 328 | static void DestroyTLS(void *ptr) { 329 | struct TLS *tls = ptr; 330 | if (tls != NULL && tls->lastReleaseClassTable) { 331 | CFRelease(tls->lastReleaseClassTable); 332 | CFRelease(tls->lastDeallocClassTable); 333 | } 334 | free(tls); 335 | } 336 | 337 | /** 338 | * Search for the top implementation of a given method. Starting at a given class, 339 | * it searches the class hierarchy upwards until it finds a class with a different 340 | * implementation for the given selector. It then returns the topmost class to have 341 | * the same implementation as the class that was passed in. This is used to emulate 342 | * a "super" call to a swizzled method by seeing which class the swizzled implementation 343 | * belongs to, and targeting the next class above it for the next call. 344 | * 345 | * @param start the class to start examining 346 | * @param sel the selector of the method to search for 347 | */ 348 | static Class TopClassImplementingMethod(Class start, SEL sel) { 349 | IMP imp = class_getMethodImplementation(start, sel); 350 | 351 | Class previous = start; 352 | Class cursor = class_getSuperclass(previous); 353 | while (cursor != Nil) { 354 | if (imp != class_getMethodImplementation(cursor, sel)) 355 | break; 356 | previous = cursor; 357 | cursor = class_getSuperclass(cursor); 358 | } 359 | 360 | return previous; 361 | } 362 | 363 | /** 364 | * A swizzled release implementation which calls through to the real implementation with the 365 | * global weak mutex held, to eliminate race conditions between an object being destroyed and 366 | * a weak reference to that object being fetched. 367 | */ 368 | static void SwizzledReleaseIMP(PLObjectPtr self, SEL _cmd) { 369 | struct TLS *tls = GetTLS(); 370 | 371 | pthread_mutex_lock(&gWeakMutex); { 372 | // Add this object to the list of releasing objects. 373 | CFBagAddValue(gReleasingObjects, self); 374 | } pthread_mutex_unlock(&gWeakMutex); 375 | 376 | // Figure out which class release was last sent to, in the event of recursive releases. 377 | // If lastSent is Nil, then this is the first release call on the stack for this object 378 | // and the call should start at the bottom. Otherwise, we want the next class above the 379 | // last one that was used. 380 | Class lastSent = (__bridge Class)CFDictionaryGetValue(tls->lastReleaseClassTable, self); 381 | Class targetClass = lastSent == Nil ? object_getClass(self) : class_getSuperclass(lastSent); 382 | targetClass = TopClassImplementingMethod(targetClass, releaseSELSwizzled); 383 | 384 | // If [self release] is called recursively (happens if 'self' is released in 'dealloc') 385 | // then targetClass ends up being NSObject and doesn't respond to releaseSELSwizzled. 386 | // To detect this, if targetClass doesn't respond to releaseSELSwizzled, start over at 387 | // the bottom. 388 | if (!class_respondsToSelector(targetClass, releaseSELSwizzled)) { 389 | targetClass = object_getClass(self); 390 | targetClass = TopClassImplementingMethod(targetClass, releaseSELSwizzled); 391 | } 392 | 393 | CFDictionarySetValue(tls->lastReleaseClassTable, self, (__bridge void *)targetClass); 394 | 395 | // Call through to the original implementation on the target class. 396 | void (*origIMP)(PLObjectPtr, SEL) = (__typeof__(origIMP))class_getMethodImplementation(targetClass, releaseSELSwizzled); 397 | origIMP(self, _cmd); 398 | 399 | // Clean up the class table. 400 | CFDictionaryRemoveValue(tls->lastReleaseClassTable, self); 401 | 402 | pthread_mutex_lock(&gWeakMutex); { 403 | // We're no longer releasing. 404 | CFBagRemoveValue(gReleasingObjects, self); 405 | pthread_cond_broadcast(&gReleasingObjectsCond); 406 | } pthread_mutex_unlock(&gWeakMutex); 407 | } 408 | 409 | /** 410 | * A helper function used when enumerating the CFSet of weak reference addresses. It clears out 411 | * the given address. 412 | */ 413 | static void ClearAddress(const void *value, void *context) { 414 | void **address = (void **)value; 415 | *address = NULL; 416 | } 417 | 418 | /** 419 | * A swizzled dealloc implementation which clears all weak references to the object before beginning destruction. 420 | */ 421 | static void SwizzledDeallocIMP(PLObjectPtr self, SEL _cmd) { 422 | struct TLS *tls = GetTLS(); 423 | 424 | pthread_mutex_lock(&gWeakMutex); { 425 | // Clear all weak references and delete the addresses set. 426 | CFSetRef addresses = CFDictionaryGetValue(gObjectToAddressesMap, self); 427 | if (addresses != NULL) 428 | CFSetApplyFunction(addresses, ClearAddress, NULL); 429 | CFDictionaryRemoveValue(gObjectToAddressesMap, self); 430 | 431 | // Although the releasing objects table hasn't changed, the value that others 432 | // will load out of weak pointers to this object has, at which point they will 433 | // no longer find it (i.e. nil) in the table, so we signal the change. 434 | pthread_cond_broadcast(&gReleasingObjectsCond); 435 | } pthread_mutex_unlock(&gWeakMutex); 436 | 437 | // We follow the same basic procedure as in SwizzledReleaseIMP to properly handle recursion. 438 | Class lastSent = (__bridge Class)CFDictionaryGetValue(tls->lastDeallocClassTable, self); 439 | Class targetClass = lastSent == Nil ? object_getClass(self) : class_getSuperclass(lastSent); 440 | targetClass = TopClassImplementingMethod(targetClass, deallocSELSwizzled); 441 | CFDictionarySetValue(tls->lastDeallocClassTable, self, (__bridge void *)targetClass); 442 | 443 | // Call through to the original implementation. 444 | void (*origIMP)(PLObjectPtr, SEL) = (__typeof__(origIMP))class_getMethodImplementation(targetClass, deallocSELSwizzled); 445 | origIMP(self, _cmd); 446 | 447 | // And clear our last class entry, to clean up for the next guy with this pointer. 448 | // Note: a new object may now exist at this pointer, BUT this is still safe, since 449 | // the dictionary is thread-local. Really. I think. Right? 450 | CFDictionaryRemoveValue(tls->lastDeallocClassTable, self); 451 | } 452 | 453 | /** 454 | * Swizzle out a method on a given class. 455 | * 456 | * @param c the class to manipulate 457 | * @param orig the original selector of the method 458 | * @param new the swizzled selector of the method; the original implementation will be found here afterwards 459 | * @param newIMP the new method implementation to install under "orig" 460 | */ 461 | static void Swizzle(Class c, SEL orig, SEL new, IMP newIMP) { 462 | Method m = class_getInstanceMethod(c, orig); 463 | IMP origIMP = method_getImplementation(m); 464 | class_addMethod(c, new, origIMP, method_getTypeEncoding(m)); 465 | class_replaceMethod(c, orig, newIMP, method_getTypeEncoding(m)); 466 | } 467 | 468 | /** 469 | * Ensure that the appropriate swizzling has been done to the given object's class. 470 | * 471 | * @param obj the object to check 472 | */ 473 | static void EnsureDeallocationTrigger(PLObjectPtr obj) { 474 | Class c = object_getClass(obj); 475 | if (CFSetContainsValue(gSwizzledClasses, (__bridge const void *)c)) 476 | return; 477 | 478 | Swizzle(c, releaseSEL, releaseSELSwizzled, (IMP)SwizzledReleaseIMP); 479 | Swizzle(c, deallocSEL, deallocSELSwizzled, (IMP)SwizzledDeallocIMP); 480 | 481 | CFSetAddValue(gSwizzledClasses, (__bridge const void *)c); 482 | } 483 | -------------------------------------------------------------------------------- /PLWeakCompatibility/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /PLWeakCompatibility/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // PLWeakCompatibility 4 | // 5 | // Created by Michael Ash on 3/28/12. 6 | // Copyright (c) 2012 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "PLAppDelegate.h" 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([PLAppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /PLWeakCompatibilityTests/PLWeakCompatibilityTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | coop.plausible.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /PLWeakCompatibilityTests/PLWeakCompatibilityTests.h: -------------------------------------------------------------------------------- 1 | // 2 | // PLWeakCompatibilityTests.h 3 | // PLWeakCompatibilityTests 4 | // 5 | // Created by Michael Ash on 3/28/12. 6 | // Copyright (c) 2012 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface PLWeakCompatibilityTests : SenTestCase 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /PLWeakCompatibilityTests/PLWeakCompatibilityTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // PLWeakCompatibilityTests.m 3 | // PLWeakCompatibilityTests 4 | // 5 | // Created by Michael Ash on 3/28/12. 6 | // Copyright (c) 2012 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "PLWeakCompatibilityTests.h" 10 | 11 | #import 12 | #import 13 | 14 | #define EXCLUDE_STUB_PROTOTYPES 1 15 | #import "PLWeakCompatibilityStubs.h" 16 | 17 | 18 | #define TESTCLASS(name, superclass) \ 19 | @interface name : superclass \ 20 | @property (copy) dispatch_block_t releaseBlock; \ 21 | @property (copy) dispatch_block_t deallocBlock; \ 22 | @end \ 23 | @implementation name { SEL _release; } \ 24 | @synthesize releaseBlock = _releaseBlock ## name, deallocBlock = _deallocBlock ## name; \ 25 | - (id) init { \ 26 | self = [super init]; \ 27 | _release = sel_getUid("release"); \ 28 | Method m = class_getInstanceMethod([name class], @selector(release_toswizzle)); \ 29 | class_addMethod([name class], _release, method_getImplementation(m), method_getTypeEncoding(m)); \ 30 | return self; \ 31 | } \ 32 | - (void) release_toswizzle { \ 33 | if ([self releaseBlock] != nil) [self releaseBlock](); \ 34 | if (_release == NULL) _release = sel_getUid("release"); \ 35 | struct { void *obj, *class; } superStruct = { (__bridge void *)self, (__bridge void *)[superclass class] }; \ 36 | void (*msgSendSuper)(void *, SEL) = (void (*)(void *, SEL))objc_msgSendSuper; \ 37 | msgSendSuper(&superStruct, _release); \ 38 | } \ 39 | - (void) dealloc { \ 40 | if ([self deallocBlock] != nil) [self deallocBlock](); \ 41 | _release = NULL; \ 42 | } \ 43 | @end 44 | 45 | TESTCLASS(PLWeakCompatibilityTestClass1, NSObject) 46 | TESTCLASS(PLWeakCompatibilityTestClass2, PLWeakCompatibilityTestClass1) 47 | TESTCLASS(PLWeakCompatibilityTestClass3, PLWeakCompatibilityTestClass2) 48 | 49 | @interface PLWeakCompatibilityEmptyTestSubclass : NSObject @end 50 | @implementation PLWeakCompatibilityEmptyTestSubclass @end 51 | 52 | @interface PLWeakCompatibilityManipulateSelfInDeallocClass : NSObject @end 53 | @implementation PLWeakCompatibilityManipulateSelfInDeallocClass 54 | 55 | - (void) dealloc { 56 | CFRelease(CFBridgingRetain(self)); 57 | } 58 | 59 | @end 60 | 61 | @implementation PLWeakCompatibilityTests 62 | 63 | - (void) enumerateConfigurations: (void (^)(void)) block { 64 | PLWeakCompatibilitySetFallthroughEnabled(YES); 65 | PLWeakCompatibilitySetMAZWREnabled(NO); 66 | block(); 67 | 68 | PLWeakCompatibilitySetFallthroughEnabled(NO); 69 | block(); 70 | 71 | PLWeakCompatibilitySetMAZWREnabled(YES); 72 | if (PLWeakCompatibilityHasMAZWR()) { 73 | block(); 74 | } else { 75 | NSLog(@"Unable to test MAZeroingWeakRef usage as MAZWR is not present"); 76 | } 77 | } 78 | 79 | - (void) testBasics { 80 | [self enumerateConfigurations: ^{ 81 | __weak id weakObj; 82 | 83 | @autoreleasepool { 84 | id obj = [[PLWeakCompatibilityEmptyTestSubclass alloc] init]; 85 | weakObj = obj; 86 | STAssertNotNil(weakObj, @"Weak pointer should not be nil"); 87 | 88 | obj = nil; 89 | } 90 | 91 | STAssertNil(weakObj, @"Weak pointer should be nil after destroying the object"); 92 | }]; 93 | } 94 | 95 | - (void) testInheritance { 96 | [self enumerateConfigurations: ^{ 97 | __weak id weakObj1; 98 | __weak id weakObj2; 99 | 100 | @autoreleasepool { 101 | PLWeakCompatibilityTestClass1 *obj1 = [[PLWeakCompatibilityTestClass1 alloc] init]; 102 | PLWeakCompatibilityTestClass2 *obj2 = [[PLWeakCompatibilityTestClass2 alloc] init]; 103 | 104 | weakObj1 = obj1; 105 | weakObj2 = obj2; 106 | 107 | STAssertNotNil(weakObj1, @"Test object 1 should not be nil"); 108 | STAssertNotNil(weakObj2, @"Test object 2 should not be nil"); 109 | 110 | NSArray *array = [NSArray arrayWithObjects: obj1, obj2, nil]; 111 | array = [NSArray arrayWithObjects: obj2, obj1, nil]; 112 | NSMutableArray *mutableArray = [array mutableCopy]; 113 | [mutableArray removeAllObjects]; 114 | } 115 | 116 | STAssertNil(weakObj1, @"Test object 1 should be nil"); 117 | STAssertNil(weakObj2, @"Test object 2 should be nil"); 118 | }]; 119 | } 120 | 121 | - (void) testDeallocDeadlock { 122 | [self enumerateConfigurations: ^{ 123 | /* MAZeroingWeakRef is (currently?) susceptible to this deadlock, so don't test it 124 | * since we don't want to deadlock the tests. */ 125 | if (PLWeakCompatibilityHasMAZWR()) { 126 | return; 127 | } 128 | 129 | @autoreleasepool { 130 | __weak id weakSelf = self; 131 | 132 | PLWeakCompatibilityTestClass1 *obj = [[PLWeakCompatibilityTestClass1 alloc] init]; 133 | [obj setDeallocBlock: ^{ 134 | dispatch_group_t group = dispatch_group_create(); 135 | dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{ 136 | [weakSelf self]; 137 | }); 138 | dispatch_group_wait(group, DISPATCH_TIME_FOREVER); 139 | dispatch_release(group); 140 | }]; 141 | __weak id weakObj = obj; 142 | obj = nil; 143 | weakObj = nil; 144 | } 145 | }]; 146 | } 147 | 148 | - (void) testGrabDuringRelease { 149 | /* This test only applies to the built-in ZWR implementation (the OS's can grab a weak ref 150 | * while blocked in release, and MAZWR will use that when it's available), so exclude other 151 | * configurations. */ 152 | PLWeakCompatibilitySetFallthroughEnabled(NO); 153 | PLWeakCompatibilitySetMAZWREnabled(NO); 154 | 155 | /* Declare the target and a weak reference to it. Target is a void * so we can have 156 | * better control over its lifetime. Also note the massive proliferation of 157 | * @autoreleasepool blocks for the same reason. */ 158 | __block const void *target; 159 | __weak PLWeakCompatibilityTestClass1 *weakTarget; 160 | 161 | @autoreleasepool { 162 | target = CFBridgingRetain([[PLWeakCompatibilityTestClass1 alloc] init]); 163 | weakTarget = (__bridge id)target; 164 | } 165 | 166 | /* Set up the block that will be used to acquire the weak reference. Do it now so 167 | * all of the weak calls used to set up the block are complete before we start blocking. */ 168 | __block BOOL acquired; 169 | dispatch_semaphore_t acquiredSem = dispatch_semaphore_create(0); 170 | dispatch_block_t acquireBlock; 171 | @autoreleasepool { 172 | acquireBlock = [^{ 173 | id target = weakTarget; 174 | acquired = target != nil; 175 | dispatch_semaphore_signal(acquiredSem); 176 | } copy]; 177 | } 178 | 179 | /* Make the object block when released. */ 180 | dispatch_semaphore_t releaseStartedSem = dispatch_semaphore_create(0); 181 | dispatch_semaphore_t releaseSem = dispatch_semaphore_create(0); 182 | void (*setReleaseBlock)(const void *, SEL, dispatch_block_t); 183 | @autoreleasepool { 184 | setReleaseBlock = (void *)[(__bridge id)target methodForSelector: @selector(setReleaseBlock:)]; 185 | } 186 | /* When this line runs, target MUST have a retain count of 1, and must do nothing more than be released 187 | * and deallocate, because this release block is only safe to run once. The rest of the code is set up 188 | * to make that happen. */ 189 | dispatch_retain(releaseStartedSem); 190 | dispatch_retain(releaseSem); 191 | setReleaseBlock(target, @selector(setReleaseBlock:), ^{ 192 | dispatch_semaphore_signal(releaseStartedSem); 193 | dispatch_semaphore_wait(releaseSem, DISPATCH_TIME_FOREVER); 194 | dispatch_release(releaseSem); 195 | dispatch_release(releaseStartedSem); 196 | }); 197 | 198 | /* Start the release in the background, but it will wait. */ 199 | dispatch_async(dispatch_get_global_queue(0, 0), ^{ 200 | CFRelease(target); 201 | target = NULL; 202 | }); 203 | 204 | /* We want to wait for it to get started here. */ 205 | dispatch_semaphore_wait(releaseStartedSem, DISPATCH_TIME_FOREVER); 206 | 207 | /* target is now blocked in release. Start trying to acquire it. */ 208 | dispatch_async(dispatch_get_global_queue(0, 0), acquireBlock); 209 | 210 | /* Wait a moment to ensure everybody is blocked. */ 211 | [NSThread sleepUntilDate: [NSDate dateWithTimeIntervalSinceNow: 1.0]]; 212 | 213 | /* Unblock the release. */ 214 | dispatch_semaphore_signal(releaseSem); 215 | 216 | /* Wait for acquisition. */ 217 | dispatch_semaphore_wait(acquiredSem, DISPATCH_TIME_FOREVER); 218 | 219 | /* Make sure we got nil. */ 220 | STAssertFalse(acquired, @"Should have loaded nil from the weak reference while releasing."); 221 | 222 | /* Clean up. */ 223 | dispatch_release(releaseSem); 224 | dispatch_release(releaseStartedSem); 225 | dispatch_release(acquiredSem); 226 | } 227 | 228 | - (void) testMultithreadedRelease { 229 | [self enumerateConfigurations: ^{ 230 | /* Use a lot of iterations because this bug doesn't show up reliably. */ 231 | for(int n = 0; n < 100000; n++) { 232 | const void *targetCF; 233 | __weak PLWeakCompatibilityTestClass1 *weakTarget; 234 | 235 | /* Create the target in an autorelease pool so we can control its lifetime. */ 236 | @autoreleasepool { 237 | PLWeakCompatibilityTestClass1 *target = [[PLWeakCompatibilityTestClass1 alloc] init]; 238 | weakTarget = target; 239 | targetCF = CFBridgingRetain(target); 240 | } 241 | 242 | /* At this point, target has a retain count of 1. Bump that up so we can get some simultaneous release going. */ 243 | CFRetain(targetCF); 244 | 245 | /* Release it twice in the background. */ 246 | for (int i = 0; i < 2; i++) 247 | [NSThread detachNewThreadSelector: @selector(invoke) toTarget: [^{ 248 | @autoreleasepool { 249 | CFRelease(targetCF); 250 | } 251 | } copy] withObject: nil]; 252 | 253 | /* Wait for the weak target to go nil. If the ZWR implementation is vulnerable to race conditions between multiple 254 | * release calls, this will *occasionally* trigger it. */ 255 | while (1) { 256 | @autoreleasepool { 257 | id target = weakTarget; 258 | if (target == nil) { 259 | break; 260 | } 261 | } 262 | } 263 | } 264 | }]; 265 | } 266 | 267 | - (void) testReleaseInDealloc { 268 | [self enumerateConfigurations: ^{ 269 | id obj = [[PLWeakCompatibilityManipulateSelfInDeallocClass alloc] init]; 270 | __weak id weakObj = obj; 271 | [obj self]; 272 | [weakObj self]; 273 | }]; 274 | } 275 | 276 | @end 277 | -------------------------------------------------------------------------------- /PLWeakCompatibilityTests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | PLWeakCompatibility 2 | =================== 3 | 4 | Do you like ARC but need to support older OSes? Do you contemplate dropping support for Mac OS X 10.6 or iOS 4 just so you can use `__weak`? Good news! Now you can use `__weak` on those older OSes by just dropping a file into your project and adding a couple of compiler flags. 5 | 6 | `PLWeakCompatibility` is a set of stubs that implement the Objective-C runtime functions the compiler uses to make `__weak` work. It automatically calls through to the real runtime functions if they're present (i.e. your app is running on iOS5+ or Mac OS X 10.7+) and uses its own implementation if they're not. 7 | 8 | To use `PLWeakCompatibility`: 9 | 10 | 1. Drop `PLWeakCompatibilityStubs.m` into your project. 11 | 2. Add these flags to your Other C Flags in your Xcode target settings: `-Xclang -fobjc-runtime-has-weak`. 12 | 3. There is no step 3! 13 | 14 | Note that, by default, `PLWeakCompatibility` uses `MAZeroingWeakRef` to handle `__weak` *if* `MAZeroingWeakRef` is present. If not, it uses its own, less sophisticated, internal implementation. If you are already using `MAZeroingWeakRef`, then `PLWeakCompatibility` will take advantage of it. If you're not, you don't need it. There is nothing you need to do to enable the use of `MAZeroingWeakRef`, it will simply be used if it's in your project. 15 | 16 | 17 | Implementation Notes 18 | -------------------- 19 | 20 | The built-in weak reference implementation is basic but serviceable. It works by swizzling out `-release` and `-dealloc` on target classes directly. This means that every instance of any weakly referenced class takes a performance hit for those operations, even for instances which are not themselves weakly referenced. 21 | 22 | This swizzling *should* be benign, but as with all things runtime manipulation, problems may occur. In particular, I do not anticipate weak references to bridged CoreFoundation objects working at all, and there may be conflicts with Key-Value Observing. The good news is that, since the `PLWeakCompatibility` implementation is only active on older OSes, you have stable targets to test against, and can know that future updates won't affect compatibility. 23 | 24 | 25 | Compatibility Notes 26 | ------------------- 27 | 28 | `PLWeakCompatibility` *should* be fully compatible with any OS/architecture/compiler combination which supports ARC. Since the calls are generated at compile time, and the stubs simply call through to Apple's implementations when available, it's extremely unlikely that a future OS update will break an app that uses `PLWeakCompatibility`. All of the tricky business happens on OSes which will not receive further updates. 29 | 30 | It is possible that a future version of Xcode will include a compiler which does not get along with these stubs. We consider this possibility to be unlikely, but it's possible in theory. If it does happen, you may continue to build using an old compiler for as long as you support iOS 4 or Mac OS 10.6, and we also hope to be able to fix up any incompatibilities in the unlikely event that this occurs. 31 | --------------------------------------------------------------------------------