From a16318fde5c9651777aaf1e34fd6d4e81496d7aa Mon Sep 17 00:00:00 2001 From: Remy Demarest Date: Thu, 6 Oct 2011 16:41:50 -0400 Subject: [PATCH 01/17] Added KVO workaround. The workaround allows to reference weakly an object that already has KVO observers and still keep the zeroing power. --- Source/MAZeroingWeakRef.m | 41 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/Source/MAZeroingWeakRef.m b/Source/MAZeroingWeakRef.m index 023e616..d991bd5 100644 --- a/Source/MAZeroingWeakRef.m +++ b/Source/MAZeroingWeakRef.m @@ -56,6 +56,13 @@ - (BOOL)_isKVOA; @end #endif +@interface NSObject (MAKVODummyObservedProperty) +@property(nonatomic) int MAZeroingWeakRef_KVO_dummy_observableProperty; +@end + +@interface MAZeroingWeakRef_KVO_dummy_observer : NSObject ++ (id)dummyObserver; +@end @interface MAZeroingWeakRef () @@ -64,7 +71,6 @@ - (void)_executeCleanupBlockWithTarget: (id)target; @end - static id (*objc_loadWeak_fptr)(id *location); static id (*objc_storeWeak_fptr)(id *location, id obj); @@ -295,6 +301,10 @@ static void KVOSubclassRelease(id self, SEL _cmd) static void KVOSubclassDealloc(id self, SEL _cmd) { + Class cls = object_getClass(self); + [self removeObserver:[MAZeroingWeakRef_KVO_dummy_observer dummyObserver] forKeyPath:@"MAZeroingWeakRef_KVO_dummy_observableProperty"]; + object_setClass(self, cls); + ClearWeakRefsForObject(self); IMP originalDealloc = class_getMethodImplementation(object_getClass(self), @selector(MAZeroingWeakRef_KVO_original_dealloc)); ((void (*)(id, SEL))originalDealloc)(self, _cmd); @@ -486,7 +496,6 @@ static Class CreatePlainCustomSubclass(Class class) static void PatchKVOSubclass(Class class) { - NSLog(@"Patching KVO class %s", class_getName(class)); Method release = class_getInstanceMethod(class, @selector(release)); Method dealloc = class_getInstanceMethod(class, @selector(dealloc)); @@ -527,6 +536,7 @@ static Class CreateCustomSubclass(Class class, id obj) } else if(IsKVOSubclass(obj)) { + [obj addObserver:[MAZeroingWeakRef_KVO_dummy_observer dummyObserver] forKeyPath:@"MAZeroingWeakRef_KVO_dummy_observableProperty" options:0x0 context:[MAZeroingWeakRef_KVO_dummy_observer dummyObserver]]; PatchKVOSubclass(class); return class; } @@ -693,3 +703,30 @@ - (void)_executeCleanupBlockWithTarget: (id)target } @end + +@implementation MAZeroingWeakRef_KVO_dummy_observer ++ (id)dummyObserver; +{ + static id dummyObserver = nil; + + if(dummyObserver == nil) + { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + dummyObserver = [[MAZeroingWeakRef_KVO_dummy_observer alloc] init]; + }); + } + + return dummyObserver; +} + +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context +{ +} + +@end + +@implementation NSObject (MAKVODummyObservedProperty) +- (int)MAZeroingWeakRef_KVO_dummy_observableProperty { return 0; } +- (void)setMAZeroingWeakRef_KVO_dummy_observableProperty:(int)value { } +@end From 01398cbbc089ef674303de95e5c0ae9128598991 Mon Sep 17 00:00:00 2001 From: Remy Demarest Date: Thu, 6 Oct 2011 17:31:24 -0400 Subject: [PATCH 02/17] Cleanup hack. --- Source/MAZeroingWeakRef.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/MAZeroingWeakRef.m b/Source/MAZeroingWeakRef.m index d991bd5..6845e7c 100644 --- a/Source/MAZeroingWeakRef.m +++ b/Source/MAZeroingWeakRef.m @@ -301,12 +301,12 @@ static void KVOSubclassRelease(id self, SEL _cmd) static void KVOSubclassDealloc(id self, SEL _cmd) { + ClearWeakRefsForObject(self); + Class cls = object_getClass(self); [self removeObserver:[MAZeroingWeakRef_KVO_dummy_observer dummyObserver] forKeyPath:@"MAZeroingWeakRef_KVO_dummy_observableProperty"]; - object_setClass(self, cls); - ClearWeakRefsForObject(self); - IMP originalDealloc = class_getMethodImplementation(object_getClass(self), @selector(MAZeroingWeakRef_KVO_original_dealloc)); + IMP originalDealloc = class_getMethodImplementation(object_getClass(self), (cls == object_getClass(self) ? @selector(MAZeroingWeakRef_KVO_original_dealloc) : @selector(dealloc))); ((void (*)(id, SEL))originalDealloc)(self, _cmd); } From e5aea14bd0de2c2448b9cd885a9bc2a44419e76c Mon Sep 17 00:00:00 2001 From: Remy Demarest Date: Sat, 8 Oct 2011 02:24:25 -0400 Subject: [PATCH 03/17] Added flag to prevent the use of ARC runtime functions. --- Source/MAZeroingWeakRef.m | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Source/MAZeroingWeakRef.m b/Source/MAZeroingWeakRef.m index 6845e7c..b46d5e3 100644 --- a/Source/MAZeroingWeakRef.m +++ b/Source/MAZeroingWeakRef.m @@ -14,6 +14,9 @@ #import #import +#ifndef USE_ARC_FUNCTIONS_IF_AVAILABLE +#define USE_ARC_FUNCTIONS_IF_AVAILABLE 1 +#endif /* The COREFOUNDATION_HACK_LEVEL macro allows you to control how much horrible CF @@ -171,7 +174,7 @@ + (void)initialize // the runtime functions Dl_info info; int success = dladdr(objc_allocateClassPair, &info); - if(success) + if(success && USE_ARC_FUNCTIONS_IF_AVAILABLE) { // note: we leak the handle because it's inconsequential // and technically, the fptrs would be invalid after a dlclose From 985fea61ff61acc44edbcfa415a4adb838146ca1 Mon Sep 17 00:00:00 2001 From: Remy Demarest Date: Sat, 8 Oct 2011 02:44:03 -0400 Subject: [PATCH 04/17] Fixed KVO observation bug. The observation is added only if the object is not already observed --- Source/MAZeroingWeakRef.m | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/Source/MAZeroingWeakRef.m b/Source/MAZeroingWeakRef.m index b46d5e3..e78e8b3 100644 --- a/Source/MAZeroingWeakRef.m +++ b/Source/MAZeroingWeakRef.m @@ -146,6 +146,7 @@ @implementation MAZeroingWeakRef static CFMutableDictionaryRef gObjectWeakRefsMap; // maps (non-retained) objects to CFMutableSetRefs containing weak refs +static CFMutableSetRef gObservingInstances; static NSMutableSet *gCustomSubclasses; static NSMutableDictionary *gCustomSubclassMap; // maps regular classes to their custom subclasses @@ -167,6 +168,7 @@ + (void)initialize gObjectWeakRefsMap = CFDictionaryCreateMutable(NULL, 0, NULL, &kCFTypeDictionaryValueCallBacks); gCustomSubclasses = [[NSMutableSet alloc] init]; gCustomSubclassMap = [[NSMutableDictionary alloc] init]; + gObservingInstances = CFSetCreateMutable(NULL, 0, NULL); // see if the 10.7 ZWR runtime functions are available // nothing special about objc_allocateClassPair, it just @@ -307,7 +309,12 @@ static void KVOSubclassDealloc(id self, SEL _cmd) ClearWeakRefsForObject(self); Class cls = object_getClass(self); - [self removeObserver:[MAZeroingWeakRef_KVO_dummy_observer dummyObserver] forKeyPath:@"MAZeroingWeakRef_KVO_dummy_observableProperty"]; + + if(CFSetContainsValue(gObservingInstances, self)) + { + CFSetRemoveValue(gObservingInstances, self); + [self removeObserver:[MAZeroingWeakRef_KVO_dummy_observer dummyObserver] forKeyPath:@"MAZeroingWeakRef_KVO_dummy_observableProperty"]; + } IMP originalDealloc = class_getMethodImplementation(object_getClass(self), (cls == object_getClass(self) ? @selector(MAZeroingWeakRef_KVO_original_dealloc) : @selector(dealloc))); ((void (*)(id, SEL))originalDealloc)(self, _cmd); @@ -539,7 +546,6 @@ static Class CreateCustomSubclass(Class class, id obj) } else if(IsKVOSubclass(obj)) { - [obj addObserver:[MAZeroingWeakRef_KVO_dummy_observer dummyObserver] forKeyPath:@"MAZeroingWeakRef_KVO_dummy_observableProperty" options:0x0 context:[MAZeroingWeakRef_KVO_dummy_observer dummyObserver]]; PatchKVOSubclass(class); return class; } @@ -573,6 +579,16 @@ static void RegisterRef(MAZeroingWeakRef *ref, id target) { WhileLocked({ EnsureCustomSubclass(target); + + // If the real class and the custom class of the target are the same + // then the object is a being observed by KVO + // Add a dummy observer to the target so KVO won't bypass the patched dealloc + if(object_getClass(target) == [gCustomSubclassMap objectForKey:object_getClass(target)] && !CFSetContainsValue(gObservingInstances, target)) + { + CFSetAddValue(gObservingInstances, target); + [target addObserver:[MAZeroingWeakRef_KVO_dummy_observer dummyObserver] forKeyPath:@"MAZeroingWeakRef_KVO_dummy_observableProperty" options:0x0 context:NULL]; + } + AddWeakRefToObject(target, ref); #if COREFOUNDATION_HACK_LEVEL >= 3 if(IsTollFreeBridged(object_getClass(target), target)) @@ -712,13 +728,10 @@ + (id)dummyObserver; { static id dummyObserver = nil; - if(dummyObserver == nil) - { - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - dummyObserver = [[MAZeroingWeakRef_KVO_dummy_observer alloc] init]; - }); - } + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + dummyObserver = [[MAZeroingWeakRef_KVO_dummy_observer alloc] init]; + }); return dummyObserver; } From 5c8f86879ff74f9c3be4859c702dfd5596ff0dba Mon Sep 17 00:00:00 2001 From: Remy Demarest Date: Sat, 8 Oct 2011 02:44:20 -0400 Subject: [PATCH 05/17] Added test cases. --- Source/main.m | 114 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 111 insertions(+), 3 deletions(-) diff --git a/Source/main.m b/Source/main.m index f9988de..b9d033f 100644 --- a/Source/main.m +++ b/Source/main.m @@ -63,6 +63,24 @@ - (void)observeValueForKeyPath: (NSString *)keyPath ofObject: (id)object change: @end +@interface OtherKVOTarget : NSObject {} @end +@implementation OtherKVOTarget + +- (void)setKey: (id)newValue +{ +} + +- (id)key +{ + return nil; +} + +- (void)observeValueForKeyPath: (NSString *)keyPath ofObject: (id)object change: (NSDictionary *)change context: (void *)context +{ +} + +@end + static void WithPool(void (^block)(void)) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; @@ -246,6 +264,7 @@ static void TestNSConstantTarget(void) NSString *str = [[NSMutableString alloc] initWithString: @"Not Constant String"]; MAZeroingWeakRef *ref = [[MAZeroingWeakRef alloc] initWithTarget: str]; [ref release]; + [str release]; }); } @@ -367,7 +386,7 @@ static void TestWeakProxy(void) } NSMutableString *str = [[NSMutableString alloc] init]; - NSMutableString *proxy = [[MAZeroingWeakProxy alloc] initWithTarget: str]; + NSMutableString *proxy = (id)[[MAZeroingWeakProxy alloc] initWithTarget: str]; WithPool(^{ TEST_ASSERT([proxy isEqual: @""]); @@ -438,6 +457,8 @@ static void TestKVOTarget(void) MAZeroingWeakRef *ref = [[MAZeroingWeakRef alloc] initWithTarget: target]; [target setKey: @"value"]; [ref release]; + [target removeObserver:target forKeyPath:@"key"]; + [target release]; } static void TestKVOMultiLevelTarget(void) @@ -448,6 +469,7 @@ static void TestKVOMultiLevelTarget(void) MAZeroingWeakRef *ref = [[MAZeroingWeakRef alloc] initWithTarget: target]; [target removeObserver:target forKeyPath:@"key.whatever"]; [ref release]; + [target release]; } static void TestClassForCoder(void) @@ -456,6 +478,7 @@ static void TestClassForCoder(void) TEST_ASSERT([obj classForCoder] == [NSObject class]); [[[MAZeroingWeakRef alloc] initWithTarget: obj] autorelease]; TEST_ASSERT([obj classForCoder] == [NSObject class]); + [obj release]; } static void TestKVOReleaseNoCrash(void) @@ -492,6 +515,90 @@ static void TestKVOReleaseCrash(void) [ref release]; } +static void TestKVOObserveBeforeWeakRef(void) +{ + KVOTarget *target = [[KVOTarget alloc] init]; + + [target addObserver: target forKeyPath: @"key" options: 0 context: NULL]; + + MAZeroingWeakRef *ref = [[MAZeroingWeakRef alloc] initWithTarget: target]; + + [target setKey: @"value"]; + + WithPool(^{ + TEST_ASSERT([ref target] == target); + }); + + [target removeObserver:target forKeyPath:@"key"]; + + [target release]; + + WithPool(^{ + TEST_ASSERT([ref target] == nil); + }); + [ref release]; +} + +static void TestKVOObserveAfterWeakRef(void) +{ + KVOTarget *target = [[KVOTarget alloc] init]; + + MAZeroingWeakRef *ref = [[MAZeroingWeakRef alloc] initWithTarget: target]; + + [target addObserver: target forKeyPath: @"key" options: 0 context: NULL]; + + [target setKey: @"value"]; + + WithPool(^{ + TEST_ASSERT([ref target] == target); + }); + + [target removeObserver:target forKeyPath:@"key"]; + + [target release]; + + TEST_ASSERT([ref target] == nil); + + [ref release]; +} + +static void TestKVOObserveAfterAfterWeakRef(void) +{ + OtherKVOTarget *faker = [[OtherKVOTarget alloc] init]; + + WithPool(^{ + [MAZeroingWeakRef refWithTarget:faker]; + }); + + [faker addObserver: faker forKeyPath: @"key" options: 0 context: NULL]; + + WithPool(^{ + [MAZeroingWeakRef refWithTarget:faker]; + }); + + [faker removeObserver:faker forKeyPath:@"key"]; + + OtherKVOTarget *target = [[OtherKVOTarget alloc] init]; + + + MAZeroingWeakRef *ref = [[MAZeroingWeakRef alloc] initWithTarget: target]; + + WithPool(^{ + TEST_ASSERT([ref target] == target); + }); + + + [target release]; + + BOOL isNil = [ref target] == nil; + + TEST_ASSERT(isNil); + + + [ref release]; + [faker release]; +} + int main(int argc, const char * argv[]) { WithPool(^{ @@ -513,8 +620,9 @@ int main(int argc, const char * argv[]) TEST(TestKVOTarget); TEST(TestKVOMultiLevelTarget); TEST(TestClassForCoder); - TEST(TestKVOReleaseNoCrash); - TEST(TestKVOReleaseCrash); + TEST(TestKVOObserveAfterWeakRef); + TEST(TestKVOObserveBeforeWeakRef); + TEST(TestKVOObserveAfterAfterWeakRef); NSString *message; if(gFailureCount) From 521cf9834056df64631659d2beee751e652514e9 Mon Sep 17 00:00:00 2001 From: Remy Demarest Date: Sat, 8 Oct 2011 02:44:38 -0400 Subject: [PATCH 06/17] Prevent the use of ARC to test Snow Leopard version. --- ZeroingWeakRef.xcodeproj/project.pbxproj | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ZeroingWeakRef.xcodeproj/project.pbxproj b/ZeroingWeakRef.xcodeproj/project.pbxproj index 2243ea1..5c9bdb1 100644 --- a/ZeroingWeakRef.xcodeproj/project.pbxproj +++ b/ZeroingWeakRef.xcodeproj/project.pbxproj @@ -177,7 +177,10 @@ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = DEBUG; + GCC_PREPROCESSOR_DEFINITIONS = ( + "USE_ARC_FUNCTIONS_IF_AVAILABLE=0", + DEBUG, + ); GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; From 3ec5a05a24f29a172374329b2e839ce0d0e6616c Mon Sep 17 00:00:00 2001 From: Remy Demarest Date: Thu, 27 Oct 2011 10:17:11 -0400 Subject: [PATCH 07/17] MAWeakTimer additions. Allows the creation and scheduling of timers that do not retain their targets and invalidate themselves automatically when the target is deallocated. --- Source/NSTimer+MAWeakTimer.h | 14 +++++++ Source/NSTimer+MAWeakTimer.m | 51 ++++++++++++++++++++++++ ZeroingWeakRef.xcodeproj/project.pbxproj | 6 +++ 3 files changed, 71 insertions(+) create mode 100644 Source/NSTimer+MAWeakTimer.h create mode 100644 Source/NSTimer+MAWeakTimer.m diff --git a/Source/NSTimer+MAWeakTimer.h b/Source/NSTimer+MAWeakTimer.h new file mode 100644 index 0000000..a4b7d37 --- /dev/null +++ b/Source/NSTimer+MAWeakTimer.h @@ -0,0 +1,14 @@ +// +// NSTimer+MAWeakTimer.h +// ZeroingWeakRef +// +// Created by Remy Demarest on 27/10/2011. +// Copyright (c) 2011 NuLayer Inc. All rights reserved. +// + +#import + +@interface NSTimer (MAWeakTimer) ++ (NSTimer *)scheduledWeakTimerWithTimeInterval:(NSTimeInterval)seconds target:(id)target selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)repeats; ++ (NSTimer *)weakTimerWithTimeInterval:(NSTimeInterval)seconds target:(id)target selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)repeats; +@end diff --git a/Source/NSTimer+MAWeakTimer.m b/Source/NSTimer+MAWeakTimer.m new file mode 100644 index 0000000..45a82ba --- /dev/null +++ b/Source/NSTimer+MAWeakTimer.m @@ -0,0 +1,51 @@ +// +// NSTimer+MAWeakTimer.m +// ZeroingWeakRef +// +// Created by Remy Demarest on 27/10/2011. +// Copyright (c) 2011 NuLayer Inc. All rights reserved. +// + +#import "NSTimer+MAWeakTimer.h" +#import "MAZeroingWeakRef.h" +#import "MAZeroingWeakProxy.h" + +@implementation NSTimer (MAWeakTimer) + ++ (NSTimer *)scheduledWeakTimerWithTimeInterval:(NSTimeInterval)seconds target:(id)target selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)repeats; +{ + MAZeroingWeakProxy *proxy = [MAZeroingWeakProxy proxyWithTarget:target]; + + NSTimer *timer = [self scheduledTimerWithTimeInterval:seconds target:proxy selector:aSelector userInfo:userInfo repeats:repeats]; + + MAWeakDeclare(timer); + + [proxy setCleanupBlock: + ^(id target) { + MAWeakImportReturn(timer); + + [timer invalidate]; + }]; + + return timer; +} + ++ (NSTimer *)weakTimerWithTimeInterval:(NSTimeInterval)seconds target:(id)target selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)repeats; +{ + MAZeroingWeakProxy *proxy = [MAZeroingWeakProxy proxyWithTarget:target]; + + NSTimer *timer = [self timerWithTimeInterval:seconds target:proxy selector:aSelector userInfo:userInfo repeats:repeats]; + + MAWeakDeclare(timer); + + [proxy setCleanupBlock: + ^(id target) { + MAWeakImportReturn(timer); + + [timer invalidate]; + }]; + + return timer; +} + +@end diff --git a/ZeroingWeakRef.xcodeproj/project.pbxproj b/ZeroingWeakRef.xcodeproj/project.pbxproj index 5c9bdb1..6a18b20 100644 --- a/ZeroingWeakRef.xcodeproj/project.pbxproj +++ b/ZeroingWeakRef.xcodeproj/project.pbxproj @@ -14,6 +14,7 @@ C2D7541011E2588600816068 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = C2D7540F11E2588600816068 /* main.m */; }; C2DF1F2611ED2C1300EFC8AE /* MAWeakArray.m in Sources */ = {isa = PBXBuildFile; fileRef = C2DF1F2511ED2C1300EFC8AE /* MAWeakArray.m */; }; C2DF1F2B11ED2C4700EFC8AE /* MAWeakDictionary.m in Sources */ = {isa = PBXBuildFile; fileRef = C2DF1F2A11ED2C4700EFC8AE /* MAWeakDictionary.m */; }; + C65F68161459990300D3A417 /* NSTimer+MAWeakTimer.m in Sources */ = {isa = PBXBuildFile; fileRef = C65F68151459990300D3A417 /* NSTimer+MAWeakTimer.m */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -43,6 +44,8 @@ C2DF1F2511ED2C1300EFC8AE /* MAWeakArray.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MAWeakArray.m; sourceTree = ""; }; C2DF1F2911ED2C4700EFC8AE /* MAWeakDictionary.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MAWeakDictionary.h; sourceTree = ""; }; C2DF1F2A11ED2C4700EFC8AE /* MAWeakDictionary.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MAWeakDictionary.m; sourceTree = ""; }; + C65F68141459990300D3A417 /* NSTimer+MAWeakTimer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSTimer+MAWeakTimer.h"; sourceTree = ""; }; + C65F68151459990300D3A417 /* NSTimer+MAWeakTimer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSTimer+MAWeakTimer.m"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -81,6 +84,8 @@ C2DF1F2511ED2C1300EFC8AE /* MAWeakArray.m */, C2DF1F2911ED2C4700EFC8AE /* MAWeakDictionary.h */, C2DF1F2A11ED2C4700EFC8AE /* MAWeakDictionary.m */, + C65F68141459990300D3A417 /* NSTimer+MAWeakTimer.h */, + C65F68151459990300D3A417 /* NSTimer+MAWeakTimer.m */, ); path = Source; sourceTree = ""; @@ -165,6 +170,7 @@ C2DF1F2611ED2C1300EFC8AE /* MAWeakArray.m in Sources */, C2DF1F2B11ED2C4700EFC8AE /* MAWeakDictionary.m in Sources */, C26F610511F207270080EC96 /* MAZeroingWeakProxy.m in Sources */, + C65F68161459990300D3A417 /* NSTimer+MAWeakTimer.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; From 7e69e0eeff6aabf85a83609d98b16f738b96771e Mon Sep 17 00:00:00 2001 From: Remy Demarest Date: Thu, 27 Oct 2011 10:34:10 -0400 Subject: [PATCH 08/17] Added comments. --- Source/NSTimer+MAWeakTimer.m | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Source/NSTimer+MAWeakTimer.m b/Source/NSTimer+MAWeakTimer.m index 45a82ba..476ca6e 100644 --- a/Source/NSTimer+MAWeakTimer.m +++ b/Source/NSTimer+MAWeakTimer.m @@ -14,14 +14,17 @@ @implementation NSTimer (MAWeakTimer) + (NSTimer *)scheduledWeakTimerWithTimeInterval:(NSTimeInterval)seconds target:(id)target selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)repeats; { + // Use a proxy so the message sent by the timer is passed down directly to the target MAZeroingWeakProxy *proxy = [MAZeroingWeakProxy proxyWithTarget:target]; NSTimer *timer = [self scheduledTimerWithTimeInterval:seconds target:proxy selector:aSelector userInfo:userInfo repeats:repeats]; + // Weak retain of the timer to avoid cyclic reference which would prevent the timer from being deallocated until the target is deallocated MAWeakDeclare(timer); [proxy setCleanupBlock: - ^(id target) { + ^(id target) + { MAWeakImportReturn(timer); [timer invalidate]; @@ -32,14 +35,17 @@ + (NSTimer *)scheduledWeakTimerWithTimeInterval:(NSTimeInterval)seconds target:( + (NSTimer *)weakTimerWithTimeInterval:(NSTimeInterval)seconds target:(id)target selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)repeats; { + // Use a proxy so the message sent by the timer is passed down directly to the target MAZeroingWeakProxy *proxy = [MAZeroingWeakProxy proxyWithTarget:target]; NSTimer *timer = [self timerWithTimeInterval:seconds target:proxy selector:aSelector userInfo:userInfo repeats:repeats]; + // Weak retain of the timer to avoid cyclic reference which would prevent the timer from being deallocated until the target is deallocated MAWeakDeclare(timer); [proxy setCleanupBlock: - ^(id target) { + ^(id target) + { MAWeakImportReturn(timer); [timer invalidate]; From e785aa9ae30450e13d16e55cc86101692ae56cff Mon Sep 17 00:00:00 2001 From: Remy Demarest Date: Sun, 20 Nov 2011 22:26:15 -0500 Subject: [PATCH 09/17] Removed weak reference on NSTimer. --- Source/MAZeroingWeakRef.m | 2 +- Source/NSTimer+MAWeakTimer.m | 18 ++++++++---------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/Source/MAZeroingWeakRef.m b/Source/MAZeroingWeakRef.m index e78e8b3..2a770e6 100644 --- a/Source/MAZeroingWeakRef.m +++ b/Source/MAZeroingWeakRef.m @@ -37,7 +37,7 @@ objects and will assert if trying to make a ZWR to one */ #ifndef COREFOUNDATION_HACK_LEVEL -#define COREFOUNDATION_HACK_LEVEL 1 +#define COREFOUNDATION_HACK_LEVEL 0 #endif /* diff --git a/Source/NSTimer+MAWeakTimer.m b/Source/NSTimer+MAWeakTimer.m index 476ca6e..37351ae 100644 --- a/Source/NSTimer+MAWeakTimer.m +++ b/Source/NSTimer+MAWeakTimer.m @@ -17,16 +17,15 @@ + (NSTimer *)scheduledWeakTimerWithTimeInterval:(NSTimeInterval)seconds target:( // Use a proxy so the message sent by the timer is passed down directly to the target MAZeroingWeakProxy *proxy = [MAZeroingWeakProxy proxyWithTarget:target]; + // The timer releases its target as soon as it is invalidated + // thus releasing the proxy object, the proxy object will then release its cleanup block + // releasing the cleanup block will end in releasing the timer + // which in turn will remove all traces of renegade objects from memory NSTimer *timer = [self scheduledTimerWithTimeInterval:seconds target:proxy selector:aSelector userInfo:userInfo repeats:repeats]; - // Weak retain of the timer to avoid cyclic reference which would prevent the timer from being deallocated until the target is deallocated - MAWeakDeclare(timer); - [proxy setCleanupBlock: ^(id target) { - MAWeakImportReturn(timer); - [timer invalidate]; }]; @@ -38,16 +37,15 @@ + (NSTimer *)weakTimerWithTimeInterval:(NSTimeInterval)seconds target:(id)target // Use a proxy so the message sent by the timer is passed down directly to the target MAZeroingWeakProxy *proxy = [MAZeroingWeakProxy proxyWithTarget:target]; + // The timer releases its target as soon as it is invalidated + // thus releasing the proxy object, the proxy object will then release its cleanup block + // releasing the cleanup block will end in releasing the timer + // which in turn will remove all traces of renegade objects from memory NSTimer *timer = [self timerWithTimeInterval:seconds target:proxy selector:aSelector userInfo:userInfo repeats:repeats]; - // Weak retain of the timer to avoid cyclic reference which would prevent the timer from being deallocated until the target is deallocated - MAWeakDeclare(timer); - [proxy setCleanupBlock: ^(id target) { - MAWeakImportReturn(timer); - [timer invalidate]; }]; From 864bdcd2a344d123e26a7e79fc7f86dc85cfda6d Mon Sep 17 00:00:00 2001 From: Remy Demarest Date: Mon, 21 Nov 2011 14:24:40 -0500 Subject: [PATCH 10/17] Get approved on the app store. --- Source/MAZeroingWeakRef.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/MAZeroingWeakRef.m b/Source/MAZeroingWeakRef.m index 2a770e6..4667346 100644 --- a/Source/MAZeroingWeakRef.m +++ b/Source/MAZeroingWeakRef.m @@ -48,7 +48,7 @@ 0 - No hackery, uses the KVO overridden -class to check. */ #ifndef KVO_HACK_LEVEL -#define KVO_HACK_LEVEL 1 +#define KVO_HACK_LEVEL 0 #endif #if KVO_HACK_LEVEL >= 1 From c5aeb3e11131c85a556ff8808d8462ae30adb0b7 Mon Sep 17 00:00:00 2001 From: Remy Demarest Date: Tue, 22 Nov 2011 11:24:41 -0500 Subject: [PATCH 11/17] Macros modified to allow returning any kind of data. --- Source/MAZeroingWeakRef.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Source/MAZeroingWeakRef.h b/Source/MAZeroingWeakRef.h index 1af79ee..0c1c57e 100644 --- a/Source/MAZeroingWeakRef.h +++ b/Source/MAZeroingWeakRef.h @@ -51,22 +51,22 @@ #define __has_feature(feature) 0 #endif -#define MAWeakVar(var) __weak_ ## var +#define MAWeakVar(var) __weak_ ## var #if __has_feature(objc_arc_weak) -#define MAWeakDeclare(var) __weak __typeof__((var)) MAWeakVar(var) = var -#define MAWeakImport(var) __typeof__((MAWeakVar(var))) var = MAWeakVar(var) -#define MAWeakImportReturn(var) MAWeakImport(var); do { if(var == nil) return; } while(NO) +#define MAWeakDeclare(var) __weak __typeof__((var)) MAWeakVar(var) = var +#define MAWeakImport(var) __typeof__((MAWeakVar(var))) var = MAWeakVar(var) +#define MAWeakImportReturn(var, ...) MAWeakImport(var); do { if(var == nil) return __VA_ARGS__; } while(NO) #else -#define MAWeakDeclare(var) __typeof__((var)) MAWeakVar(var) = (id)[MAZeroingWeakRef refWithTarget:var] -#define MAWeakImport(var) __typeof__((MAWeakVar(var))) var = [(MAZeroingWeakRef *)MAWeakVar(var) target] -#define MAWeakImportReturn(var) MAWeakImport(var); do { if(var == nil) return; } while(NO) +#define MAWeakDeclare(var) __typeof__((var)) MAWeakVar(var) = (id)[MAZeroingWeakRef refWithTarget:var] +#define MAWeakImport(var) __typeof__((MAWeakVar(var))) var = [(MAZeroingWeakRef *)MAWeakVar(var) target] +#define MAWeakImportReturn(var, ...) MAWeakImport(var); do { if(var == nil) return __VA_ARGS__; } while(NO) #endif -#define MAWeakSelfDeclare() MAWeakDeclare(self) -#define MAWeakSelfImport() MAWeakImport(self) -#define MAWeakSelfImportReturn() MAWeakImportReturn(self) +#define MAWeakSelfDeclare() MAWeakDeclare(self) +#define MAWeakSelfImport() MAWeakImport(self) +#define MAWeakSelfImportReturn(...) MAWeakImportReturn(self, ##__VA_ARGS__) From c2900d6a3d76aa7ee52ab95799453ca7bf88c79e Mon Sep 17 00:00:00 2001 From: Remy Demarest Date: Fri, 16 Dec 2011 22:23:23 +0100 Subject: [PATCH 12/17] Added objc_arc_weak_capture feature case. --- Source/MAZeroingWeakRef.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Source/MAZeroingWeakRef.h b/Source/MAZeroingWeakRef.h index 0c1c57e..ca7cc34 100644 --- a/Source/MAZeroingWeakRef.h +++ b/Source/MAZeroingWeakRef.h @@ -53,7 +53,13 @@ #define MAWeakVar(var) __weak_ ## var -#if __has_feature(objc_arc_weak) +#if __has_feature(objc_arc_weak_capture) + +#define MAWeakDeclare(var) +#define MAWeakImport(var) __weak_capture(var) +#define MAWeakImportReturn(var, ...) MAWeakImport(var); do { if(var == nil) return __VA_ARGS__; } while(NO) + +#elif __has_feature(objc_arc_weak) #define MAWeakDeclare(var) __weak __typeof__((var)) MAWeakVar(var) = var #define MAWeakImport(var) __typeof__((MAWeakVar(var))) var = MAWeakVar(var) From 70147047c7c4246836fed73279996cb37319b040 Mon Sep 17 00:00:00 2001 From: Remy Demarest Date: Fri, 16 Dec 2011 22:26:18 +0100 Subject: [PATCH 13/17] Factorizing code. --- Source/MAZeroingWeakRef.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Source/MAZeroingWeakRef.h b/Source/MAZeroingWeakRef.h index ca7cc34..40383ad 100644 --- a/Source/MAZeroingWeakRef.h +++ b/Source/MAZeroingWeakRef.h @@ -57,22 +57,21 @@ #define MAWeakDeclare(var) #define MAWeakImport(var) __weak_capture(var) -#define MAWeakImportReturn(var, ...) MAWeakImport(var); do { if(var == nil) return __VA_ARGS__; } while(NO) #elif __has_feature(objc_arc_weak) #define MAWeakDeclare(var) __weak __typeof__((var)) MAWeakVar(var) = var #define MAWeakImport(var) __typeof__((MAWeakVar(var))) var = MAWeakVar(var) -#define MAWeakImportReturn(var, ...) MAWeakImport(var); do { if(var == nil) return __VA_ARGS__; } while(NO) #else #define MAWeakDeclare(var) __typeof__((var)) MAWeakVar(var) = (id)[MAZeroingWeakRef refWithTarget:var] #define MAWeakImport(var) __typeof__((MAWeakVar(var))) var = [(MAZeroingWeakRef *)MAWeakVar(var) target] -#define MAWeakImportReturn(var, ...) MAWeakImport(var); do { if(var == nil) return __VA_ARGS__; } while(NO) #endif +#define MAWeakImportReturn(var, ...) MAWeakImport(var); do { if(var == nil) return __VA_ARGS__; } while(NO) + #define MAWeakSelfDeclare() MAWeakDeclare(self) #define MAWeakSelfImport() MAWeakImport(self) #define MAWeakSelfImportReturn(...) MAWeakImportReturn(self, ##__VA_ARGS__) From 803dbd33f7fcd343b4654d1e109bc9b13c593f13 Mon Sep 17 00:00:00 2001 From: Remy Demarest Date: Sat, 21 Apr 2012 22:29:08 -0400 Subject: [PATCH 14/17] Typing correction for weak references. --- Source/MAZeroingWeakRef.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/MAZeroingWeakRef.h b/Source/MAZeroingWeakRef.h index 40383ad..71babd0 100644 --- a/Source/MAZeroingWeakRef.h +++ b/Source/MAZeroingWeakRef.h @@ -60,8 +60,8 @@ #elif __has_feature(objc_arc_weak) -#define MAWeakDeclare(var) __weak __typeof__((var)) MAWeakVar(var) = var -#define MAWeakImport(var) __typeof__((MAWeakVar(var))) var = MAWeakVar(var) +#define MAWeakDeclare(var) __weak id MAWeakVar(var) = var +#define MAWeakImport(var) __typeof__(var) var = MAWeakVar(var) #else From 47a909cfcc8719d8a2347c0e0fc525908d392fed Mon Sep 17 00:00:00 2001 From: Remy Demarest Date: Sun, 22 Apr 2012 20:51:50 -0400 Subject: [PATCH 15/17] Pulled Mike Ash's repository into the fork. --- .../NativeZWRCheckeriPhone-Info.plist | 47 + NativeZWRChecker/main.m | 175 +++ NativeZWRChecker/sourcedumper.py | 1168 +++++++++++++++++ Source/MANotificationCenterAdditions.h | 0 Source/MANotificationCenterAdditions.m | 0 Source/MAWeakArray.h | 0 Source/MAWeakArray.m | 0 Source/MAWeakDictionary.h | 0 Source/MAWeakDictionary.m | 0 Source/MAZeroingWeakProxy.h | 0 Source/MAZeroingWeakProxy.m | 0 Source/MAZeroingWeakRef.h | 28 +- Source/MAZeroingWeakRef.m | 190 ++- ...MAZeroingWeakRefNativeZWRNotAllowedTable.h | 180 +++ Source/main.m | 122 +- ZeroingWeakRef.xcodeproj/project.pbxproj | 236 +++- .../contents.xcworkspacedata | 0 .../WorkspaceState.xcuserstate | 0 18 files changed, 1958 insertions(+), 188 deletions(-) create mode 100755 NativeZWRChecker/NativeZWRCheckeriPhone-Info.plist create mode 100755 NativeZWRChecker/main.m create mode 100755 NativeZWRChecker/sourcedumper.py mode change 100644 => 100755 Source/MANotificationCenterAdditions.h mode change 100644 => 100755 Source/MANotificationCenterAdditions.m mode change 100644 => 100755 Source/MAWeakArray.h mode change 100644 => 100755 Source/MAWeakArray.m mode change 100644 => 100755 Source/MAWeakDictionary.h mode change 100644 => 100755 Source/MAWeakDictionary.m mode change 100644 => 100755 Source/MAZeroingWeakProxy.h mode change 100644 => 100755 Source/MAZeroingWeakProxy.m mode change 100644 => 100755 Source/MAZeroingWeakRef.h mode change 100644 => 100755 Source/MAZeroingWeakRef.m create mode 100755 Source/MAZeroingWeakRefNativeZWRNotAllowedTable.h mode change 100644 => 100755 Source/main.m mode change 100644 => 100755 ZeroingWeakRef.xcodeproj/project.pbxproj mode change 100644 => 100755 ZeroingWeakRef.xcodeproj/project.xcworkspace/contents.xcworkspacedata mode change 100644 => 100755 ZeroingWeakRef.xcodeproj/project.xcworkspace/xcuserdata/mikeash.xcuserdatad/WorkspaceState.xcuserstate diff --git a/NativeZWRChecker/NativeZWRCheckeriPhone-Info.plist b/NativeZWRChecker/NativeZWRCheckeriPhone-Info.plist new file mode 100755 index 0000000..590b926 --- /dev/null +++ b/NativeZWRChecker/NativeZWRCheckeriPhone-Info.plist @@ -0,0 +1,47 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + ${PRODUCT_NAME} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIconFiles + + CFBundleIdentifier + com.mikeash.${PRODUCT_NAME:rfc1034identifier} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + LSRequiresIPhoneOS + + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/NativeZWRChecker/main.m b/NativeZWRChecker/main.m new file mode 100755 index 0000000..1a24884 --- /dev/null +++ b/NativeZWRChecker/main.m @@ -0,0 +1,175 @@ +// +// main.m +// NativeZWRCheckeriPhone +// +// Created by Michael Ash on 10/15/11. +// Copyright (c) 2011 __MyCompanyName__. All rights reserved. +// + +#import +#import + +#import +#import +#import +#import +#import +#import + + +@implementation NSObject (HackHackHackYourBoat) + +- (BOOL)_isDeallocating { return NO; } + +@end + +static void Check(void) +{ + [NSAutoreleasePool new]; + + char *badClassNames[] = { + "NSProxy", + "__NSPlaceholderArray", + "NSSubrangeData", + "NSJSONSerialization", + "NSCGImageSnapshotRep", + "FEOpenCLContext", + "_PFEncodedData", + "NSPropertyListSerialization", + "FEContext", + "NSPersistentStore", + "HICocoaWindowAdapter", + "NSApplication", + "NSCachedImageRep", + "NSCIImageRep", + "NSCGImageRep", + "NSPasteboard", + "NSFileVersion", + "NSIconRefImageRep", + "NSIconRefBitmapImageRep", + "NSColorPanel", + "NSFontDescriptor", + "NSKnownKeysDictionary", + "__NSPlaceholderSet", + "NSCustomImageRep", + "_NSTemporaryObjectID2", + "NSTemporaryObjectID", + "NSKeyedUnarchiver", + "NSPICTImageRep", + "_NSZombie_", + "NSKnownKeysMappingStrategy2", + "__NSGenericDeallocHandler", + "NSPDFImageRep", + "NSMessageBuilder", + "NSDistributedLock", + "NSKeyedArchiver", + "__CFNotification", + "NSNavFBETopLevelNode", + "Protocol", + "NSTreeNode", + "NSBitmapImageRep", + "NSNotification", + "NSDocumentRevisionsPlaceholderView", + "__NSPlaceholderDictionary", + "DDNonTerminal", + "NSAtomicStoreCacheNode", + "NSViewTemplate", + "__NSPlaceholderOrderedSet", + "Object", + "NSLeafProxy", + "__IncompleteProtocol", + "NSHTTPCookie", + "_PFEncodedString", + "NSEPSImageRep", + "_PFEncodedArray", + "DOMObject", + "UIProgressBar", + "UIWebTextView", + "BasicAccount", + "UIWebBrowserView", + "UIPasteboard", + "_UIDefinitionService", + "_UIDateLabelCache", + "ABPersonLinker", + "WebInspectorWindowController", + "UIPrintInteractionController", + "_TMBlockDebugger", + "UIDocument", + "UISplitViewController", + "MCDependencyManager", + "DADConnection", + "UIApplication", + "UIPrintInfo", + "UIPopoverController", + "UIURLResolver", + "NSSpeechSynthesizer" + }; + + void (*NSApplicationLoadFptr)(void) = dlsym(RTLD_DEFAULT, "NSApplicationLoad"); + if(NSApplicationLoadFptr) + NSApplicationLoadFptr(); + + int count = objc_getClassList(NULL, 0); + Class *classes = malloc(count * sizeof(*classes)); + objc_getClassList(classes, count); + + NSMutableArray *results = [NSMutableArray array]; + + fprintf(stderr, "starting...\n"); + for(int i = 0; i < count; i++) + { + Class c = classes[i]; + + BOOL isBad = NO; + for(Class toCheck = c; toCheck; toCheck = class_getSuperclass(toCheck)) + { + for(unsigned i = 0; i < sizeof(badClassNames) / sizeof(*badClassNames); i++) + { + if(strcmp(class_getName(toCheck), badClassNames[i]) == 0) + isBad = YES; + } + } + if(isBad) + continue; + + id instance = [[c alloc] init]; + + BOOL (*allowsWeakReference)(id, SEL); + SEL allowsWeakReferenceSEL = @selector(allowsWeakReference); + allowsWeakReference = (BOOL (*)(id, SEL))class_getMethodImplementation(c, allowsWeakReferenceSEL); + if((IMP)allowsWeakReference != class_getMethodImplementation(c, @selector(thisHadBetterBeUndefinedIReallyHopeSo))) + { + BOOL allows = allowsWeakReference(instance, allowsWeakReferenceSEL); + if(!allows) + { + const char *name = class_getName(c); + NSMutableData *sha = [NSMutableData dataWithLength: CC_SHA1_DIGEST_LENGTH]; + CC_SHA1(name, (int)strlen(name), [sha mutableBytes]); + + NSDictionary *d = [NSDictionary dictionaryWithObjectsAndKeys: + sha, @"sha", + [NSString stringWithUTF8String: name], @"name", + nil]; + [results addObject: d]; + } + } + } + fprintf(stderr, "done!\n"); + + NSData *data = [NSPropertyListSerialization dataFromPropertyList: results format: NSPropertyListXMLFormat_v1_0 errorDescription: NULL]; + [[NSFileHandle fileHandleWithStandardOutput] writeData: data]; +} + +int main(int argc, char *argv[]) +{ + int (*UIApplicationMainFptr)(int, char **, void *, void *) = dlsym(RTLD_DEFAULT, "UIApplicationMain"); + if(UIApplicationMainFptr) + { + dispatch_async(dispatch_get_main_queue(), ^{ Check(); }); + UIApplicationMainFptr(argc, argv, NULL, NULL); + } + else + { + Check(); + } +} diff --git a/NativeZWRChecker/sourcedumper.py b/NativeZWRChecker/sourcedumper.py new file mode 100755 index 0000000..1a01d41 --- /dev/null +++ b/NativeZWRChecker/sourcedumper.py @@ -0,0 +1,1168 @@ +#!/usr/bin/python + +iOSPlist = """ + + + + + name + __NSOperationInternal + sha + + ROSeGwWpNKnZxacFFj1PFUGoRSQ= + + + + name + __NSStackBlock__ + sha + + 3papHp41j4ZHdNNrNkFTcEBSr8s= + + + + name + NSPort + sha + + We3vJYzFNeejp1rM03UIQ7IK7rI= + + + + name + NSMachPort + sha + + sEAJodm0DwS2BNbVe53fngii5Lc= + + + + name + NSMessagePort + sha + + VHdluyievZ9dDDlwW+dlzDzMSgY= + + + + name + __NSFinalizingBlock__ + sha + + 3AZZFtRa6m+OCKyJrAtzLGJn/wA= + + + + name + NSBlock + sha + + BQpaL8Om1fvPzIXyL+oW67/PnlI= + + + + name + __NSStackBlock + sha + + zRs7gD8UnN6tGEvpRLoBXwiY1ow= + + + + name + __NSAutoBlock + sha + + lyAIsod346R+vjRvhCmmISp/zA4= + + + + name + __NSFinalizingBlock + sha + + jjw57/tev/xpn9vXTJevn8e/5wU= + + + + name + __NSAutoBlock__ + sha + + sX6EDSOPeVb/kkB2sGuBdpYPwQo= + + + + name + _CTNativeGlyphStorage + sha + + Tqpn+KXIPhk/wAlZeVGgjuv7dyY= + + + +""" + +MacPlist = """ + + + + + name + NSWindow + sha + + SFeMN8U0BSGJXEsVB5y4/3tu8a4= + + + + name + NSDrawerWindow + sha + + /NgSMV9gYZR7dN7V+TRqUf8W7x4= + + + + name + NSNavAdvancedSearchController + sha + + TbJhqXch7kQchtzNaHxvbfKT7R4= + + + + name + NSFindPanel + sha + + zYGpaERs/FtA/hC0w04Z/VdobMs= + + + + name + NSCarbonWindow + sha + + ahavRAEYXohNEBwmK/fK9AkLJI4= + + + + name + NSSecureTextView + sha + + LbaEa2rmSFa0uK4Jj4jUn3GNK/Q= + + + + name + __NSAutoBlock + sha + + lyAIsod346R+vjRvhCmmISp/zA4= + + + + name + NSViewHierarchyLock + sha + + CIJQZlV2mLW4ViDWHAdVTjLgsTM= + + + + name + NSBlock + sha + + BQpaL8Om1fvPzIXyL+oW67/PnlI= + + + + name + NSFontPanel + sha + + vqtJfV9j/tynQ0OtJIBs6zYE0ps= + + + + name + __NSStackBlock + sha + + zRs7gD8UnN6tGEvpRLoBXwiY1ow= + + + + name + NSFindPatternFieldEditor + sha + + rXX5qhv5U5M14xaY/H7l7JvKZO8= + + + + name + _PFManagedObjectReferenceQueue + sha + + UrTPGUe41WVWdcBG1Dya8iEvxco= + + + + name + __NSFinalizingBlock + sha + + jjw57/tev/xpn9vXTJevn8e/5wU= + + + + name + NSTableOptionsPanel + sha + + Qm66oEUVhjdLMEgOe68K0nVDEPs= + + + + name + NSColorPopoverController + sha + + VKRPkoniO0lucOF1kHm7U19PzD4= + + + + name + NSLazyBrowserCell + sha + + /9eaS5QRt7u4JU00YIBG3DqV7eM= + + + + name + NSTableOptions + sha + + CRF7IZAowDmQm8WpD68IQ565ncM= + + + + name + NSStringDrawingTextStorage + sha + + SgzNnuoeiuoPAPPnM7FvW0JVVUU= + + + + name + _NSFullScreenWindow + sha + + gxE/KY51+hnKgl8M5kBgmaXMsNU= + + + + name + _NSMagnifierWindow + sha + + 6FjBniKPQyf85Jf7Jusye6+DwYk= + + + + name + _NSCachedAttributedString + sha + + q+3V5uisAQ0gV39x/RjMaXIKHUI= + + + + name + _NSNonretainedFullScreenWindow + sha + + puhB56xY9iFkgq2oZRpUWIzTVKA= + + + + name + NSSubTextStorage + sha + + b8VsLCw34olyVrN9ti1nTNBfVcE= + + + + name + NSCorrectionSubPanel + sha + + GkQ7kZTSNF5KGNlxFyzE+lpxTLU= + + + + name + NSToolTipPanel + sha + + lp+Z+UkqDP4ITu3UK2k57xK6GAI= + + + + name + NSTokenTextView + sha + + Ttf83RkW7X6eg44lXKbmDuE2w7E= + + + + name + NSTextTab + sha + + f7VofsahuBSzG9Lszpk+A3IdF84= + + + + name + NSAccessoryWindow + sha + + Q6z7uarex+PgkTJgrf7SRP51vGs= + + + + name + NSCorrectionPanel + sha + + HJDf026wh9bEpDPZn/neafSAffQ= + + + + name + NSFontManager + sha + + 3ZSbDioAG3dNHOYikR0AxPJRqnc= + + + + name + NSPrintPreviewController + sha + + anKU3rnEk4bMiB4Di39yfFGW+7o= + + + + name + NSISObjectiveVariable + sha + + Bw9S7Pex5Sp8OdRhF3Ymjnpcj7I= + + + + name + NSPort + sha + + We3vJYzFNeejp1rM03UIQ7IK7rI= + + + + name + NSMachPort + sha + + sEAJodm0DwS2BNbVe53fngii5Lc= + + + + name + NSParagraphStyle + sha + + dvUt4yMQmGGsWZlZ2j2NpgpnN8A= + + + + name + NSMutableParagraphStyle + sha + + +iyzpRrhoAOUQuJsqqH4I7ISjv0= + + + + name + NSMessagePort + sha + + VHdluyievZ9dDDlwW+dlzDzMSgY= + + + + name + NSExceptionAlertController + sha + + lR/CLWuBi8ZtYomSaF9LVHS8G0M= + + + + name + NSISNonNegativeVariableWithDelegate + sha + + GtoRBKxZzliZCAWux59ffB6r8xI= + + + + name + NSFont + sha + + 2xon5Aci9SfDzcgrtiwlQPlGpHM= + + + + name + NSNavNewFolderController + sha + + +YmCkaf8Q+4bA+/MSAgRUZty6RQ= + + + + name + NSNavProgressErrorViewController + sha + + v4NLJvLDJMVkXUyWhu1CHIMFNIw= + + + + name + _NSBorderlessLayerTreeProjectionWindow + sha + + vmYan5nzSrmnsAatwYHf4h4Bi/Q= + + + + name + NSManagedObjectID + sha + + KwHd7qY430VSAaMzGCouFwWWgUo= + + + + name + NSSavePanel + sha + + 8aVWn479HMFaFcUCDVa0G3AQ3wo= + + + + name + NSISNonNegativeVariableWithDelegateToBeMinimized + sha + + kSnm/5yoG3gzXvXW9vM0qSdo3Eg= + + + + name + NSStatusBarWindow + sha + + aDpl8bpqf6f7EuQfUyWtdIgNczA= + + + + name + _NSSlideAndCrossFadeAnimationProjectionWindow + sha + + N29wQ0c/FJv4HlfLQNZU1NFvxl4= + + + + name + NSPanel + sha + + nbOBxM5LSG2AavThMdqNx4OrxaE= + + + + name + __NSSharedFontInstanceInfo + sha + + Hfw+cCmab76aPudWHmQT6Wr9yc0= + + + + name + _NSDuplicateDocumentAnimationProjectionWindow + sha + + k2sV+fK5+4ZCsp12qpo+r0c7S5c= + + + + name + _NSSavePanelTextView + sha + + X8BeiDqxkZz5nRn+eamPekIDfHI= + + + + name + NSISNonNegativeMarkerVariableToBeMinimized + sha + + 87iKzyPmaeh2Qp2xSgKxn4SkOT4= + + + + name + NSBrowserColumnViewController + sha + + 3l09TtZ6XGvnSkwKv75f30g0gOg= + + + + name + NSExternalRefCountedData + sha + + tGkj/ekPJBm3p5Lh7RvRoK5khYc= + + + + name + NSISNonNegativeVariableToBeMinimized + sha + + BYOuxVYFzrPVGOkwt3D0eMmv3VQ= + + + + name + NSISPureMarkerVariable + sha + + 8s5xPyEDG1dlM7/nI02Zghu59jQ= + + + + name + NSNavProgressStatusViewController + sha + + fXYY9mdJ8CfQMRTzzk1ulSaVobk= + + + + name + NSDockMiniViewWindow + sha + + 3ZeRBWfU7XCsylSRUpqDl9InMkU= + + + + name + NSISNonNegativeVariable + sha + + 2QkSOU2kA4sCE0rGWNWeUErwAjY= + + + + name + __NSFontTypefaceInfo + sha + + M0YWTuFHGjKCbq5h7fgOJ6h22gg= + + + + name + NSCarbonMenuWindow + sha + + iegw7vmHI9dVQXH+vWpqCfioqbA= + + + + name + _NSTextFinderOverlayWindow + sha + + wy4SWbpy11FAc+Ph+x6XsMXB5Os= + + + + name + NSSpellingPanel + sha + + IEXWZk7TRqIxvNSRu8Z/r5oW81U= + + + + name + NSISVariable + sha + + PYR5FhTbcicFsSuM7fsf5mWbozI= + + + + name + NSATSGlyphStorage + sha + + B0BGyq1tzEkmPIG4C+chzCjPwyQ= + + + + name + NSText + sha + + wZS0fLqk9TpDBqOEZOv34OC2mFU= + + + + name + NSNavFilepathInputController + sha + + OGBcP6MLw40+BzMeVPPtiCkOr8M= + + + + name + NSNavProgressWindow + sha + + /NR/6hsRv+uSVyNwCRKJr4Si3zE= + + + + name + NSISNonNegativeMarkerVariable + sha + + hF1GmfJvPnDQBwQyaIJdrdtdlok= + + + + name + __NSOperationInternal + sha + + ROSeGwWpNKnZxacFFj1PFUGoRSQ= + + + + name + NSSingleLineTypesetter + sha + + mEoN+Xv4IBzGQEMGB2wU1yUhJbc= + + + + name + NSISVariableWithDelegate + sha + + JJc4QSvnGGdiBd3fwVdZScQWMpQ= + + + + name + NSNavProgressWindowController + sha + + qpt1Mw+o+tqNStZMQxJHTRCywKA= + + + + name + _NSBrowserTableColumnViewController + sha + + H/UmwkD3kRafI04jpP3P4LcSvgU= + + + + name + NSImage + sha + + 98w7UxBrKaYsvbQzj6JGUJ+X5nc= + + + + name + NSATSTypesetter + sha + + 6i+fLL9rpyN+ZHDMdZypvXAs0WY= + + + + name + _NSPopoverWindow + sha + + 7NDJV6/O/hXno6ss2nKurRdFhrE= + + + + name + NSRulerMarkerPanel + sha + + Z66vWYyjSvjpCuh8GEgANLxKaUA= + + + + name + _NSCoreManagedObjectID + sha + + ULIuKpe0CGGpUXIgdL+F5FSzGiQ= + + + + name + __NSFinalizingBlock__ + sha + + 3AZZFtRa6m+OCKyJrAtzLGJn/wA= + + + + name + _NSBrowserPreviewColumnViewController + sha + + W4odqX5yXXCBzwzguHOPXIXWoeE= + + + + name + __NSATSStringSegment + sha + + bzQVPTMn4pgVaw3FsAmOiyJAiJw= + + + + name + _NSBrowserMatrixColumnViewController + sha + + Ohkhh6cAV7VU31NQV+eI9oU9XnM= + + + + name + NSPersistentUIWindowInfo + sha + + 5fBFUxrIXWvsMyb2QL5JGKvRHag= + + + + name + _NSAutomaticFocusRingOverlayWindow + sha + + qS/ZwOqufQPYXr5n7l+wYNBXelw= + + + + name + NSPersistentUIEncodedReference + sha + + 3BCrWRJDZBJ54IKz+c079E17lCU= + + + + name + __NSAutoBlock__ + sha + + sX6EDSOPeVb/kkB2sGuBdpYPwQo= + + + + name + NSLineFragmentRenderingContext + sha + + rGK8uSbdJD0/xCZHUMa7a1aTFiw= + + + + name + NSComboBoxWindow + sha + + oGMLwra+9sOGRwcO2O//kuUx6QA= + + + + name + NSProgressPanel + sha + + U03ljaFAy3oaJ9OJJDna0UYc8IQ= + + + + name + _NSFlippedImage + sha + + vHs+POfjFBtGd0TbQ8OkuTFmCMc= + + + + name + NSOpenPanel + sha + + 8+tajnD2v0E3iS6US5QjfTRsRrQ= + + + + name + _NSOrderOutAnimationProxyWindow + sha + + d+DVB4OnLn66rGqql0dPtCbo1co= + + + + name + NSScalarObjectID64 + sha + + mN/zOpK3GneP90WS0CIYsMzFT5Y= + + + + name + _NSFullScreenUnbufferedWindow + sha + + NcJeItBLWUr+x7IMtY0HS+5KNVI= + + + + name + NSTableCellView + sha + + A1uBQqIOINc58aSoIYYd3KXvCTQ= + + + + name + NSBasicObjectID + sha + + XyJyWRP4cds6vqAbr+12C5rzXtg= + + + + name + __NSStackBlock__ + sha + + 3papHp41j4ZHdNNrNkFTcEBSr8s= + + + + name + NSTextViewCompletionWindow + sha + + co0ndJdiBotr7JJRSr1DyKpsWAk= + + + + name + NSScalarObjectID48 + sha + + 6IwZlZkW4FMH/eDeHEVEL6Ov7pA= + + + + name + NSTypeSelectPanel + sha + + 5k9PqB+GISss6qvE1SFmTNhboJM= + + + + name + NSDocumentRevisionsTimelineWindow + sha + + Sj7E61aLBYq7vqDbWNJbme8MNsA= + + + + name + _NSScalarObjectID + sha + + EaNh4n2xPuTh0XoNxHRSdrC1frM= + + + + name + NSNavNodeSharedServerController + sha + + N3Kbz1/PiHVyjvFs5chixV/izVw= + + + + name + NSCollectionViewItem + sha + + mLK2tFhdKjwMyCfnbmMHflOyUFk= + + + + name + NSNavNodePreviewController + sha + + 6caXQIAux9K9ydl7IXQjQw/hWnE= + + + + name + _NSQuickLookWrapperDocumentWindow + sha + + D31WdK2TSOK9K1y09vjS/EfA9Lk= + + + + name + NSColorSpace + sha + + lcprGOTF+DWuLMEs3M3sTsp2lAY= + + + + name + NSPrintPanelOldAccessoryController + sha + + fN11drCx/Ms+11Hj9JN41SfCTMQ= + + + + name + _PFTask + sha + + dUvjXLAgFMqMYWDceu4PiBmfp2g= + + + + name + NSWindowController + sha + + fxg65zpHoYZciz2tdOd7o3HOtu0= + + + + name + NSAttributeDictionary + sha + + OikvRNnrgR6JITga0Tb1G7EP4qU= + + + + name + NSSidebarImage + sha + + mlem51SivOYgKEJgkwMUnd/b2k8= + + + + name + NSViewController + sha + + ooON0P+jNonvYry11rt6S/b2sfs= + + + + name + NSDocumentRevisionsWindow + sha + + 0lNAsunn2KqpjFmZAQkrqVqMBKQ= + + + + name + _NSToolbarDefaultImageRepWindow + sha + + 8fXzOOF3REOIBDYCOPz8+6gXTA4= + + + + name + NSNavPreviewController + sha + + 4b+uu16zT6HmTrDXeJa6mVHGFL4= + + + + name + NSTempAttributeDictionary + sha + + 82aVtqcnZnAvxUo45js0DVQhh44= + + + + name + NSNavSharedServerController + sha + + RbjLn+o68uMwnVPFNpVKaVXqhe4= + + + + name + _NSFullScreenTransitionOverlayWindow + sha + + c7HGS1SwVkIm0Az0KCMSN620faw= + + + + name + NSTextView + sha + + bgdKj9Wtpr9iFUmamPuebJopXkU= + + + + name + PBOXMenuWindow + sha + + rg0DJXYfH0VYJbiPqDdy/fW38YU= + + + + name + NSToolbarConfigPanel + sha + + HzqAu6fBQcmlh0Zs6FMPMSzkgu0= + + + + name + NSLocalWindowWrappingRemoteWindow + sha + + TJZzArlE4x8Lr6u68BwcEgC3hr8= + + + + name + NSToolbarFullScreenWindow + sha + + aSDvp1iijMMgobjNdUZA/AWuYQo= + + + +""" + + +import plistlib + +iOSPlist = plistlib.readPlistFromString(iOSPlist) +MacPlist = plistlib.readPlistFromString(MacPlist) + + +def PrintArray(hashesToNames, indent): + indentStr = ' ' * indent * 4 + for byte in range(256): + matching = [x for x in hashesToNames.keys() if x.startswith(chr(byte))] + if matching: + d = {} + for hash in matching: + if len(hash) > 1: + d[hash[1:]] = hashesToNames[hash] + if len(d) > 1: + print '%s[0x%x] = { 1, (struct _NativeZWRTableEntry[256]) { // %d' % (indentStr, byte, indent) + PrintArray(d, indent + 1) + print indentStr + '}},' + elif d: + hash = d.keys()[0] + hashBytes = ['0x%x' % ord(x) for x in hash] + hashC = ', '.join(hashBytes) + print '%s[0x%x] = { 0, (unsigned char[]){ %s } }, // %s' % (indentStr, byte, hashC, d[hash]) + else: + for hash in matching: + print '%s[0x%x] = { 0, &_MAZeroingWeakRefClassPresentToken }, // %s' % (indentStr, byte, hashesToNames[hash]) + + + +hashesToNames = {} +for x in iOSPlist + MacPlist: + hashesToNames[x['sha'].data] = x['name'] + +print 'static void *_MAZeroingWeakRefClassPresentToken = &_MAZeroingWeakRefClassPresentToken;' +print 'struct _NativeZWRTableEntry { BOOL isTable; void *ptr; };' +print 'static struct _NativeZWRTableEntry _MAZeroingWeakRefClassNativeWeakReferenceNotAllowedTable[256] = {' +PrintArray(hashesToNames, 1) +print '};' diff --git a/Source/MANotificationCenterAdditions.h b/Source/MANotificationCenterAdditions.h old mode 100644 new mode 100755 diff --git a/Source/MANotificationCenterAdditions.m b/Source/MANotificationCenterAdditions.m old mode 100644 new mode 100755 diff --git a/Source/MAWeakArray.h b/Source/MAWeakArray.h old mode 100644 new mode 100755 diff --git a/Source/MAWeakArray.m b/Source/MAWeakArray.m old mode 100644 new mode 100755 diff --git a/Source/MAWeakDictionary.h b/Source/MAWeakDictionary.h old mode 100644 new mode 100755 diff --git a/Source/MAWeakDictionary.m b/Source/MAWeakDictionary.m old mode 100644 new mode 100755 diff --git a/Source/MAZeroingWeakProxy.h b/Source/MAZeroingWeakProxy.h old mode 100644 new mode 100755 diff --git a/Source/MAZeroingWeakProxy.m b/Source/MAZeroingWeakProxy.m old mode 100644 new mode 100755 diff --git a/Source/MAZeroingWeakRef.h b/Source/MAZeroingWeakRef.h old mode 100644 new mode 100755 index 71babd0..38b5687 --- a/Source/MAZeroingWeakRef.h +++ b/Source/MAZeroingWeakRef.h @@ -11,6 +11,7 @@ @interface MAZeroingWeakRef : NSObject { id _target; + BOOL _nativeZWR; #if NS_BLOCKS_AVAILABLE void (^_cleanupBlock)(id target); #endif @@ -51,27 +52,22 @@ #define __has_feature(feature) 0 #endif -#define MAWeakVar(var) __weak_ ## var +#define MAWeakVar(var) __weak_ ## var -#if __has_feature(objc_arc_weak_capture) +#if __has_feature(objc_arc_weak) -#define MAWeakDeclare(var) -#define MAWeakImport(var) __weak_capture(var) - -#elif __has_feature(objc_arc_weak) - -#define MAWeakDeclare(var) __weak id MAWeakVar(var) = var -#define MAWeakImport(var) __typeof__(var) var = MAWeakVar(var) +#define MAWeakDeclare(var) __weak __typeof__((var)) MAWeakVar(var) = var +#define MAWeakImport(var) __typeof__((MAWeakVar(var))) var = MAWeakVar(var) +#define MAWeakImportReturn(var) MAWeakImport(var); do { if(var == nil) return; } while(NO) #else -#define MAWeakDeclare(var) __typeof__((var)) MAWeakVar(var) = (id)[MAZeroingWeakRef refWithTarget:var] -#define MAWeakImport(var) __typeof__((MAWeakVar(var))) var = [(MAZeroingWeakRef *)MAWeakVar(var) target] +#define MAWeakDeclare(var) __typeof__((var)) MAWeakVar(var) = (id)[MAZeroingWeakRef refWithTarget:var] +#define MAWeakImport(var) __typeof__((MAWeakVar(var))) var = [(MAZeroingWeakRef *)MAWeakVar(var) target] +#define MAWeakImportReturn(var) MAWeakImport(var); do { if(var == nil) return; } while(NO) #endif -#define MAWeakImportReturn(var, ...) MAWeakImport(var); do { if(var == nil) return __VA_ARGS__; } while(NO) - -#define MAWeakSelfDeclare() MAWeakDeclare(self) -#define MAWeakSelfImport() MAWeakImport(self) -#define MAWeakSelfImportReturn(...) MAWeakImportReturn(self, ##__VA_ARGS__) +#define MAWeakSelfDeclare() MAWeakDeclare(self) +#define MAWeakSelfImport() MAWeakImport(self) +#define MAWeakSelfImportReturn() MAWeakImportReturn(self) diff --git a/Source/MAZeroingWeakRef.m b/Source/MAZeroingWeakRef.m old mode 100644 new mode 100755 index 4667346..2f51a70 --- a/Source/MAZeroingWeakRef.m +++ b/Source/MAZeroingWeakRef.m @@ -7,6 +7,10 @@ #import "MAZeroingWeakRef.h" +#import "MAZeroingWeakRefNativeZWRNotAllowedTable.h" + +#import + #import #import #import @@ -14,9 +18,6 @@ #import #import -#ifndef USE_ARC_FUNCTIONS_IF_AVAILABLE -#define USE_ARC_FUNCTIONS_IF_AVAILABLE 1 -#endif /* The COREFOUNDATION_HACK_LEVEL macro allows you to control how much horrible CF @@ -51,6 +52,19 @@ #define KVO_HACK_LEVEL 0 #endif +/* + The USE_BLOCKS_BASED_LOCKING macro allows control on the code structure used + during lock checking. You want to disable blocks if you want your app to work + on iOS 3.x devices. iOS 4.x and above can use blocks. + + 1 - Use blocks for lock checks. + + 0 - Don't use blocks for lock checks. + */ +#ifndef USE_BLOCKS_BASED_LOCKING +#define USE_BLOCKS_BASED_LOCKING 1 +#endif + #if KVO_HACK_LEVEL >= 1 @interface NSObject (KVOPrivateMethod) @@ -59,13 +73,8 @@ - (BOOL)_isKVOA; @end #endif -@interface NSObject (MAKVODummyObservedProperty) -@property(nonatomic) int MAZeroingWeakRef_KVO_dummy_observableProperty; -@end -@interface MAZeroingWeakRef_KVO_dummy_observer : NSObject -+ (id)dummyObserver; -@end +static void EnsureCustomSubclass(id obj); @interface MAZeroingWeakRef () @@ -74,6 +83,7 @@ - (void)_executeCleanupBlockWithTarget: (id)target; @end + static id (*objc_loadWeak_fptr)(id *location); static id (*objc_storeWeak_fptr)(id *location, id obj); @@ -146,7 +156,6 @@ @implementation MAZeroingWeakRef static CFMutableDictionaryRef gObjectWeakRefsMap; // maps (non-retained) objects to CFMutableSetRefs containing weak refs -static CFMutableSetRef gObservingInstances; static NSMutableSet *gCustomSubclasses; static NSMutableDictionary *gCustomSubclassMap; // maps regular classes to their custom subclasses @@ -168,7 +177,6 @@ + (void)initialize gObjectWeakRefsMap = CFDictionaryCreateMutable(NULL, 0, NULL, &kCFTypeDictionaryValueCallBacks); gCustomSubclasses = [[NSMutableSet alloc] init]; gCustomSubclassMap = [[NSMutableDictionary alloc] init]; - gObservingInstances = CFSetCreateMutable(NULL, 0, NULL); // see if the 10.7 ZWR runtime functions are available // nothing special about objc_allocateClassPair, it just @@ -176,7 +184,7 @@ + (void)initialize // the runtime functions Dl_info info; int success = dladdr(objc_allocateClassPair, &info); - if(success && USE_ARC_FUNCTIONS_IF_AVAILABLE) + if(success) { // note: we leak the handle because it's inconsequential // and technically, the fptrs would be invalid after a dlclose @@ -203,7 +211,6 @@ + (void)initialize } } -#define USE_BLOCKS_BASED_LOCKING 1 #if USE_BLOCKS_BASED_LOCKING #define BLOCK_QUALIFIER __block static void WhileLocked(void (^block)(void)) @@ -307,19 +314,30 @@ static void KVOSubclassRelease(id self, SEL _cmd) static void KVOSubclassDealloc(id self, SEL _cmd) { ClearWeakRefsForObject(self); - - Class cls = object_getClass(self); - - if(CFSetContainsValue(gObservingInstances, self)) - { - CFSetRemoveValue(gObservingInstances, self); - [self removeObserver:[MAZeroingWeakRef_KVO_dummy_observer dummyObserver] forKeyPath:@"MAZeroingWeakRef_KVO_dummy_observableProperty"]; - } - - IMP originalDealloc = class_getMethodImplementation(object_getClass(self), (cls == object_getClass(self) ? @selector(MAZeroingWeakRef_KVO_original_dealloc) : @selector(dealloc))); + IMP originalDealloc = class_getMethodImplementation(object_getClass(self), @selector(MAZeroingWeakRef_KVO_original_dealloc)); ((void (*)(id, SEL))originalDealloc)(self, _cmd); } +static void KVOSubclassRemoveObserverForKeyPath(id self, SEL _cmd, id observer, NSString *keyPath) +{ + WhileLocked({ + IMP originalIMP = class_getMethodImplementation(object_getClass(self), @selector(MAZeroingWeakRef_KVO_original_removeObserver:forKeyPath:)); + ((void (*)(id, SEL, id, NSString *))originalIMP)(self, _cmd, observer, keyPath); + + EnsureCustomSubclass(self); + }); +} + +static void KVOSubclassRemoveObserverForKeyPathContext(id self, SEL _cmd, id observer, NSString *keyPath, void *context) +{ + WhileLocked({ + IMP originalIMP = class_getMethodImplementation(object_getClass(self), @selector(MAZeroingWeakRef_KVO_original_removeObserver:forKeyPath:context:)); + ((void (*)(id, SEL, id, NSString *, context))originalIMP)(self, _cmd, observer, keyPath, context); + + EnsureCustomSubclass(self); + }); +} + #if COREFOUNDATION_HACK_LEVEL >= 3 static void CallCFReleaseLater(CFTypeRef cf) @@ -485,6 +503,64 @@ static BOOL IsKVOSubclass(id obj) #endif } +// The native ZWR capability table is conceptually a set of SHA1 hashes. +// Hashes are used instead of class names because the table is large and +// contains a lot of private classes. Embedding private class names in +// the binary is likely to cause problems with app review. Manually +// removing all private classes from the table is a lot of work. Using +// hashes allows for reasonably quick checks and no private API names. +// It's implemented as a tree of tables, where each individual table +// maps to a single byte. The top level of the tree is a 256-entry table. +// Table entries are a NULL pointer for leading bytes which aren't present +// at all. Other table entries can either contain a pointer to another +// table (in which case the process continues recursively), or they can +// contain a pointer to a single hash. In this second case, this indicates +// that this hash is the only one present in the table with that prefix +// and so a simple comparison can be used to check for membership at +// that point. +static BOOL HashPresentInTable(unsigned char *hash, int length, struct _NativeZWRTableEntry *table) +{ + while(length) + { + struct _NativeZWRTableEntry entry = table[hash[0]]; + if(entry.ptr == NULL) + { + return NO; + } + else if(!entry.isTable) + { + return memcmp(entry.ptr, hash + 1, length - 1) == 0; + } + else + { + hash++; + length--; + table = entry.ptr; + } + } + return NO; +} + +static BOOL CanNativeZWRClass(Class c) +{ + if(!c) + return YES; + + const char *name = class_getName(c); + unsigned char hash[CC_SHA1_DIGEST_LENGTH]; + CC_SHA1(name, strlen(name), hash); + + if(HashPresentInTable(hash, CC_SHA1_DIGEST_LENGTH, _MAZeroingWeakRefClassNativeWeakReferenceNotAllowedTable)) + return NO; + else + return CanNativeZWRClass(class_getSuperclass(c)); +} + +static BOOL CanNativeZWR(id obj) +{ + return CanNativeZWRClass(object_getClass(obj)); +} + static Class CreatePlainCustomSubclass(Class class) { NSString *newName = [NSString stringWithFormat: @"%s_MAZeroingWeakRefSubclass", class_getName(class)]; @@ -506,14 +582,39 @@ static Class CreatePlainCustomSubclass(Class class) static void PatchKVOSubclass(Class class) { +// NSLog(@"Patching KVO class %s", class_getName(class)); + Method removeObserverForKeyPath = class_getInstanceMethod(class, @selector(removeObserver:forKeyPath:)); Method release = class_getInstanceMethod(class, @selector(release)); Method dealloc = class_getInstanceMethod(class, @selector(dealloc)); + class_addMethod(class, + @selector(MAZeroingWeakRef_KVO_original_removeObserver:forKeyPath:), + method_getImplementation(removeObserverForKeyPath), + method_getTypeEncoding(removeObserverForKeyPath)); class_addMethod(class, @selector(MAZeroingWeakRef_KVO_original_release), method_getImplementation(release), method_getTypeEncoding(release)); class_addMethod(class, @selector(MAZeroingWeakRef_KVO_original_dealloc), method_getImplementation(dealloc), method_getTypeEncoding(dealloc)); + class_replaceMethod(class, + @selector(removeObserver:forKeyPath:), + (IMP)KVOSubclassRemoveObserverForKeyPath, + method_getTypeEncoding(removeObserverForKeyPath)); class_replaceMethod(class, @selector(release), (IMP)KVOSubclassRelease, method_getTypeEncoding(release)); class_replaceMethod(class, @selector(dealloc), (IMP)KVOSubclassDealloc, method_getTypeEncoding(dealloc)); + + // The context variant is only available on 10.7/iOS5+, so only perform that override if the method actually exists. + Method removeObserverForKeyPathContext = class_getInstanceMethod(class, @selector(removeObserver:forKeyPath:context:)); + if(removeObserverForKeyPathContext) + { + class_addMethod(class, + @selector(MAZeroingWeakRef_KVO_original_removeObserver:forKeyPath:context:), + method_getImplementation(removeObserverForKeyPathContext), + method_getTypeEncoding(removeObserverForKeyPathContext)); + class_replaceMethod(class, + @selector(removeObserver:forKeyPath:context:), + (IMP)KVOSubclassRemoveObserverForKeyPathContext, + method_getTypeEncoding(removeObserverForKeyPathContext)); + + } } static void RegisterCustomSubclass(Class subclass, Class superclass) @@ -579,16 +680,6 @@ static void RegisterRef(MAZeroingWeakRef *ref, id target) { WhileLocked({ EnsureCustomSubclass(target); - - // If the real class and the custom class of the target are the same - // then the object is a being observed by KVO - // Add a dummy observer to the target so KVO won't bypass the patched dealloc - if(object_getClass(target) == [gCustomSubclassMap objectForKey:object_getClass(target)] && !CFSetContainsValue(gObservingInstances, target)) - { - CFSetAddValue(gObservingInstances, target); - [target addObserver:[MAZeroingWeakRef_KVO_dummy_observer dummyObserver] forKeyPath:@"MAZeroingWeakRef_KVO_dummy_observableProperty" options:0x0 context:NULL]; - } - AddWeakRefToObject(target, ref); #if COREFOUNDATION_HACK_LEVEL >= 3 if(IsTollFreeBridged(object_getClass(target), target)) @@ -621,9 +712,10 @@ - (id)initWithTarget: (id)target { if((self = [self init])) { - if(objc_storeWeak_fptr) + if(objc_storeWeak_fptr && CanNativeZWR(target)) { objc_storeWeak_fptr(&_target, target); + _nativeZWR = YES; } else { @@ -636,7 +728,7 @@ - (id)initWithTarget: (id)target - (void)dealloc { - if(objc_storeWeak_fptr) + if(objc_storeWeak_fptr && _nativeZWR) objc_storeWeak_fptr(&_target, nil); else UnregisterRef(self); @@ -659,7 +751,7 @@ - (void)setCleanupBlock: (void (^)(id target))block [_cleanupBlock release]; _cleanupBlock = block; - if(objc_loadWeak_fptr) + if(objc_loadWeak_fptr && _nativeZWR) { // wrap a pool around this code, otherwise it artificially extends // the lifetime of the target object @@ -690,7 +782,7 @@ - (void)setCleanupBlock: (void (^)(id target))block - (id)target { - if(objc_loadWeak_fptr) + if(objc_loadWeak_fptr && _nativeZWR) { return objc_loadWeak_fptr(&_target); } @@ -722,27 +814,3 @@ - (void)_executeCleanupBlockWithTarget: (id)target } @end - -@implementation MAZeroingWeakRef_KVO_dummy_observer -+ (id)dummyObserver; -{ - static id dummyObserver = nil; - - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - dummyObserver = [[MAZeroingWeakRef_KVO_dummy_observer alloc] init]; - }); - - return dummyObserver; -} - -- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context -{ -} - -@end - -@implementation NSObject (MAKVODummyObservedProperty) -- (int)MAZeroingWeakRef_KVO_dummy_observableProperty { return 0; } -- (void)setMAZeroingWeakRef_KVO_dummy_observableProperty:(int)value { } -@end diff --git a/Source/MAZeroingWeakRefNativeZWRNotAllowedTable.h b/Source/MAZeroingWeakRefNativeZWRNotAllowedTable.h new file mode 100755 index 0000000..6d06abe --- /dev/null +++ b/Source/MAZeroingWeakRefNativeZWRNotAllowedTable.h @@ -0,0 +1,180 @@ +static void *_MAZeroingWeakRefClassPresentToken = &_MAZeroingWeakRefClassPresentToken; +struct _NativeZWRTableEntry { BOOL isTable; void *ptr; }; +static struct _NativeZWRTableEntry _MAZeroingWeakRefClassNativeWeakReferenceNotAllowedTable[256] = { + [0x3] = { 0, (unsigned char[]){ 0x5b, 0x81, 0x42, 0xa2, 0xe, 0x20, 0xd7, 0x39, 0xf1, 0xa4, 0xa8, 0x21, 0x86, 0x1d, 0xdc, 0xa5, 0xef, 0x9, 0x34 } }, // NSTableCellView + [0x5] = { 1, (struct _NativeZWRTableEntry[256]) { // 1 + [0xa] = { 0, (unsigned char[]){ 0x5a, 0x2f, 0xc3, 0xa6, 0xd5, 0xfb, 0xcf, 0xcc, 0x85, 0xf2, 0x2f, 0xea, 0x16, 0xeb, 0xbf, 0xcf, 0x9e, 0x52 } }, // NSBlock + [0x83] = { 0, (unsigned char[]){ 0xae, 0xc5, 0x56, 0x5, 0xce, 0xb3, 0xd5, 0x18, 0xe9, 0x30, 0xb7, 0x70, 0xf4, 0x78, 0xc9, 0xaf, 0xdd, 0x54 } }, // NSISNonNegativeVariableToBeMinimized + }}, + [0x7] = { 1, (struct _NativeZWRTableEntry[256]) { // 1 + [0xf] = { 0, (unsigned char[]){ 0x52, 0xec, 0xf7, 0xb1, 0xe5, 0x2a, 0x7c, 0x39, 0xd4, 0x61, 0x17, 0x76, 0x26, 0x8e, 0x7a, 0x5c, 0x8f, 0xb2 } }, // NSISObjectiveVariable + [0x40] = { 0, (unsigned char[]){ 0x46, 0xca, 0xad, 0x6d, 0xcc, 0x49, 0x26, 0x3c, 0x81, 0xb8, 0xb, 0xe7, 0x21, 0xcc, 0x28, 0xcf, 0xc3, 0x24 } }, // NSATSGlyphStorage + }}, + [0x8] = { 0, (unsigned char[]){ 0x82, 0x50, 0x66, 0x55, 0x76, 0x98, 0xb5, 0xb8, 0x56, 0x20, 0xd6, 0x1c, 0x7, 0x55, 0x4e, 0x32, 0xe0, 0xb1, 0x33 } }, // NSViewHierarchyLock + [0x9] = { 0, (unsigned char[]){ 0x11, 0x7b, 0x21, 0x90, 0x28, 0xc0, 0x39, 0x90, 0x9b, 0xc5, 0xa9, 0xf, 0xaf, 0x8, 0x43, 0x9e, 0xb9, 0x9d, 0xc3 } }, // NSTableOptions + [0xf] = { 0, (unsigned char[]){ 0x7d, 0x56, 0x74, 0xad, 0x93, 0x48, 0xe2, 0xbd, 0x2b, 0x5c, 0xb4, 0xf6, 0xf8, 0xd2, 0xfc, 0x47, 0xc0, 0xf4, 0xb9 } }, // _NSQuickLookWrapperDocumentWindow + [0x11] = { 0, (unsigned char[]){ 0xa3, 0x61, 0xe2, 0x7d, 0xb1, 0x3e, 0xe4, 0xe1, 0xd1, 0x7a, 0xd, 0xc4, 0x74, 0x52, 0x76, 0xb0, 0xb5, 0x7e, 0xb3 } }, // _NSScalarObjectID + [0x1a] = { 1, (struct _NativeZWRTableEntry[256]) { // 1 + [0x44] = { 0, (unsigned char[]){ 0x3b, 0x91, 0x94, 0xd2, 0x34, 0x5e, 0x4a, 0x18, 0xd9, 0x71, 0x17, 0x2c, 0xc4, 0xfa, 0x5a, 0x71, 0x4c, 0xb5 } }, // NSCorrectionSubPanel + [0xda] = { 0, (unsigned char[]){ 0x11, 0x4, 0xac, 0x59, 0xce, 0x58, 0x99, 0x8, 0x5, 0xae, 0xc7, 0x9f, 0x5f, 0x7c, 0x1e, 0xab, 0xf3, 0x12 } }, // NSISNonNegativeVariableWithDelegate + }}, + [0x1c] = { 0, (unsigned char[]){ 0x90, 0xdf, 0xd3, 0x6e, 0xb0, 0x87, 0xd6, 0xc4, 0xa4, 0x33, 0xd9, 0x9f, 0xf9, 0xde, 0x69, 0xf4, 0x80, 0x7d, 0xf4 } }, // NSCorrectionPanel + [0x1d] = { 0, (unsigned char[]){ 0xfc, 0x3e, 0x70, 0x29, 0x9a, 0x6f, 0xbe, 0x9a, 0x3e, 0xe7, 0x56, 0x1e, 0x64, 0x13, 0xe9, 0x6a, 0xfd, 0xc9, 0xcd } }, // __NSSharedFontInstanceInfo + [0x1f] = { 1, (struct _NativeZWRTableEntry[256]) { // 1 + [0x3a] = { 0, (unsigned char[]){ 0x80, 0xbb, 0xa7, 0xc1, 0x41, 0xc9, 0xa5, 0x87, 0x46, 0x6c, 0xe8, 0x53, 0xf, 0x31, 0x2c, 0xe4, 0x82, 0xed } }, // NSToolbarConfigPanel + [0xf5] = { 0, (unsigned char[]){ 0x26, 0xc2, 0x40, 0xf7, 0x91, 0x16, 0x9f, 0x23, 0x4e, 0x23, 0xa4, 0xfd, 0xcf, 0xe0, 0xb7, 0x12, 0xbe, 0x5 } }, // _NSBrowserTableColumnViewController + }}, + [0x20] = { 0, (unsigned char[]){ 0x45, 0xd6, 0x66, 0x4e, 0xd3, 0x46, 0xa2, 0x31, 0xbc, 0xd4, 0x91, 0xbb, 0xc6, 0x7f, 0xaf, 0x9a, 0x16, 0xf3, 0x55 } }, // NSSpellingPanel + [0x24] = { 0, (unsigned char[]){ 0x97, 0x38, 0x41, 0x2b, 0xe7, 0x18, 0x67, 0x62, 0x5, 0xdd, 0xdf, 0xc1, 0x57, 0x59, 0x49, 0xc4, 0x16, 0x32, 0x94 } }, // NSISVariableWithDelegate + [0x2b] = { 0, (unsigned char[]){ 0x1, 0xdd, 0xee, 0xa6, 0x38, 0xdf, 0x45, 0x52, 0x1, 0xa3, 0x33, 0x18, 0x2a, 0x2e, 0x17, 0x5, 0x96, 0x81, 0x4a } }, // NSManagedObjectID + [0x2d] = { 0, (unsigned char[]){ 0xb6, 0x84, 0x6b, 0x6a, 0xe6, 0x48, 0x56, 0xb4, 0xb8, 0xae, 0x9, 0x8f, 0x88, 0xd4, 0x9f, 0x71, 0x8d, 0x2b, 0xf4 } }, // NSSecureTextView + [0x33] = { 0, (unsigned char[]){ 0x46, 0x16, 0x4e, 0xe1, 0x47, 0x1a, 0x32, 0x82, 0x6e, 0xae, 0x61, 0xed, 0xf8, 0xe, 0x27, 0xa8, 0x76, 0xda, 0x8 } }, // __NSFontTypefaceInfo + [0x35] = { 0, (unsigned char[]){ 0xc2, 0x5e, 0x22, 0xd0, 0x4b, 0x59, 0x4a, 0xfe, 0xc7, 0xb2, 0xc, 0xb5, 0x8d, 0x7, 0x4b, 0xee, 0x4a, 0x35, 0x52 } }, // _NSFullScreenUnbufferedWindow + [0x37] = { 1, (struct _NativeZWRTableEntry[256]) { // 1 + [0x6f] = { 0, (unsigned char[]){ 0x70, 0x43, 0x47, 0x3f, 0x14, 0x9b, 0xf8, 0x1e, 0x57, 0xcb, 0x40, 0xd6, 0x54, 0xd4, 0xd1, 0x6f, 0xc6, 0x5e } }, // _NSSlideAndCrossFadeAnimationProjectionWindow + [0x72] = { 0, (unsigned char[]){ 0x9b, 0xcf, 0x5f, 0xcf, 0x88, 0x75, 0x72, 0x8e, 0xf1, 0x6c, 0xe5, 0xc8, 0x62, 0xc5, 0x5f, 0xe2, 0xcd, 0x5c } }, // NSNavNodeSharedServerController + }}, + [0x38] = { 0, (unsigned char[]){ 0x60, 0x5c, 0x3f, 0xa3, 0xb, 0xc3, 0x8d, 0x3e, 0x7, 0x33, 0x1e, 0x54, 0xf3, 0xed, 0x88, 0x29, 0xe, 0xaf, 0xc3 } }, // NSNavFilepathInputController + [0x3a] = { 1, (struct _NativeZWRTableEntry[256]) { // 1 + [0x19] = { 0, (unsigned char[]){ 0x21, 0x87, 0xa7, 0x0, 0x57, 0xb5, 0x54, 0xdf, 0x53, 0x50, 0x57, 0xe7, 0x88, 0xf6, 0x85, 0x3d, 0x5e, 0x73 } }, // _NSBrowserMatrixColumnViewController + [0x29] = { 0, (unsigned char[]){ 0x2f, 0x44, 0xd9, 0xeb, 0x81, 0x1e, 0x89, 0x21, 0x38, 0x1a, 0xd1, 0x36, 0xf5, 0x1b, 0xb1, 0xf, 0xe2, 0xa5 } }, // NSAttributeDictionary + }}, + [0x3d] = { 0, (unsigned char[]){ 0x84, 0x79, 0x16, 0x14, 0xdb, 0x72, 0x27, 0x5, 0xb1, 0x2b, 0x8c, 0xed, 0xfb, 0x1f, 0xe6, 0x65, 0x9b, 0xa3, 0x32 } }, // NSISVariable + [0x42] = { 0, (unsigned char[]){ 0x6e, 0xba, 0xa0, 0x45, 0x15, 0x86, 0x37, 0x4b, 0x30, 0x48, 0xe, 0x7b, 0xaf, 0xa, 0xd2, 0x75, 0x43, 0x10, 0xfb } }, // NSTableOptionsPanel + [0x43] = { 0, (unsigned char[]){ 0xac, 0xfb, 0xb9, 0xaa, 0xde, 0xc7, 0xe3, 0xe0, 0x91, 0x32, 0x60, 0xad, 0xfe, 0xd2, 0x44, 0xfe, 0x75, 0xbc, 0x6b } }, // NSAccessoryWindow + [0x44] = { 0, (unsigned char[]){ 0xe4, 0x9e, 0x1b, 0x5, 0xa9, 0x34, 0xa9, 0xd9, 0xc5, 0xa7, 0x5, 0x16, 0x3d, 0x4f, 0x15, 0x41, 0xa8, 0x45, 0x24 } }, // __NSOperationInternal + [0x45] = { 0, (unsigned char[]){ 0xb8, 0xcb, 0x9f, 0xea, 0x3a, 0xf2, 0xe3, 0x30, 0x9d, 0x53, 0xc5, 0x36, 0x95, 0x4a, 0x69, 0x55, 0xea, 0x85, 0xee } }, // NSNavSharedServerController + [0x48] = { 0, (unsigned char[]){ 0x57, 0x8c, 0x37, 0xc5, 0x34, 0x5, 0x21, 0x89, 0x5c, 0x4b, 0x15, 0x7, 0x9c, 0xb8, 0xff, 0x7b, 0x6e, 0xf1, 0xae } }, // NSWindow + [0x4a] = { 1, (struct _NativeZWRTableEntry[256]) { // 1 + [0xc] = { 0, (unsigned char[]){ 0xcd, 0x9e, 0xea, 0x1e, 0x8a, 0xea, 0xf, 0x0, 0xf3, 0xe7, 0x33, 0xb1, 0x6f, 0x5b, 0x42, 0x55, 0x55, 0x45 } }, // NSStringDrawingTextStorage + [0x3e] = { 0, (unsigned char[]){ 0xc4, 0xeb, 0x56, 0x8b, 0x5, 0x8a, 0xbb, 0xbe, 0xa0, 0xdb, 0x58, 0xd2, 0x5b, 0x99, 0xef, 0xc, 0x36, 0xc0 } }, // NSDocumentRevisionsTimelineWindow + }}, + [0x4c] = { 0, (unsigned char[]){ 0x96, 0x73, 0x2, 0xb9, 0x44, 0xe3, 0x1f, 0xb, 0xaf, 0xab, 0xba, 0xf0, 0x1c, 0x1c, 0x12, 0x0, 0xb7, 0x86, 0xbf } }, // NSLocalWindowWrappingRemoteWindow + [0x4d] = { 0, (unsigned char[]){ 0xb2, 0x61, 0xa9, 0x77, 0x21, 0xee, 0x44, 0x1c, 0x86, 0xdc, 0xcd, 0x68, 0x7c, 0x6f, 0x6d, 0xf2, 0x93, 0xed, 0x1e } }, // NSNavAdvancedSearchController + [0x4e] = { 1, (struct _NativeZWRTableEntry[256]) { // 1 + [0xaa] = { 0, (unsigned char[]){ 0x67, 0xf8, 0xa5, 0xc8, 0x3e, 0x19, 0x3f, 0xc0, 0x9, 0x59, 0x79, 0x51, 0xa0, 0x8e, 0xeb, 0xfb, 0x77, 0x26 } }, // _CTNativeGlyphStorage + [0xd7] = { 0, (unsigned char[]){ 0xfc, 0xdd, 0x19, 0x16, 0xed, 0x7e, 0x9e, 0x83, 0x8e, 0x25, 0x5c, 0xa6, 0xe6, 0xe, 0xe1, 0x36, 0xc3, 0xb1 } }, // NSTokenTextView + }}, + [0x50] = { 0, (unsigned char[]){ 0xb2, 0x2e, 0x2a, 0x97, 0xb4, 0x8, 0x61, 0xa9, 0x51, 0x72, 0x20, 0x74, 0xbf, 0x85, 0xe4, 0x54, 0xb3, 0x1a, 0x24 } }, // _NSCoreManagedObjectID + [0x52] = { 0, (unsigned char[]){ 0xb4, 0xcf, 0x19, 0x47, 0xb8, 0xd5, 0x65, 0x56, 0x75, 0xc0, 0x46, 0xd4, 0x3c, 0x9a, 0xf2, 0x21, 0x2f, 0xc5, 0xca } }, // _PFManagedObjectReferenceQueue + [0x53] = { 0, (unsigned char[]){ 0x4d, 0xe5, 0x8d, 0xa1, 0x40, 0xcb, 0x7a, 0x1a, 0x27, 0xd3, 0x89, 0x24, 0x39, 0xda, 0xd1, 0x46, 0x1c, 0xf0, 0x84 } }, // NSProgressPanel + [0x54] = { 1, (struct _NativeZWRTableEntry[256]) { // 1 + [0x77] = { 0, (unsigned char[]){ 0x65, 0xbb, 0x28, 0x9e, 0xbd, 0x9f, 0x5d, 0xc, 0x39, 0x70, 0x5b, 0xe7, 0x65, 0xcc, 0x3c, 0xcc, 0x4a, 0x6 } }, // NSMessagePort + [0xa4] = { 0, (unsigned char[]){ 0x4f, 0x92, 0x89, 0xe2, 0x3b, 0x49, 0x6e, 0x70, 0xe1, 0x75, 0x90, 0x79, 0xbb, 0x53, 0x5f, 0x4f, 0xcc, 0x3e } }, // NSColorPopoverController + }}, + [0x59] = { 0, (unsigned char[]){ 0xed, 0xef, 0x25, 0x8c, 0xc5, 0x35, 0xe7, 0xa3, 0xa7, 0x5a, 0xcc, 0xd3, 0x75, 0x8, 0x43, 0xb2, 0xa, 0xee, 0xb2 } }, // NSPort + [0x5b] = { 0, (unsigned char[]){ 0x8a, 0x1d, 0xa9, 0x7e, 0x72, 0x5d, 0x70, 0x81, 0xcf, 0xc, 0xe0, 0xb8, 0x73, 0x8f, 0x5c, 0x85, 0xd6, 0xa1, 0xe1 } }, // _NSBrowserPreviewColumnViewController + [0x5f] = { 1, (struct _NativeZWRTableEntry[256]) { // 1 + [0x22] = { 0, (unsigned char[]){ 0x72, 0x59, 0x13, 0xf8, 0x71, 0xdb, 0x3a, 0xbe, 0xa0, 0x1b, 0xaf, 0xed, 0x76, 0xb, 0x9a, 0xf3, 0x5e, 0xd8 } }, // NSBasicObjectID + [0xc0] = { 0, (unsigned char[]){ 0x5e, 0x88, 0x3a, 0xb1, 0x91, 0x9c, 0xf9, 0x9d, 0x19, 0xfe, 0x79, 0xa9, 0x8f, 0x7a, 0x42, 0x3, 0x7c, 0x72 } }, // _NSSavePanelTextView + }}, + [0x67] = { 0, (unsigned char[]){ 0xae, 0xaf, 0x59, 0x8c, 0xa3, 0x4a, 0xf8, 0xe9, 0xa, 0xe8, 0x7c, 0x18, 0x48, 0x0, 0x34, 0xbc, 0x4a, 0x69, 0x40 } }, // NSRulerMarkerPanel + [0x68] = { 0, (unsigned char[]){ 0x3a, 0x65, 0xf1, 0xba, 0x6a, 0x7f, 0xa7, 0xfb, 0x12, 0xe4, 0x1f, 0x53, 0x25, 0xad, 0x74, 0x88, 0xd, 0x73, 0x30 } }, // NSStatusBarWindow + [0x69] = { 0, (unsigned char[]){ 0x20, 0xef, 0xa7, 0x58, 0xa2, 0x8c, 0xc3, 0x20, 0xa1, 0xb8, 0xcd, 0x75, 0x46, 0x40, 0xfc, 0x5, 0xae, 0x61, 0xa } }, // NSToolbarFullScreenWindow + [0x6a] = { 1, (struct _NativeZWRTableEntry[256]) { // 1 + [0x16] = { 0, (unsigned char[]){ 0xaf, 0x44, 0x1, 0x18, 0x5e, 0x88, 0x4d, 0x10, 0x1c, 0x26, 0x2b, 0xf7, 0xca, 0xf4, 0x9, 0xb, 0x24, 0x8e } }, // NSCarbonWindow + [0x72] = { 0, (unsigned char[]){ 0x94, 0xde, 0xb9, 0xc4, 0x93, 0x86, 0xcc, 0x88, 0x1e, 0x3, 0x8b, 0x7f, 0x72, 0x7c, 0x51, 0x96, 0xfb, 0xba } }, // NSPrintPreviewController + }}, + [0x6e] = { 0, (unsigned char[]){ 0x7, 0x4a, 0x8f, 0xd5, 0xad, 0xa6, 0xbf, 0x62, 0x15, 0x49, 0x9a, 0x98, 0xfb, 0x9e, 0x6c, 0x9a, 0x29, 0x5e, 0x45 } }, // NSTextView + [0x6f] = { 1, (struct _NativeZWRTableEntry[256]) { // 1 + [0x34] = { 0, (unsigned char[]){ 0x15, 0x3d, 0x33, 0x27, 0xe2, 0x98, 0x15, 0x6b, 0xd, 0xc5, 0xb0, 0x9, 0x8e, 0x8b, 0x22, 0x40, 0x88, 0x9c } }, // __NSATSStringSegment + [0xc5] = { 0, (unsigned char[]){ 0x6c, 0x2c, 0x2c, 0x37, 0xe2, 0x89, 0x72, 0x56, 0xb3, 0x7d, 0xb6, 0x2d, 0x67, 0x4c, 0xd0, 0x5f, 0x55, 0xc1 } }, // NSSubTextStorage + }}, + [0x72] = { 0, (unsigned char[]){ 0x8d, 0x27, 0x74, 0x97, 0x62, 0x6, 0x8b, 0x6b, 0xec, 0x92, 0x51, 0x4a, 0xbd, 0x43, 0xc8, 0xaa, 0x6c, 0x58, 0x9 } }, // NSTextViewCompletionWindow + [0x73] = { 0, (unsigned char[]){ 0xb1, 0xc6, 0x4b, 0x54, 0xb0, 0x56, 0x42, 0x26, 0xd0, 0xc, 0xf4, 0x28, 0x23, 0x12, 0x37, 0xad, 0xb4, 0x7d, 0xac } }, // _NSFullScreenTransitionOverlayWindow + [0x75] = { 0, (unsigned char[]){ 0x4b, 0xe3, 0x5c, 0xb0, 0x20, 0x14, 0xca, 0x8c, 0x61, 0x60, 0xdc, 0x7a, 0xee, 0xf, 0x88, 0x19, 0x9f, 0xa7, 0x68 } }, // _PFTask + [0x76] = { 0, (unsigned char[]){ 0xf5, 0x2d, 0xe3, 0x23, 0x10, 0x98, 0x61, 0xac, 0x59, 0x99, 0x59, 0xda, 0x3d, 0x8d, 0xa6, 0xa, 0x67, 0x37, 0xc0 } }, // NSParagraphStyle + [0x77] = { 0, (unsigned char[]){ 0xe0, 0xd5, 0x7, 0x83, 0xa7, 0x2e, 0x7e, 0xba, 0xac, 0x6a, 0xaa, 0x97, 0x47, 0x4f, 0xb4, 0x26, 0xe8, 0xd5, 0xca } }, // _NSOrderOutAnimationProxyWindow + [0x7c] = { 0, (unsigned char[]){ 0xdd, 0x75, 0x76, 0xb0, 0xb1, 0xfc, 0xcb, 0x3e, 0xd7, 0x51, 0xe3, 0xf4, 0x93, 0x78, 0xd5, 0x27, 0xc2, 0x4c, 0xc4 } }, // NSPrintPanelOldAccessoryController + [0x7d] = { 0, (unsigned char[]){ 0x76, 0x18, 0xf6, 0x67, 0x49, 0xf0, 0x27, 0xd0, 0x31, 0x14, 0xf3, 0xce, 0x4d, 0x6e, 0x95, 0x26, 0x95, 0xa1, 0xb9 } }, // NSNavProgressStatusViewController + [0x7f] = { 1, (struct _NativeZWRTableEntry[256]) { // 1 + [0x18] = { 0, (unsigned char[]){ 0x3a, 0xe7, 0x3a, 0x47, 0xa1, 0x86, 0x5c, 0x8b, 0x3d, 0xad, 0x74, 0xe7, 0x7b, 0xa3, 0x71, 0xce, 0xb6, 0xed } }, // NSWindowController + [0xb5] = { 0, (unsigned char[]){ 0x68, 0x7e, 0xc6, 0xa1, 0xb8, 0x14, 0xb3, 0x1b, 0xd2, 0xec, 0xce, 0x99, 0x3e, 0x3, 0x72, 0x1d, 0x17, 0xce } }, // NSTextTab + }}, + [0x83] = { 0, (unsigned char[]){ 0x11, 0x3f, 0x29, 0x8e, 0x75, 0xfa, 0x19, 0xca, 0x82, 0x5f, 0xc, 0xe6, 0x40, 0x60, 0x99, 0xa5, 0xcc, 0xb0, 0xd5 } }, // _NSFullScreenWindow + [0x84] = { 0, (unsigned char[]){ 0x5d, 0x46, 0x99, 0xf2, 0x6f, 0x3e, 0x70, 0xd0, 0x7, 0x4, 0x32, 0x68, 0x82, 0x5d, 0xad, 0xdb, 0x5d, 0x96, 0x89 } }, // NSISNonNegativeMarkerVariable + [0x89] = { 0, (unsigned char[]){ 0xe8, 0x30, 0xee, 0xf9, 0x87, 0x23, 0xd7, 0x55, 0x41, 0x71, 0xfe, 0xbd, 0x6a, 0x6a, 0x9, 0xf8, 0xa8, 0xa9, 0xb0 } }, // NSCarbonMenuWindow + [0x8e] = { 0, (unsigned char[]){ 0x3c, 0x39, 0xef, 0xfb, 0x5e, 0xbf, 0xfc, 0x69, 0x9f, 0xdb, 0xd7, 0x4c, 0x97, 0xaf, 0x9f, 0xc7, 0xbf, 0xe7, 0x5 } }, // __NSFinalizingBlock + [0x91] = { 0, (unsigned char[]){ 0x29, 0xe6, 0xff, 0x9c, 0xa8, 0x1b, 0x78, 0x33, 0x5e, 0xf5, 0xd6, 0xf6, 0xf3, 0x34, 0xa9, 0x27, 0x68, 0xdc, 0x48 } }, // NSISNonNegativeVariableWithDelegateToBeMinimized + [0x93] = { 0, (unsigned char[]){ 0x6b, 0x15, 0xf9, 0xf2, 0xb9, 0xfb, 0x86, 0x42, 0xb2, 0x9d, 0x76, 0xaa, 0x9a, 0x3e, 0xaf, 0x47, 0x3b, 0x4b, 0x97 } }, // _NSDuplicateDocumentAnimationProjectionWindow + [0x95] = { 1, (struct _NativeZWRTableEntry[256]) { // 1 + [0x1f] = { 0, (unsigned char[]){ 0xc2, 0x2d, 0x6b, 0x81, 0x8b, 0xc6, 0x6d, 0x62, 0x89, 0x92, 0x68, 0x5f, 0x4b, 0x54, 0x74, 0xbc, 0x1b, 0x43 } }, // NSExceptionAlertController + [0xca] = { 0, (unsigned char[]){ 0x6b, 0x18, 0xe4, 0xc5, 0xf8, 0x35, 0xae, 0x2c, 0xc1, 0x2c, 0xdc, 0xcd, 0xec, 0x4e, 0xca, 0x76, 0x94, 0x6 } }, // NSColorSpace + }}, + [0x96] = { 0, (unsigned char[]){ 0x9f, 0x99, 0xf9, 0x49, 0x2a, 0xc, 0xfe, 0x8, 0x4e, 0xed, 0xd4, 0x2b, 0x69, 0x39, 0xef, 0x12, 0xba, 0x18, 0x2 } }, // NSToolTipPanel + [0x97] = { 0, (unsigned char[]){ 0x20, 0x8, 0xb2, 0x87, 0x77, 0xe3, 0xa4, 0x7e, 0xbe, 0x34, 0x6f, 0x84, 0x29, 0xa6, 0x21, 0x2a, 0x7f, 0xcc, 0xe } }, // __NSAutoBlock + [0x98] = { 1, (struct _NativeZWRTableEntry[256]) { // 1 + [0x4a] = { 0, (unsigned char[]){ 0xd, 0xf9, 0x7b, 0xf8, 0x20, 0x1c, 0xc6, 0x40, 0x43, 0x6, 0x7, 0x6c, 0x14, 0xd7, 0x25, 0x21, 0x25, 0xb7 } }, // NSSingleLineTypesetter + [0xb2] = { 0, (unsigned char[]){ 0xb6, 0xb4, 0x58, 0x5d, 0x2a, 0x3c, 0xc, 0xc8, 0x27, 0xe7, 0x6e, 0x63, 0x7, 0x7e, 0x53, 0xb2, 0x50, 0x59 } }, // NSCollectionViewItem + [0xdf] = { 0, (unsigned char[]){ 0xf3, 0x3a, 0x92, 0xb7, 0x1a, 0x77, 0x8f, 0xf7, 0x45, 0x92, 0xd0, 0x22, 0x18, 0xb0, 0xcc, 0xc5, 0x4f, 0x96 } }, // NSScalarObjectID64 + }}, + [0x9a] = { 0, (unsigned char[]){ 0x57, 0xa6, 0xe7, 0x54, 0xa2, 0xbc, 0xe6, 0x20, 0x28, 0x42, 0x60, 0x93, 0x3, 0x14, 0x9d, 0xdf, 0xdb, 0xda, 0x4f } }, // NSSidebarImage + [0x9d] = { 0, (unsigned char[]){ 0xb3, 0x81, 0xc4, 0xce, 0x4b, 0x48, 0x6d, 0x80, 0x6a, 0xf4, 0xe1, 0x31, 0xda, 0x8d, 0xc7, 0x83, 0xab, 0xc5, 0xa1 } }, // NSPanel + [0xa0] = { 0, (unsigned char[]){ 0x63, 0xb, 0xc2, 0xb6, 0xbe, 0xf6, 0xc3, 0x86, 0x47, 0x7, 0xe, 0xd8, 0xef, 0xff, 0x92, 0xe5, 0x31, 0xe9, 0x0 } }, // NSComboBoxWindow + [0xa2] = { 0, (unsigned char[]){ 0x83, 0x8d, 0xd0, 0xff, 0xa3, 0x36, 0x89, 0xef, 0x62, 0xbc, 0xb5, 0xd6, 0xbb, 0x7a, 0x4b, 0xf6, 0xf6, 0xb1, 0xfb } }, // NSViewController + [0xa6] = { 0, (unsigned char[]){ 0xe8, 0x41, 0xe7, 0xac, 0x58, 0xf6, 0x21, 0x64, 0x82, 0xad, 0xa8, 0x65, 0x1a, 0x54, 0x58, 0x8c, 0xd3, 0x54, 0xa0 } }, // _NSNonretainedFullScreenWindow + [0xa9] = { 0, (unsigned char[]){ 0x2f, 0xd9, 0xc0, 0xea, 0xae, 0x7d, 0x3, 0xd8, 0x5e, 0xbe, 0x67, 0xee, 0x5f, 0xb0, 0x60, 0xd0, 0x57, 0x7a, 0x5c } }, // _NSAutomaticFocusRingOverlayWindow + [0xaa] = { 0, (unsigned char[]){ 0x9b, 0x75, 0x33, 0xf, 0xa8, 0xfa, 0xda, 0x8d, 0x4a, 0xd6, 0x4c, 0x43, 0x12, 0x47, 0x4d, 0x10, 0xb2, 0xc0, 0xa0 } }, // NSNavProgressWindowController + [0xab] = { 0, (unsigned char[]){ 0xed, 0xd5, 0xe6, 0xe8, 0xac, 0x1, 0xd, 0x20, 0x57, 0x7f, 0x71, 0xfd, 0x18, 0xcc, 0x69, 0x72, 0xa, 0x1d, 0x42 } }, // _NSCachedAttributedString + [0xac] = { 0, (unsigned char[]){ 0x62, 0xbc, 0xb9, 0x26, 0xdd, 0x24, 0x3d, 0x3f, 0xc4, 0x26, 0x47, 0x50, 0xc6, 0xbb, 0x6b, 0x56, 0x93, 0x16, 0x2c } }, // NSLineFragmentRenderingContext + [0xad] = { 0, (unsigned char[]){ 0x75, 0xf9, 0xaa, 0x1b, 0xf9, 0x53, 0x93, 0x35, 0xe3, 0x16, 0x98, 0xfc, 0x7e, 0xe5, 0xec, 0x9b, 0xca, 0x64, 0xef } }, // NSFindPatternFieldEditor + [0xae] = { 0, (unsigned char[]){ 0xd, 0x3, 0x25, 0x76, 0x1f, 0x1f, 0x45, 0x58, 0x25, 0xb8, 0x8f, 0xa8, 0x37, 0x72, 0xfd, 0xf5, 0xb7, 0xf1, 0x85 } }, // PBOXMenuWindow + [0xb0] = { 0, (unsigned char[]){ 0x40, 0x9, 0xa1, 0xd9, 0xb4, 0xf, 0x4, 0xb6, 0x4, 0xd6, 0xd5, 0x7b, 0x9d, 0xdf, 0x9e, 0x8, 0xa2, 0xe4, 0xb7 } }, // NSMachPort + [0xb1] = { 0, (unsigned char[]){ 0x7e, 0x84, 0xd, 0x23, 0x8f, 0x79, 0x56, 0xff, 0x92, 0x40, 0x76, 0xb0, 0x6b, 0x81, 0x76, 0x96, 0xf, 0xc1, 0xa } }, // __NSAutoBlock__ + [0xb4] = { 0, (unsigned char[]){ 0x69, 0x23, 0xfd, 0xe9, 0xf, 0x24, 0x19, 0xb7, 0xa7, 0x92, 0xe1, 0xed, 0x1b, 0xd1, 0xa0, 0xae, 0x64, 0x85, 0x87 } }, // NSExternalRefCountedData + [0xbc] = { 0, (unsigned char[]){ 0x7b, 0x3e, 0x3c, 0xe7, 0xe3, 0x14, 0x1b, 0x46, 0x77, 0x44, 0xdb, 0x43, 0xc3, 0xa4, 0xb9, 0x31, 0x66, 0x8, 0xc7 } }, // _NSFlippedImage + [0xbe] = { 1, (struct _NativeZWRTableEntry[256]) { // 1 + [0x66] = { 0, (unsigned char[]){ 0x1a, 0x9f, 0x99, 0xf3, 0x4a, 0xb9, 0xa7, 0xb0, 0x6, 0xad, 0xc1, 0x81, 0xdf, 0xe2, 0x1e, 0x1, 0x8b, 0xf4 } }, // _NSBorderlessLayerTreeProjectionWindow + [0xab] = { 0, (unsigned char[]){ 0x49, 0x7d, 0x5f, 0x63, 0xfe, 0xdc, 0xa7, 0x43, 0x43, 0xad, 0x24, 0x80, 0x6c, 0xeb, 0x36, 0x4, 0xd2, 0x9b } }, // NSFontPanel + }}, + [0xbf] = { 0, (unsigned char[]){ 0x83, 0x4b, 0x26, 0xf2, 0xc3, 0x24, 0xc5, 0x64, 0x5d, 0x4c, 0x96, 0x86, 0xed, 0x42, 0x1c, 0x83, 0x5, 0x34, 0x8c } }, // NSNavProgressErrorViewController + [0xc1] = { 0, (unsigned char[]){ 0x94, 0xb4, 0x7c, 0xba, 0xa4, 0xf5, 0x3a, 0x43, 0x6, 0xa3, 0x84, 0x64, 0xeb, 0xf7, 0xe0, 0xe0, 0xb6, 0x98, 0x55 } }, // NSText + [0xc3] = { 0, (unsigned char[]){ 0x2e, 0x12, 0x59, 0xba, 0x72, 0xd7, 0x51, 0x40, 0x73, 0xe3, 0xe1, 0xfb, 0x1e, 0x97, 0xb0, 0xc5, 0xc1, 0xe4, 0xeb } }, // _NSTextFinderOverlayWindow + [0xcd] = { 1, (struct _NativeZWRTableEntry[256]) { // 1 + [0x1b] = { 0, (unsigned char[]){ 0x3b, 0x80, 0x3f, 0x14, 0x9c, 0xde, 0xad, 0x18, 0x4b, 0xe9, 0x44, 0xba, 0x1, 0x5f, 0x8, 0x98, 0xd6, 0x8c } }, // __NSStackBlock + [0x81] = { 0, (unsigned char[]){ 0xa9, 0x68, 0x44, 0x6c, 0xfc, 0x5b, 0x40, 0xfe, 0x10, 0xb4, 0xc3, 0x4e, 0x19, 0xfd, 0x57, 0x68, 0x6c, 0xcb } }, // NSFindPanel + }}, + [0xd2] = { 0, (unsigned char[]){ 0x53, 0x40, 0xb2, 0xe9, 0xe7, 0xd8, 0xaa, 0xa9, 0x8c, 0x59, 0x99, 0x1, 0x9, 0x2b, 0xa9, 0x5a, 0x8c, 0x4, 0xa4 } }, // NSDocumentRevisionsWindow + [0xd9] = { 0, (unsigned char[]){ 0x9, 0x12, 0x39, 0x4d, 0xa4, 0x3, 0x8b, 0x2, 0x13, 0x4a, 0xc6, 0x58, 0xd5, 0x9e, 0x50, 0x4a, 0xf0, 0x2, 0x36 } }, // NSISNonNegativeVariable + [0xdb] = { 0, (unsigned char[]){ 0x1a, 0x27, 0xe4, 0x7, 0x22, 0xf5, 0x27, 0xc3, 0xcd, 0xc8, 0x2b, 0xb6, 0x2c, 0x25, 0x40, 0xf9, 0x46, 0xa4, 0x73 } }, // NSFont + [0xdc] = { 1, (struct _NativeZWRTableEntry[256]) { // 1 + [0x6] = { 0, (unsigned char[]){ 0x59, 0x16, 0xd4, 0x5a, 0xea, 0x6f, 0x8e, 0x8, 0xac, 0x89, 0xac, 0xb, 0x73, 0x2c, 0x62, 0x67, 0xff, 0x0 } }, // __NSFinalizingBlock__ + [0x10] = { 0, (unsigned char[]){ 0xab, 0x59, 0x12, 0x43, 0x64, 0x12, 0x79, 0xe0, 0x82, 0xb3, 0xf9, 0xcd, 0x3b, 0xf4, 0x4d, 0x7b, 0x94, 0x25 } }, // NSPersistentUIEncodedReference + }}, + [0xdd] = { 1, (struct _NativeZWRTableEntry[256]) { // 1 + [0x94] = { 0, (unsigned char[]){ 0x9b, 0xe, 0x2a, 0x0, 0x1b, 0x77, 0x4d, 0x1c, 0xe6, 0x22, 0x91, 0x1d, 0x0, 0xc4, 0xf2, 0x51, 0xaa, 0x77 } }, // NSFontManager + [0x97] = { 0, (unsigned char[]){ 0x91, 0x5, 0x67, 0xd4, 0xed, 0x70, 0xac, 0xca, 0x54, 0x91, 0x52, 0x9a, 0x83, 0x97, 0xd2, 0x27, 0x32, 0x45 } }, // NSDockMiniViewWindow + }}, + [0xde] = { 1, (struct _NativeZWRTableEntry[256]) { // 1 + [0x5d] = { 0, (unsigned char[]){ 0x3d, 0x4e, 0xd6, 0x7a, 0x5c, 0x6b, 0xe7, 0x4a, 0x4c, 0xa, 0xbf, 0xbe, 0x5f, 0xdf, 0x48, 0x34, 0x80, 0xe8 } }, // NSBrowserColumnViewController + [0x96] = { 0, (unsigned char[]){ 0xa9, 0x1e, 0x9e, 0x35, 0x8f, 0x86, 0x47, 0x74, 0xd3, 0x6b, 0x36, 0x41, 0x53, 0x70, 0x40, 0x52, 0xaf, 0xcb } }, // __NSStackBlock__ + }}, + [0xe1] = { 0, (unsigned char[]){ 0xbf, 0xae, 0xbb, 0x5e, 0xb3, 0x4f, 0xa1, 0xe6, 0x4e, 0xb0, 0xd7, 0x78, 0x96, 0xba, 0x99, 0x51, 0xc6, 0x14, 0xbe } }, // NSNavPreviewController + [0xe5] = { 0, (unsigned char[]){ 0xf0, 0x45, 0x53, 0x1a, 0xc8, 0x5d, 0x6b, 0xec, 0x33, 0x26, 0xf6, 0x40, 0xbe, 0x49, 0x18, 0xab, 0xd1, 0x1d, 0xa8 } }, // NSPersistentUIWindowInfo + [0xe6] = { 0, (unsigned char[]){ 0x4f, 0x4f, 0xa8, 0x1f, 0x86, 0x21, 0x2b, 0x2c, 0xea, 0xab, 0xc4, 0xd5, 0x21, 0x66, 0x4c, 0xd8, 0x5b, 0xa0, 0x93 } }, // NSTypeSelectPanel + [0xe8] = { 1, (struct _NativeZWRTableEntry[256]) { // 1 + [0x58] = { 0, (unsigned char[]){ 0xc1, 0x9e, 0x22, 0x8f, 0x43, 0x27, 0xfc, 0xe4, 0x97, 0xfb, 0x26, 0xeb, 0x32, 0x7b, 0xaf, 0x83, 0xc1, 0x89 } }, // _NSMagnifierWindow + [0x8c] = { 0, (unsigned char[]){ 0x19, 0x95, 0x99, 0x16, 0xe0, 0x53, 0x7, 0xfd, 0xe0, 0xde, 0x1c, 0x45, 0x44, 0x2f, 0xa3, 0xaf, 0xee, 0x90 } }, // NSScalarObjectID48 + }}, + [0xe9] = { 0, (unsigned char[]){ 0xc6, 0x97, 0x40, 0x80, 0x2e, 0xc7, 0xd2, 0xbd, 0xc9, 0xd9, 0x7b, 0x21, 0x74, 0x23, 0x43, 0xf, 0xe1, 0x5a, 0x71 } }, // NSNavNodePreviewController + [0xea] = { 0, (unsigned char[]){ 0x2f, 0x9f, 0x2c, 0xbf, 0x6b, 0xa7, 0x23, 0x7e, 0x64, 0x70, 0xcc, 0x75, 0x9c, 0xa9, 0xbd, 0x70, 0x2c, 0xd1, 0x66 } }, // NSATSTypesetter + [0xec] = { 0, (unsigned char[]){ 0xd0, 0xc9, 0x57, 0xaf, 0xce, 0xfe, 0x15, 0xe7, 0xa3, 0xab, 0x2c, 0xda, 0x72, 0xae, 0xad, 0x17, 0x45, 0x86, 0xb1 } }, // _NSPopoverWindow + [0xf1] = { 1, (struct _NativeZWRTableEntry[256]) { // 1 + [0xa5] = { 0, (unsigned char[]){ 0x56, 0x9f, 0x8e, 0xfd, 0x1c, 0xc1, 0x5a, 0x15, 0xc5, 0x2, 0xd, 0x56, 0xb4, 0x1b, 0x70, 0x10, 0xdf, 0xa } }, // NSSavePanel + [0xf5] = { 0, (unsigned char[]){ 0xf3, 0x38, 0xe1, 0x77, 0x44, 0x43, 0x88, 0x4, 0x36, 0x2, 0x38, 0xfc, 0xfc, 0xfb, 0xa8, 0x17, 0x4c, 0xe } }, // _NSToolbarDefaultImageRepWindow + }}, + [0xf2] = { 0, (unsigned char[]){ 0xce, 0x71, 0x3f, 0x21, 0x3, 0x1b, 0x57, 0x65, 0x33, 0xbf, 0xe7, 0x23, 0x4d, 0x99, 0x82, 0x1b, 0xb9, 0xf6, 0x34 } }, // NSISPureMarkerVariable + [0xf3] = { 1, (struct _NativeZWRTableEntry[256]) { // 1 + [0x66] = { 0, (unsigned char[]){ 0x95, 0xb6, 0xa7, 0x27, 0x66, 0x70, 0x2f, 0xc5, 0x4a, 0x38, 0xe6, 0x3b, 0x34, 0xd, 0x54, 0x21, 0x87, 0x8e } }, // NSTempAttributeDictionary + [0xb8] = { 0, (unsigned char[]){ 0x8a, 0xcf, 0x23, 0xe6, 0x69, 0xe8, 0x76, 0x42, 0x9d, 0xb1, 0x4a, 0x2, 0xb1, 0x9f, 0x84, 0xa4, 0x39, 0x3e } }, // NSISNonNegativeMarkerVariableToBeMinimized + [0xeb] = { 0, (unsigned char[]){ 0x5a, 0x8e, 0x70, 0xf6, 0xbf, 0x41, 0x37, 0x89, 0x2e, 0x94, 0x4b, 0x94, 0x23, 0x7d, 0x34, 0x6c, 0x46, 0xb4 } }, // NSOpenPanel + }}, + [0xf7] = { 0, (unsigned char[]){ 0xcc, 0x3b, 0x53, 0x10, 0x6b, 0x29, 0xa6, 0x2c, 0xbd, 0xb4, 0x33, 0x8f, 0xa2, 0x46, 0x50, 0x9f, 0x97, 0xe6, 0x77 } }, // NSImage + [0xf9] = { 0, (unsigned char[]){ 0x89, 0x82, 0x91, 0xa7, 0xfc, 0x43, 0xee, 0x1b, 0x3, 0xef, 0xcc, 0x48, 0x8, 0x11, 0x51, 0x9b, 0x72, 0xe9, 0x14 } }, // NSNavNewFolderController + [0xfa] = { 0, (unsigned char[]){ 0x2c, 0xb3, 0xa5, 0x1a, 0xe1, 0xa0, 0x3, 0x94, 0x42, 0xe2, 0x6c, 0xaa, 0xa1, 0xf8, 0x23, 0xb2, 0x12, 0x8e, 0xfd } }, // NSMutableParagraphStyle + [0xfc] = { 1, (struct _NativeZWRTableEntry[256]) { // 1 + [0xd4] = { 0, (unsigned char[]){ 0x7f, 0xea, 0x1b, 0x11, 0xbf, 0xeb, 0x92, 0x57, 0x23, 0x70, 0x9, 0x12, 0x89, 0xaf, 0x84, 0xa2, 0xdf, 0x31 } }, // NSNavProgressWindow + [0xd8] = { 0, (unsigned char[]){ 0x12, 0x31, 0x5f, 0x60, 0x61, 0x94, 0x7b, 0x74, 0xde, 0xd5, 0xf9, 0x34, 0x6a, 0x51, 0xff, 0x16, 0xef, 0x1e } }, // NSDrawerWindow + }}, + [0xff] = { 0, (unsigned char[]){ 0xd7, 0x9a, 0x4b, 0x94, 0x11, 0xb7, 0xbb, 0xb8, 0x25, 0x4d, 0x34, 0x60, 0x80, 0x46, 0xdc, 0x3a, 0x95, 0xed, 0xe3 } }, // NSLazyBrowserCell +}; diff --git a/Source/main.m b/Source/main.m old mode 100644 new mode 100755 index b9d033f..fc3d9f1 --- a/Source/main.m +++ b/Source/main.m @@ -63,24 +63,6 @@ - (void)observeValueForKeyPath: (NSString *)keyPath ofObject: (id)object change: @end -@interface OtherKVOTarget : NSObject {} @end -@implementation OtherKVOTarget - -- (void)setKey: (id)newValue -{ -} - -- (id)key -{ - return nil; -} - -- (void)observeValueForKeyPath: (NSString *)keyPath ofObject: (id)object change: (NSDictionary *)change context: (void *)context -{ -} - -@end - static void WithPool(void (^block)(void)) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; @@ -264,7 +246,6 @@ static void TestNSConstantTarget(void) NSString *str = [[NSMutableString alloc] initWithString: @"Not Constant String"]; MAZeroingWeakRef *ref = [[MAZeroingWeakRef alloc] initWithTarget: str]; [ref release]; - [str release]; }); } @@ -386,7 +367,7 @@ static void TestWeakProxy(void) } NSMutableString *str = [[NSMutableString alloc] init]; - NSMutableString *proxy = (id)[[MAZeroingWeakProxy alloc] initWithTarget: str]; + NSMutableString *proxy = (NSMutableString *)[[MAZeroingWeakProxy alloc] initWithTarget: str]; WithPool(^{ TEST_ASSERT([proxy isEqual: @""]); @@ -457,8 +438,6 @@ static void TestKVOTarget(void) MAZeroingWeakRef *ref = [[MAZeroingWeakRef alloc] initWithTarget: target]; [target setKey: @"value"]; [ref release]; - [target removeObserver:target forKeyPath:@"key"]; - [target release]; } static void TestKVOMultiLevelTarget(void) @@ -469,7 +448,6 @@ static void TestKVOMultiLevelTarget(void) MAZeroingWeakRef *ref = [[MAZeroingWeakRef alloc] initWithTarget: target]; [target removeObserver:target forKeyPath:@"key.whatever"]; [ref release]; - [target release]; } static void TestClassForCoder(void) @@ -478,7 +456,6 @@ static void TestClassForCoder(void) TEST_ASSERT([obj classForCoder] == [NSObject class]); [[[MAZeroingWeakRef alloc] initWithTarget: obj] autorelease]; TEST_ASSERT([obj classForCoder] == [NSObject class]); - [obj release]; } static void TestKVOReleaseNoCrash(void) @@ -515,88 +492,22 @@ static void TestKVOReleaseCrash(void) [ref release]; } -static void TestKVOObserveBeforeWeakRef(void) -{ - KVOTarget *target = [[KVOTarget alloc] init]; - - [target addObserver: target forKeyPath: @"key" options: 0 context: NULL]; - - MAZeroingWeakRef *ref = [[MAZeroingWeakRef alloc] initWithTarget: target]; - - [target setKey: @"value"]; - - WithPool(^{ - TEST_ASSERT([ref target] == target); - }); - - [target removeObserver:target forKeyPath:@"key"]; - - [target release]; - - WithPool(^{ - TEST_ASSERT([ref target] == nil); - }); - [ref release]; -} - -static void TestKVOObserveAfterWeakRef(void) +static void TestNativeZWRFallback(void) { - KVOTarget *target = [[KVOTarget alloc] init]; - - MAZeroingWeakRef *ref = [[MAZeroingWeakRef alloc] initWithTarget: target]; - - [target addObserver: target forKeyPath: @"key" options: 0 context: NULL]; - - [target setKey: @"value"]; - - WithPool(^{ - TEST_ASSERT([ref target] == target); - }); - - [target removeObserver:target forKeyPath:@"key"]; - - [target release]; - - TEST_ASSERT([ref target] == nil); - - [ref release]; + NSPort *port = [NSPort port]; + [MAZeroingWeakRef refWithTarget: port]; } -static void TestKVOObserveAfterAfterWeakRef(void) +static void TestKVORemovalCrash(void) { - OtherKVOTarget *faker = [[OtherKVOTarget alloc] init]; - - WithPool(^{ - [MAZeroingWeakRef refWithTarget:faker]; - }); - - [faker addObserver: faker forKeyPath: @"key" options: 0 context: NULL]; - - WithPool(^{ - [MAZeroingWeakRef refWithTarget:faker]; - }); - - [faker removeObserver:faker forKeyPath:@"key"]; - - OtherKVOTarget *target = [[OtherKVOTarget alloc] init]; - - - MAZeroingWeakRef *ref = [[MAZeroingWeakRef alloc] initWithTarget: target]; - - WithPool(^{ - TEST_ASSERT([ref target] == target); - }); - - - [target release]; - - BOOL isNil = [ref target] == nil; - - TEST_ASSERT(isNil); - - - [ref release]; - [faker release]; + NSObject *obj = [[NSObject alloc] init]; + NSObject *observer = [[NSObject alloc] init]; + [obj addObserver:observer forKeyPath:@"description" options:NSKeyValueObservingOptionNew context:nil]; + MAZeroingWeakRef *weakRef = [MAZeroingWeakRef refWithTarget:obj]; + [obj removeObserver:observer forKeyPath:@"description"]; + [obj release]; + NSLog(@"weakRef %@", weakRef.target); + [observer release]; } int main(int argc, const char * argv[]) @@ -620,9 +531,10 @@ int main(int argc, const char * argv[]) TEST(TestKVOTarget); TEST(TestKVOMultiLevelTarget); TEST(TestClassForCoder); - TEST(TestKVOObserveAfterWeakRef); - TEST(TestKVOObserveBeforeWeakRef); - TEST(TestKVOObserveAfterAfterWeakRef); + TEST(TestKVOReleaseNoCrash); + TEST(TestKVOReleaseCrash); + TEST(TestNativeZWRFallback); + TEST(TestKVORemovalCrash); NSString *message; if(gFailureCount) diff --git a/ZeroingWeakRef.xcodeproj/project.pbxproj b/ZeroingWeakRef.xcodeproj/project.pbxproj old mode 100644 new mode 100755 index 6a18b20..9e50276 --- a/ZeroingWeakRef.xcodeproj/project.pbxproj +++ b/ZeroingWeakRef.xcodeproj/project.pbxproj @@ -8,6 +8,13 @@ /* Begin PBXBuildFile section */ C208C96011EBB8F100A8E38D /* MANotificationCenterAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = C208C95F11EBB8F100A8E38D /* MANotificationCenterAdditions.m */; }; + C23912C3144A54F900AEFD01 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C23912C2144A54F900AEFD01 /* UIKit.framework */; }; + C23912C4144A54F900AEFD01 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C2D7540B11E2588600816068 /* Foundation.framework */; }; + C23912C6144A54F900AEFD01 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C23912C5144A54F900AEFD01 /* CoreGraphics.framework */; }; + C23912CE144A54F900AEFD01 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = C23912CD144A54F900AEFD01 /* main.m */; }; + C2414C0D144A5F2C0029A0D4 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C2D7540B11E2588600816068 /* Foundation.framework */; }; + C2414C18144A5F690029A0D4 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = C23912CD144A54F900AEFD01 /* main.m */; }; + C2414C1C144A5F8F0029A0D4 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C2414C1B144A5F8F0029A0D4 /* AppKit.framework */; }; C25675F111E25C6A00CAB48E /* MAZeroingWeakRef.m in Sources */ = {isa = PBXBuildFile; fileRef = C25675F011E25C6A00CAB48E /* MAZeroingWeakRef.m */; }; C26F610511F207270080EC96 /* MAZeroingWeakProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = C26F610411F207270080EC96 /* MAZeroingWeakProxy.m */; }; C2D7540C11E2588600816068 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C2D7540B11E2588600816068 /* Foundation.framework */; }; @@ -18,6 +25,15 @@ /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ + C2414C09144A5F2C0029A0D4 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; C2D7540511E2588600816068 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -32,6 +48,14 @@ /* Begin PBXFileReference section */ C208C95E11EBB8F100A8E38D /* MANotificationCenterAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MANotificationCenterAdditions.h; sourceTree = ""; }; C208C95F11EBB8F100A8E38D /* MANotificationCenterAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MANotificationCenterAdditions.m; sourceTree = ""; }; + C23912C0144A54F900AEFD01 /* NativeZWRCheckeriPhone.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = NativeZWRCheckeriPhone.app; sourceTree = BUILT_PRODUCTS_DIR; }; + C23912C2144A54F900AEFD01 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; }; + C23912C5144A54F900AEFD01 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = Library/Frameworks/CoreGraphics.framework; sourceTree = DEVELOPER_DIR; }; + C23912C9144A54F900AEFD01 /* NativeZWRCheckeriPhone-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "NativeZWRCheckeriPhone-Info.plist"; sourceTree = ""; }; + C23912CD144A54F900AEFD01 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + C2414C0B144A5F2C0029A0D4 /* NativeZWRCheckerMac */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = NativeZWRCheckerMac; sourceTree = BUILT_PRODUCTS_DIR; }; + C2414C19144A5F6F0029A0D4 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = SDKs/MacOSX10.7.sdk/System/Library/Frameworks/Cocoa.framework; sourceTree = DEVELOPER_DIR; }; + C2414C1B144A5F8F0029A0D4 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = SDKs/MacOSX10.7.sdk/System/Library/Frameworks/AppKit.framework; sourceTree = DEVELOPER_DIR; }; C25675EF11E25C6A00CAB48E /* MAZeroingWeakRef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MAZeroingWeakRef.h; sourceTree = ""; }; C25675F011E25C6A00CAB48E /* MAZeroingWeakRef.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MAZeroingWeakRef.m; sourceTree = ""; }; C26F610311F207270080EC96 /* MAZeroingWeakProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MAZeroingWeakProxy.h; sourceTree = ""; }; @@ -46,9 +70,29 @@ C2DF1F2A11ED2C4700EFC8AE /* MAWeakDictionary.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MAWeakDictionary.m; sourceTree = ""; }; C65F68141459990300D3A417 /* NSTimer+MAWeakTimer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSTimer+MAWeakTimer.h"; sourceTree = ""; }; C65F68151459990300D3A417 /* NSTimer+MAWeakTimer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSTimer+MAWeakTimer.m"; sourceTree = ""; }; + C2EB6F77144B37A400278198 /* MAZeroingWeakRefNativeZWRNotAllowedTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MAZeroingWeakRefNativeZWRNotAllowedTable.h; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + C23912BD144A54F900AEFD01 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + C23912C3144A54F900AEFD01 /* UIKit.framework in Frameworks */, + C23912C4144A54F900AEFD01 /* Foundation.framework in Frameworks */, + C23912C6144A54F900AEFD01 /* CoreGraphics.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + C2414C08144A5F2C0029A0D4 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + C2414C1C144A5F8F0029A0D4 /* AppKit.framework in Frameworks */, + C2414C0D144A5F2C0029A0D4 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; C2D7540411E2588600816068 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -60,10 +104,22 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + C23912C7144A54F900AEFD01 /* NativeZWRChecker */ = { + isa = PBXGroup; + children = ( + C23912C9144A54F900AEFD01 /* NativeZWRCheckeriPhone-Info.plist */, + C23912CD144A54F900AEFD01 /* main.m */, + ); + path = NativeZWRChecker; + sourceTree = ""; + }; C2D753FA11E2588500816068 = { isa = PBXGroup; children = ( + C2414C1B144A5F8F0029A0D4 /* AppKit.framework */, + C2414C19144A5F6F0029A0D4 /* Cocoa.framework */, C2D7540111E2588600816068 /* Source */, + C23912C7144A54F900AEFD01 /* NativeZWRChecker */, C2D7540811E2588600816068 /* Products */, C2D7540A11E2588600816068 /* Frameworks */, C2D7541111E2588600816068 /* Other Sources */, @@ -86,6 +142,7 @@ C2DF1F2A11ED2C4700EFC8AE /* MAWeakDictionary.m */, C65F68141459990300D3A417 /* NSTimer+MAWeakTimer.h */, C65F68151459990300D3A417 /* NSTimer+MAWeakTimer.m */, + C2EB6F77144B37A400278198 /* MAZeroingWeakRefNativeZWRNotAllowedTable.h */, ); path = Source; sourceTree = ""; @@ -94,6 +151,8 @@ isa = PBXGroup; children = ( C2D7540711E2588600816068 /* ZeroingWeakRef */, + C23912C0144A54F900AEFD01 /* NativeZWRCheckeriPhone.app */, + C2414C0B144A5F2C0029A0D4 /* NativeZWRCheckerMac */, ); name = Products; sourceTree = ""; @@ -102,6 +161,8 @@ isa = PBXGroup; children = ( C2D7540B11E2588600816068 /* Foundation.framework */, + C23912C2144A54F900AEFD01 /* UIKit.framework */, + C23912C5144A54F900AEFD01 /* CoreGraphics.framework */, ); name = Frameworks; sourceTree = ""; @@ -117,6 +178,40 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ + C23912BF144A54F900AEFD01 /* NativeZWRCheckeriPhone */ = { + isa = PBXNativeTarget; + buildConfigurationList = C23912D5144A54F900AEFD01 /* Build configuration list for PBXNativeTarget "NativeZWRCheckeriPhone" */; + buildPhases = ( + C23912BC144A54F900AEFD01 /* Sources */, + C23912BD144A54F900AEFD01 /* Frameworks */, + C23912BE144A54F900AEFD01 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = NativeZWRCheckeriPhone; + productName = NativeZWRCheckeriPhone; + productReference = C23912C0144A54F900AEFD01 /* NativeZWRCheckeriPhone.app */; + productType = "com.apple.product-type.application"; + }; + C2414C0A144A5F2C0029A0D4 /* NativeZWRCheckerMac */ = { + isa = PBXNativeTarget; + buildConfigurationList = C2414C15144A5F2C0029A0D4 /* Build configuration list for PBXNativeTarget "NativeZWRCheckerMac" */; + buildPhases = ( + C2414C07144A5F2C0029A0D4 /* Sources */, + C2414C08144A5F2C0029A0D4 /* Frameworks */, + C2414C09144A5F2C0029A0D4 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = NativeZWRCheckerMac; + productName = NativeZWRCheckerMac; + productReference = C2414C0B144A5F2C0029A0D4 /* NativeZWRCheckerMac */; + productType = "com.apple.product-type.tool"; + }; C2D7540611E2588600816068 /* ZeroingWeakRef */ = { isa = PBXNativeTarget; buildConfigurationList = C2D7541511E2588600816068 /* Build configuration list for PBXNativeTarget "ZeroingWeakRef" */; @@ -148,6 +243,7 @@ Japanese, French, German, + en, ); mainGroup = C2D753FA11E2588500816068; productRefGroup = C2D7540811E2588600816068 /* Products */; @@ -155,11 +251,39 @@ projectRoot = ""; targets = ( C2D7540611E2588600816068 /* ZeroingWeakRef */, + C23912BF144A54F900AEFD01 /* NativeZWRCheckeriPhone */, + C2414C0A144A5F2C0029A0D4 /* NativeZWRCheckerMac */, ); }; /* End PBXProject section */ +/* Begin PBXResourcesBuildPhase section */ + C23912BE144A54F900AEFD01 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ + C23912BC144A54F900AEFD01 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + C23912CE144A54F900AEFD01 /* main.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + C2414C07144A5F2C0029A0D4 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + C2414C18144A5F690029A0D4 /* main.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; C2D7540311E2588600816068 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -177,22 +301,105 @@ /* End PBXSourcesBuildPhase section */ /* Begin XCBuildConfiguration section */ + C23912D3144A54F900AEFD01 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "\"$(DEVELOPER_FRAMEWORKS_DIR)\"", + ); + GCC_DYNAMIC_NO_PIC = NO; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; + INFOPLIST_FILE = "NativeZWRCheckeriPhone/NativeZWRCheckeriPhone-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 5.0; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + WRAPPER_EXTENSION = app; + }; + name = Debug; + }; + C23912D4144A54F900AEFD01 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "\"$(DEVELOPER_FRAMEWORKS_DIR)\"", + ); + GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; + INFOPLIST_FILE = "NativeZWRCheckeriPhone/NativeZWRCheckeriPhone-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 5.0; + OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + WRAPPER_EXTENSION = app; + }; + name = Release; + }; + C2414C16144A5F2C0029A0D4 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD_64_BIT)"; + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; + MACOSX_DEPLOYMENT_TARGET = 10.7; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Debug; + }; + C2414C17144A5F2C0029A0D4 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD_64_BIT)"; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; + MACOSX_DEPLOYMENT_TARGET = 10.7; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Release; + }; C2D7541311E2588600816068 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "USE_ARC_FUNCTIONS_IF_AVAILABLE=0", - DEBUG, - ); + GCC_PREPROCESSOR_DEFINITIONS = DEBUG; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; ONLY_ACTIVE_ARCH = YES; PREBINDING = NO; - SDKROOT = macosx10.6; }; name = Debug; }; @@ -205,7 +412,6 @@ GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; PREBINDING = NO; - SDKROOT = macosx10.6; }; name = Release; }; @@ -242,6 +448,24 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + C23912D5144A54F900AEFD01 /* Build configuration list for PBXNativeTarget "NativeZWRCheckeriPhone" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C23912D3144A54F900AEFD01 /* Debug */, + C23912D4144A54F900AEFD01 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + C2414C15144A5F2C0029A0D4 /* Build configuration list for PBXNativeTarget "NativeZWRCheckerMac" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C2414C16144A5F2C0029A0D4 /* Debug */, + C2414C17144A5F2C0029A0D4 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; C2D753FF11E2588500816068 /* Build configuration list for PBXProject "ZeroingWeakRef" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/ZeroingWeakRef.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ZeroingWeakRef.xcodeproj/project.xcworkspace/contents.xcworkspacedata old mode 100644 new mode 100755 diff --git a/ZeroingWeakRef.xcodeproj/project.xcworkspace/xcuserdata/mikeash.xcuserdatad/WorkspaceState.xcuserstate b/ZeroingWeakRef.xcodeproj/project.xcworkspace/xcuserdata/mikeash.xcuserdatad/WorkspaceState.xcuserstate old mode 100644 new mode 100755 From c5b7ccf4e8fa3f2e8e38ac058f3fcbbcfb699307 Mon Sep 17 00:00:00 2001 From: Remy Demarest Date: Tue, 15 May 2012 23:52:58 -0400 Subject: [PATCH 16/17] Corrected macros. --- Source/MAZeroingWeakRef.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/MAZeroingWeakRef.h b/Source/MAZeroingWeakRef.h index 38b5687..88f2b19 100755 --- a/Source/MAZeroingWeakRef.h +++ b/Source/MAZeroingWeakRef.h @@ -56,8 +56,8 @@ #if __has_feature(objc_arc_weak) -#define MAWeakDeclare(var) __weak __typeof__((var)) MAWeakVar(var) = var -#define MAWeakImport(var) __typeof__((MAWeakVar(var))) var = MAWeakVar(var) +#define MAWeakDeclare(var) __weak id MAWeakVar(var) = var +#define MAWeakImport(var) __typeof__(var) var = MAWeakVar(var) #define MAWeakImportReturn(var) MAWeakImport(var); do { if(var == nil) return; } while(NO) #else From b5da51cdd1b50154e38e24e0a6f566d9d10d1b32 Mon Sep 17 00:00:00 2001 From: Remy Demarest Date: Wed, 31 Jul 2013 21:20:31 -0700 Subject: [PATCH 17/17] Remove the shadow diagnostic around the variable redefinition. --- Source/MAZeroingWeakRef.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/MAZeroingWeakRef.h b/Source/MAZeroingWeakRef.h index 88f2b19..c7238e0 100755 --- a/Source/MAZeroingWeakRef.h +++ b/Source/MAZeroingWeakRef.h @@ -57,13 +57,13 @@ #if __has_feature(objc_arc_weak) #define MAWeakDeclare(var) __weak id MAWeakVar(var) = var -#define MAWeakImport(var) __typeof__(var) var = MAWeakVar(var) +#define MAWeakImport(var) _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wshadow\"") __typeof__(var) var = MAWeakVar(var) _Pragma("clang diagnostic pop") #define MAWeakImportReturn(var) MAWeakImport(var); do { if(var == nil) return; } while(NO) #else #define MAWeakDeclare(var) __typeof__((var)) MAWeakVar(var) = (id)[MAZeroingWeakRef refWithTarget:var] -#define MAWeakImport(var) __typeof__((MAWeakVar(var))) var = [(MAZeroingWeakRef *)MAWeakVar(var) target] +#define MAWeakImport(var) _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wshadow\"") __typeof__((MAWeakVar(var))) var = [(MAZeroingWeakRef *)MAWeakVar(var) target] _Pragma("clang diagnostic pop") #define MAWeakImportReturn(var) MAWeakImport(var); do { if(var == nil) return; } while(NO) #endif