Added MAZeroingWeakRef
authorEvan Schoenberg
Sun, 21 Aug 2011 16:17:51 -0500
changeset 3614 062a27e5858b
parent 3613 4d7607e78f81
child 3615 dd4b532eb0d5
Added MAZeroingWeakRef
(transplanted from 13d1f4765a893ca51ac912172b365f4ddae937d2)
Frameworks/MAZeroingWeakRef/LICENSE
Frameworks/MAZeroingWeakRef/README.markdown
Frameworks/MAZeroingWeakRef/Source/MANotificationCenterAdditions.h
Frameworks/MAZeroingWeakRef/Source/MANotificationCenterAdditions.m
Frameworks/MAZeroingWeakRef/Source/MAWeakArray.h
Frameworks/MAZeroingWeakRef/Source/MAWeakArray.m
Frameworks/MAZeroingWeakRef/Source/MAWeakDictionary.h
Frameworks/MAZeroingWeakRef/Source/MAWeakDictionary.m
Frameworks/MAZeroingWeakRef/Source/MAZeroingWeakProxy.h
Frameworks/MAZeroingWeakRef/Source/MAZeroingWeakProxy.m
Frameworks/MAZeroingWeakRef/Source/MAZeroingWeakRef.h
Frameworks/MAZeroingWeakRef/Source/MAZeroingWeakRef.m
Frameworks/MAZeroingWeakRef/Source/main.m
Frameworks/MAZeroingWeakRef/ZeroingWeakRef.xcodeproj/project.pbxproj
Frameworks/MAZeroingWeakRef/ZeroingWeakRef_Prefix.pch
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Frameworks/MAZeroingWeakRef/LICENSE	Sun Aug 21 16:17:51 2011 -0500
@@ -0,0 +1,15 @@
+MAZeroingWeakRef and all code associated with it is distributed under a BSD license, as listed below.
+
+
+Copyright (c) 2010, Michael Ash
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+Neither the name of Michael Ash nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Frameworks/MAZeroingWeakRef/README.markdown	Sun Aug 21 16:17:51 2011 -0500
@@ -0,0 +1,45 @@
+MAZeroingWeakRef - by Mike Ash - mike@mikeash.com
+
+Introduction
+------------
+
+MAZeroingWeakRef is a library for using zeroing weak references in retain/release Cocoa and Cocoa Touch code. These are references which do not keep an object alive, and which automatically become nil once the object is destroyed.
+
+MAZeroingWeakRef does not work under Cocoa garbage collection. The built-in __weak specifier exists for that, although it is used somewhat differently.
+
+The API is simple and mostly self-explanatory from the header file. Note that cleanup blocks are only needed for advanced uses when you need to take more action than simply zeroing the reference when the target object is destroyed. Be sure to heed the warning in the header about not doing too much work in the cleanup block.
+
+In order to allow weak references to CoreFoundation bridged objects, a fair amount of crazy hacking of private APIs had to be done. For people who don't like that sort of thing, or who are worried about rejection when building for iOS, this crazy hacking can be reduced or disabled altogether. Look at the COREFOUNDATION_HACK_LEVEL macro in MAZeroingWeakRef.m, and the comment above it which explains what the different levels do.
+
+A similar KVO_HACK_LEVEL macro is also available.
+
+App Store
+---------
+
+For iOS work, or Mac App Store work, you will probably want to set both COREFOUNDATION_HACK_LEVEL and KVO_HACK_LEVEL to `0`. In this mode, MAZeroingWeakRef uses no private APIs.
+
+Source Code
+-----------
+
+The MAZeroingWeakRef code is available from GitHub:
+
+    http://github.com/mikeash/MAZeroingWeakRef
+
+MAZeroingWeakRef is made available under a BSD license.
+
+More Information
+----------------
+
+For more information about it, this blog post gives a basic introduction to the API:
+
+    http://mikeash.com/pyblog/introducing-mazeroingweakref.html
+
+This describes how it works in most cases:
+
+http://mikeash.com/pyblog/friday-qa-2010-07-16-zeroing-weak-references-in-objective-c.html
+
+And this describes some of the more hairy parts:
+
+    http://mikeash.com/pyblog/friday-qa-2010-07-30-zeroing-weak-references-to-corefoundation-objects.html
+
+Enjoy!
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Frameworks/MAZeroingWeakRef/Source/MANotificationCenterAdditions.h	Sun Aug 21 16:17:51 2011 -0500
@@ -0,0 +1,15 @@
+//
+//  MANotificationCenterAdditions.h
+//  ZeroingWeakRef
+//
+//  Created by Michael Ash on 7/12/10.
+//
+
+#import <Foundation/Foundation.h>
+
+
+@interface NSNotificationCenter (MAZeroingWeakRefAdditions)
+#if NS_BLOCKS_AVAILABLE
+- (void)addWeakObserver: (id)observer selector: (SEL)selector name: (NSString *)name object: (NSString *)object;
+#endif
+@end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Frameworks/MAZeroingWeakRef/Source/MANotificationCenterAdditions.m	Sun Aug 21 16:17:51 2011 -0500
@@ -0,0 +1,38 @@
+//
+//  MANotificationCenterAdditions.m
+//  ZeroingWeakRef
+//
+//  Created by Michael Ash on 7/12/10.
+//
+
+#import "MANotificationCenterAdditions.h"
+
+#import "MAZeroingWeakRef.h"
+
+
+@implementation NSNotificationCenter (MAZeroingWeakRefAdditions)
+
+#if NS_BLOCKS_AVAILABLE
+
+- (void)addWeakObserver: (id)observer selector: (SEL)selector name: (NSString *)name object: (NSString *)object
+{
+    MAZeroingWeakRef *ref = [[MAZeroingWeakRef alloc] initWithTarget: observer];
+    
+    id noteObj = [self addObserverForName: name object:object queue: nil usingBlock: ^(NSNotification *note) {
+        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+        
+        id anObserver = [ref target];
+        [anObserver performSelector: selector withObject: note];
+        
+        [pool release];
+    }];
+    
+    [ref setCleanupBlock: ^(id target) {
+        [self removeObserver: noteObj];
+        [ref autorelease];
+    }];
+}
+
+#endif
+
+@end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Frameworks/MAZeroingWeakRef/Source/MAWeakArray.h	Sun Aug 21 16:17:51 2011 -0500
@@ -0,0 +1,16 @@
+//
+//  MAWeakArray.h
+//  ZeroingWeakRef
+//
+//  Created by Mike Ash on 7/13/10.
+//
+
+#import <Foundation/Foundation.h>
+
+
+@interface MAWeakArray : NSMutableArray
+{
+    NSMutableArray *_weakRefs;
+}
+
+@end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Frameworks/MAZeroingWeakRef/Source/MAWeakArray.m	Sun Aug 21 16:17:51 2011 -0500
@@ -0,0 +1,67 @@
+//
+//  MAWeakArray.m
+//  ZeroingWeakRef
+//
+//  Created by Mike Ash on 7/13/10.
+//
+
+#import "MAWeakArray.h"
+
+#import "MAZeroingWeakRef.h"
+
+
+@implementation MAWeakArray
+
+- (id)init
+{
+    if((self = [super init]))
+    {
+        _weakRefs = [[NSMutableArray alloc] init];
+    }
+    return self;
+}
+
+- (void)dealloc
+{
+    [_weakRefs release];
+    [super dealloc];
+}
+
+- (NSUInteger)count
+{
+    return [_weakRefs count];
+}
+
+- (id)objectAtIndex: (NSUInteger)index
+{
+    return [[_weakRefs objectAtIndex: index] target];
+}
+
+- (void)addObject: (id)anObject
+{
+    [_weakRefs addObject: [MAZeroingWeakRef refWithTarget: anObject]];
+}
+
+- (void)insertObject: (id)anObject atIndex: (NSUInteger)index
+{
+    [_weakRefs insertObject: [MAZeroingWeakRef refWithTarget: anObject]
+                    atIndex: index];
+}
+
+- (void)removeLastObject
+{
+    [_weakRefs removeLastObject];
+}
+
+- (void)removeObjectAtIndex: (NSUInteger)index
+{
+    [_weakRefs removeObjectAtIndex: index];
+}
+
+- (void)replaceObjectAtIndex: (NSUInteger)index withObject: (id)anObject
+{
+    [_weakRefs replaceObjectAtIndex: index
+                         withObject: [MAZeroingWeakRef refWithTarget: anObject]];
+}
+
+@end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Frameworks/MAZeroingWeakRef/Source/MAWeakDictionary.h	Sun Aug 21 16:17:51 2011 -0500
@@ -0,0 +1,16 @@
+//
+//  MAWeakDictionary.h
+//  ZeroingWeakRef
+//
+//  Created by Mike Ash on 7/13/10.
+//
+
+#import <Foundation/Foundation.h>
+
+
+@interface MAWeakDictionary : NSMutableDictionary
+{
+    NSMutableDictionary *_dict;
+}
+
+@end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Frameworks/MAZeroingWeakRef/Source/MAWeakDictionary.m	Sun Aug 21 16:17:51 2011 -0500
@@ -0,0 +1,66 @@
+//
+//  MAWeakDictionary.m
+//  ZeroingWeakRef
+//
+//  Created by Mike Ash on 7/13/10.
+//
+
+#import "MAWeakDictionary.h"
+
+#import "MAZeroingWeakRef.h"
+
+
+@implementation MAWeakDictionary
+
+- (id)init
+{
+    if((self = [super init]))
+    {
+        _dict = [[NSMutableDictionary alloc] init];
+    }
+    return self;
+}
+
+- (void)dealloc
+{
+    [_dict release];
+    [super dealloc];
+}
+
+- (NSUInteger)count
+{
+    return [_dict count];
+}
+
+- (id)objectForKey: (id)aKey
+{
+    MAZeroingWeakRef *ref = [_dict objectForKey: aKey];
+    id obj = [ref target];
+    
+    // clean out keys whose objects have gone away
+    if(ref && !obj)
+        [_dict removeObjectForKey: aKey];
+    
+    return obj;
+}
+
+- (NSEnumerator *)keyEnumerator
+{
+    // enumerate over a copy because -objectForKey: mutates
+    // which could cause an exception in code that should
+    // appear to be correct
+    return [[_dict allKeys] objectEnumerator];
+}
+
+- (void)removeObjectForKey: (id)aKey
+{
+    [_dict removeObjectForKey: aKey];
+}
+
+- (void)setObject: (id)anObject forKey: (id)aKey
+{
+    [_dict setObject: [MAZeroingWeakRef refWithTarget: anObject]
+                                               forKey: aKey];
+}
+
+@end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Frameworks/MAZeroingWeakRef/Source/MAZeroingWeakProxy.h	Sun Aug 21 16:17:51 2011 -0500
@@ -0,0 +1,31 @@
+//
+//  MAZeroingWeakProxy.h
+//  ZeroingWeakRef
+//
+//  Created by Michael Ash on 7/17/10.
+//  Copyright 2010 Michael Ash. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+
+@class MAZeroingWeakRef;
+
+@interface MAZeroingWeakProxy : NSProxy
+{
+    MAZeroingWeakRef *_weakRef;
+    Class _targetClass;
+}
+
++ (id)proxyWithTarget: (id)target;
+
+- (id)initWithTarget: (id)target;
+
+- (id)zeroingProxyTarget;
+
+#if NS_BLOCKS_AVAILABLE
+// same caveats/restrictions as MAZeroingWeakRef cleanup block
+- (void)setCleanupBlock: (void (^)(id target))block;
+#endif
+
+@end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Frameworks/MAZeroingWeakRef/Source/MAZeroingWeakProxy.m	Sun Aug 21 16:17:51 2011 -0500
@@ -0,0 +1,99 @@
+//
+//  MAZeroingWeakProxy.m
+//  ZeroingWeakRef
+//
+//  Created by Michael Ash on 7/17/10.
+//  Copyright 2010 Michael Ash. All rights reserved.
+//
+
+#import "MAZeroingWeakProxy.h"
+
+#import "MAZeroingWeakRef.h"
+
+@implementation MAZeroingWeakProxy
+
++ (id)proxyWithTarget: (id)target
+{
+    return [[[self alloc] initWithTarget: target] autorelease];
+}
+
+- (id)initWithTarget: (id)target
+{
+    // stash the class of the target so we can get method signatures after it goes away
+    _targetClass = [target class];
+    _weakRef = [[MAZeroingWeakRef alloc] initWithTarget: target];
+    return self;
+}
+
+- (void)dealloc
+{
+    [_weakRef release];
+    [super dealloc];
+}
+
+- (id)zeroingProxyTarget
+{
+    return [_weakRef target];
+}
+
+#if NS_BLOCKS_AVAILABLE
+- (void)setCleanupBlock: (void (^)(id target))block
+{
+    [_weakRef setCleanupBlock: block];
+}
+#endif
+
+- (id)forwardingTargetForSelector: (SEL)sel
+{
+    return [_weakRef target];
+}
+
+- (NSMethodSignature *)methodSignatureForSelector: (SEL)sel
+{
+    return [_targetClass instanceMethodSignatureForSelector: sel];
+}
+
+- (void)forwardInvocation: (NSInvocation *)inv
+{
+    NSMethodSignature *sig = [inv methodSignature];
+    NSUInteger returnLength = [sig methodReturnLength];
+    
+    if(returnLength)
+    {
+        char buf[returnLength];
+        bzero(buf, sizeof(buf));
+        [inv setReturnValue: buf];
+    }
+}
+
+- (BOOL)respondsToSelector: (SEL)sel
+{
+    id target = [_weakRef target];
+    if(target)
+        return [target respondsToSelector: sel];
+    else
+        return [_targetClass instancesRespondToSelector: sel];
+}
+
+- (BOOL)conformsToProtocol: (Protocol *)protocol
+{
+    id target = [_weakRef target];
+    if(target)
+        return [target conformsToProtocol: protocol];
+    else
+        return [_targetClass conformsToProtocol: protocol];
+}
+
+// NSProxy implements these for some incomprehensibly stupid reason
+
+- (NSUInteger)hash
+{
+    return [[_weakRef target] hash];
+}
+
+- (BOOL)isEqual: (id)obj
+{
+    return [[_weakRef target] isEqual: obj];
+}
+
+@end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Frameworks/MAZeroingWeakRef/Source/MAZeroingWeakRef.h	Sun Aug 21 16:17:51 2011 -0500
@@ -0,0 +1,48 @@
+//
+//  MAZeroingWeakRef.h
+//  ZeroingWeakRef
+//
+//  Created by Michael Ash on 7/5/10.
+//
+
+#import <Foundation/Foundation.h>
+
+
+@interface MAZeroingWeakRef : NSObject
+{
+    id _target;
+#if NS_BLOCKS_AVAILABLE
+    void (^_cleanupBlock)(id target);
+#endif
+}
+
++ (BOOL)canRefCoreFoundationObjects;
+
++ (id)refWithTarget: (id)target;
+
+- (id)initWithTarget: (id)target;
+
+#if NS_BLOCKS_AVAILABLE
+// ON 10.7:
+// cleanup block runs while the target's memory is still
+// allocated but after all dealloc methods have run
+// (it runs at associated object cleanup time)
+// you can use the target's pointer value but don't
+// manipulate its contents!
+
+// ON 10.6 AND BELOW:
+// cleanup block runs while the global ZWR lock is held
+// so make it short and sweet!
+// use GCD or something to schedule execution later
+// if you need to do something that may take a while
+//
+// it is unsafe to call -target on the weak ref from
+// inside the cleanup block, which is why the target
+// is passed in as a parameter
+// note that you must not resurrect the target at this point!
+- (void)setCleanupBlock: (void (^)(id target))block;
+#endif
+
+- (id)target;
+
+@end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Frameworks/MAZeroingWeakRef/Source/MAZeroingWeakRef.m	Sun Aug 21 16:17:51 2011 -0500
@@ -0,0 +1,695 @@
+//
+//  MAZeroingWeakRef.m
+//  ZeroingWeakRef
+//
+//  Created by Michael Ash on 7/5/10.
+//
+
+#import "MAZeroingWeakRef.h"
+
+#import <dlfcn.h>
+#import <libkern/OSAtomic.h>
+#import <objc/runtime.h>
+#import <mach/mach.h>
+#import <mach/port.h>
+#import <pthread.h>
+
+
+/*
+ The COREFOUNDATION_HACK_LEVEL macro allows you to control how much horrible CF
+ hackery is enabled. The following levels are defined:
+ 
+ 3 - Completely insane hackery allows weak references to CF objects, deallocates
+ them asynchronously in another thread to eliminate resurrection-related race
+ condition and crash.
+ 
+ 2 - Full hackery allows weak references to CF objects by doing horrible
+ things with the private CF class table. Extremely small risk of resurrection-
+ related race condition leading to a crash.
+ 
+ 1 - Mild hackery allows foolproof identification of CF objects and will assert
+ if trying to make a ZWR to one.
+ 
+ 0 - No hackery, checks for an "NSCF" prefix in the class name to identify CF
+ objects and will assert if trying to make a ZWR to one
+ */
+#ifndef COREFOUNDATION_HACK_LEVEL
+#define COREFOUNDATION_HACK_LEVEL 0
+#endif
+
+/*
+ The KVO_HACK_LEVEL macro allows similar control over the amount of KVO hackery.
+ 
+ 1 - Use the private _isKVOA method to check for a KVO dynamic subclass.
+ 
+ 0 - No hackery, uses the KVO overridden -class to check.
+ */
+#ifndef KVO_HACK_LEVEL
+#define KVO_HACK_LEVEL 1
+#endif
+
+#if KVO_HACK_LEVEL >= 1
+@interface NSObject (KVOPrivateMethod)
+
+- (BOOL)_isKVOA;
+
+@end
+#endif
+
+
+@interface MAZeroingWeakRef ()
+
+- (void)_zeroTarget;
+- (void)_executeCleanupBlockWithTarget: (id)target;
+
+@end
+
+
+static id (*objc_loadWeak_fptr)(id *location);
+static id (*objc_storeWeak_fptr)(id *location, id obj);
+
+@interface _MAZeroingWeakRefCleanupHelper : NSObject
+{
+    MAZeroingWeakRef *_ref;
+    id _target;
+}
+
+- (id)initWithRef: (MAZeroingWeakRef *)ref target: (id)target;
+
+@end
+
+@implementation _MAZeroingWeakRefCleanupHelper
+
+- (id)initWithRef: (MAZeroingWeakRef *)ref target: (id)target
+{
+    if((self = [self init]))
+    {
+        objc_storeWeak_fptr(&_ref, ref);
+        _target = target;
+    }
+    return self;
+}
+
+- (void)dealloc
+{
+    MAZeroingWeakRef *ref = objc_loadWeak_fptr(&_ref);
+    [ref _executeCleanupBlockWithTarget: _target];
+    objc_storeWeak_fptr(&_ref, nil);
+    
+    [super dealloc];
+}
+
+@end
+
+
+@implementation MAZeroingWeakRef
+
+#if COREFOUNDATION_HACK_LEVEL >= 2
+
+typedef struct __CFRuntimeClass {	// Version 0 struct
+    CFIndex version;
+    const char *className;
+    void (*init)(CFTypeRef cf);
+    CFTypeRef (*copy)(CFAllocatorRef allocator, CFTypeRef cf);
+    void (*finalize)(CFTypeRef cf);
+    Boolean (*equal)(CFTypeRef cf1, CFTypeRef cf2);
+    CFHashCode (*hash)(CFTypeRef cf);
+    CFStringRef (*copyFormattingDesc)(CFTypeRef cf, CFDictionaryRef formatOptions);	// str with retain
+    CFStringRef (*copyDebugDesc)(CFTypeRef cf);	// str with retain
+    void (*reclaim)(CFTypeRef cf);
+} CFRuntimeClass;
+
+extern CFRuntimeClass * _CFRuntimeGetClassWithTypeID(CFTypeID typeID);
+
+typedef void (*CFFinalizeFptr)(CFTypeRef);
+static CFFinalizeFptr *gCFOriginalFinalizes;
+static size_t gCFOriginalFinalizesSize;
+
+#endif
+
+#if COREFOUNDATION_HACK_LEVEL >= 1
+
+extern Class *__CFRuntimeObjCClassTable;
+
+#endif
+
+static pthread_mutex_t gMutex;
+
+static CFMutableDictionaryRef gObjectWeakRefsMap; // maps (non-retained) objects to CFMutableSetRefs containing weak refs
+
+static NSMutableSet *gCustomSubclasses;
+static NSMutableDictionary *gCustomSubclassMap; // maps regular classes to their custom subclasses
+
+#if COREFOUNDATION_HACK_LEVEL >= 3
+static CFMutableSetRef gCFWeakTargets;
+static NSOperationQueue *gCFDelayedDestructionQueue;
+#endif
+
++ (void)initialize
+{
+    if(self == [MAZeroingWeakRef class])
+    {
+        pthread_mutexattr_t mutexattr;
+        pthread_mutexattr_init(&mutexattr);
+        pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_RECURSIVE);
+        pthread_mutex_init(&gMutex, &mutexattr);
+        pthread_mutexattr_destroy(&mutexattr);
+        
+        gObjectWeakRefsMap = CFDictionaryCreateMutable(NULL, 0, NULL, &kCFTypeDictionaryValueCallBacks);
+        gCustomSubclasses = [[NSMutableSet alloc] init];
+        gCustomSubclassMap = [[NSMutableDictionary alloc] init];
+        
+        // see if the 10.7 ZWR runtime functions are available
+        // nothing special about objc_allocateClassPair, it just
+        // seems like a reasonable and safe choice for finding
+        // the runtime functions
+        Dl_info info;
+        int success = dladdr(objc_allocateClassPair, &info);
+        if(success)
+        {
+            // note: we leak the handle because it's inconsequential
+            // and technically, the fptrs would be invalid after a dlclose
+            void *handle = dlopen(info.dli_fname, RTLD_LAZY | RTLD_GLOBAL);
+            if(handle)
+            {
+                objc_loadWeak_fptr = dlsym(handle, "objc_loadWeak");
+                objc_storeWeak_fptr = dlsym(handle, "objc_storeWeak");
+                
+                // if either one failed, make sure both are zeroed out
+                // this is probably unnecessary, but good paranoia
+                if(!objc_loadWeak_fptr || !objc_storeWeak_fptr)
+                {
+                    objc_loadWeak_fptr = NULL;
+                    objc_storeWeak_fptr = NULL;
+                }
+            }
+        }
+        
+#if COREFOUNDATION_HACK_LEVEL >= 3
+        gCFWeakTargets = CFSetCreateMutable(NULL, 0, NULL);
+        gCFDelayedDestructionQueue = [[NSOperationQueue alloc] init];
+#endif
+    }
+}
+
+#define USE_BLOCKS_BASED_LOCKING 1
+#if USE_BLOCKS_BASED_LOCKING
+#define BLOCK_QUALIFIER __block
+static void WhileLocked(void (^block)(void))
+{
+    pthread_mutex_lock(&gMutex);
+    block();
+    pthread_mutex_unlock(&gMutex);
+}
+#define WhileLocked(block) WhileLocked(^block)
+#else
+#define BLOCK_QUALIFIER
+#define WhileLocked(block) do { \
+        pthread_mutex_lock(&gMutex); \
+        block \
+        pthread_mutex_unlock(&gMutex); \
+    } while(0)
+#endif
+
+static void AddWeakRefToObject(id obj, MAZeroingWeakRef *ref)
+{
+    CFMutableSetRef set = (void *)CFDictionaryGetValue(gObjectWeakRefsMap, obj);
+    if(!set)
+    {
+        set = CFSetCreateMutable(NULL, 0, NULL);
+        CFDictionarySetValue(gObjectWeakRefsMap, obj, set);
+        CFRelease(set);
+    }
+    CFSetAddValue(set, ref);
+}
+
+static void RemoveWeakRefFromObject(id obj, MAZeroingWeakRef *ref)
+{
+    CFMutableSetRef set = (void *)CFDictionaryGetValue(gObjectWeakRefsMap, obj);
+    CFSetRemoveValue(set, ref);
+}
+
+static void ClearWeakRefsForObject(id obj)
+{
+    CFMutableSetRef set = (void *)CFDictionaryGetValue(gObjectWeakRefsMap, obj);
+    if(set)
+    {
+        NSSet *setCopy = [[NSSet alloc] initWithSet: (NSSet *)set];
+        [setCopy makeObjectsPerformSelector: @selector(_zeroTarget)];
+        [setCopy makeObjectsPerformSelector: @selector(_executeCleanupBlockWithTarget:) withObject: obj];
+        [setCopy release];
+        CFDictionaryRemoveValue(gObjectWeakRefsMap, obj);
+    }
+}
+
+static Class GetCustomSubclass(id obj)
+{
+    Class class = object_getClass(obj);
+    while(class && ![gCustomSubclasses containsObject: class])
+        class = class_getSuperclass(class);
+    return class;
+}
+
+static Class GetRealSuperclass(id obj)
+{
+    Class class = GetCustomSubclass(obj);
+    NSCAssert1(class, @"Coudn't find ZeroingWeakRef subclass in hierarchy starting from %@, should never happen", object_getClass(obj));
+    return class_getSuperclass(class);
+}
+
+static void CustomSubclassRelease(id self, SEL _cmd)
+{
+    Class superclass = GetRealSuperclass(self);
+    IMP superRelease = class_getMethodImplementation(superclass, @selector(release));
+    WhileLocked({
+        ((void (*)(id, SEL))superRelease)(self, _cmd);
+    });
+}
+
+static void CustomSubclassDealloc(id self, SEL _cmd)
+{
+    ClearWeakRefsForObject(self);
+    Class superclass = GetRealSuperclass(self);
+    IMP superDealloc = class_getMethodImplementation(superclass, @selector(dealloc));
+    ((void (*)(id, SEL))superDealloc)(self, _cmd);
+}
+
+static Class CustomSubclassClassForCoder(id self, SEL _cmd)
+{
+    Class class = GetCustomSubclass(self);
+    Class superclass = class_getSuperclass(class);
+    IMP superClassForCoder = class_getMethodImplementation(superclass, @selector(classForCoder));
+    Class classForCoder = ((id (*)(id, SEL))superClassForCoder)(self, _cmd);
+    if(classForCoder == class)
+        classForCoder = superclass;
+    return classForCoder;
+}
+
+#if COREFOUNDATION_HACK_LEVEL >= 3
+
+static void CallCFReleaseLater(CFTypeRef cf)
+{
+    mach_port_t thread = mach_thread_self(); // must "release" this
+    
+    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+    SEL sel = @selector(releaseLater:fromThread:);
+    NSInvocation *inv = [NSInvocation invocationWithMethodSignature: [MAZeroingWeakRef methodSignatureForSelector: sel]];
+    [inv setTarget: [MAZeroingWeakRef class]];
+    [inv setSelector: sel];
+    [inv setArgument: &cf atIndex: 2];
+    [inv setArgument: &thread atIndex: 3];
+    
+    NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithInvocation: inv];
+    [gCFDelayedDestructionQueue addOperation: op];
+    [op release];
+    [pool release];
+}
+
+static const void *kPCThreadExited = &kPCThreadExited;
+static const void *kPCError = NULL;
+
+static const void *GetPC(mach_port_t thread)
+{
+#if defined(__x86_64__)
+    x86_thread_state64_t state;
+    unsigned int count = x86_THREAD_STATE64_COUNT;
+    thread_state_flavor_t flavor = x86_THREAD_STATE64;
+#define PC_REGISTER __rip
+#elif defined(__i386__)
+    i386_thread_state_t state;
+    unsigned int count = i386_THREAD_STATE_COUNT;
+    thread_state_flavor_t flavor = i386_THREAD_STATE;
+#define PC_REGISTER __eip
+#elif defined(__arm__)
+    arm_thread_state_t state;
+    unsigned int count = ARM_THREAD_STATE_COUNT;
+    thread_state_flavor_t flavor = ARM_THREAD_STATE;
+#define PC_REGISTER __pc
+#elif defined(__ppc__)
+    ppc_thread_state_t state;
+    unsigned int count = PPC_THREAD_STATE_COUNT;
+    thread_state_flavor_t flavor = PPC_THREAD_STATE;
+#define PC_REGISTER __srr0
+#elif defined(__ppc64__)
+    ppc_thread_state64_t state;
+    unsigned int count = PPC_THREAD_STATE64_COUNT;
+    thread_state_flavor_t flavor = PPC_THREAD_STATE64;
+#define PC_REGISTER __srr0
+#else
+#error don't know how to get PC for the current architecture!
+#endif
+    
+    kern_return_t ret = thread_get_state(thread, flavor, (thread_state_t)&state, &count);
+    if(ret == KERN_SUCCESS)
+        return (void *)state.PC_REGISTER;
+    else if(ret == KERN_INVALID_ARGUMENT)
+        return kPCThreadExited;
+    else
+        return kPCError;
+}
+
+static void CustomCFFinalize(CFTypeRef cf)
+{
+    WhileLocked({
+        if(CFSetContainsValue(gCFWeakTargets, cf))
+        {
+            if(CFGetRetainCount(cf) == 1)
+            {
+                ClearWeakRefsForObject((id)cf);
+                CFSetRemoveValue(gCFWeakTargets, cf);
+                CFRetain(cf);
+                CallCFReleaseLater(cf);
+            }
+        }
+        else
+        {
+            void (*fptr)(CFTypeRef) = gCFOriginalFinalizes[CFGetTypeID(cf)];
+            if(fptr)
+                fptr(cf);
+        }
+    });
+}
+
+#elif COREFOUNDATION_HACK_LEVEL >= 2
+
+static void CustomCFFinalize(CFTypeRef cf)
+{
+    WhileLocked({
+        if(CFGetRetainCount(cf) == 1)
+        {
+            ClearWeakRefsForObject((id)cf);
+            void (*fptr)(CFTypeRef) = gCFOriginalFinalizes[CFGetTypeID(cf)];
+            if(fptr)
+                fptr(cf);
+        }
+    });
+}
+#endif
+
+static BOOL IsTollFreeBridged(Class class, id obj)
+{
+#if COREFOUNDATION_HACK_LEVEL >= 1
+    CFTypeID typeID = CFGetTypeID(obj);
+    Class tfbClass = __CFRuntimeObjCClassTable[typeID];
+    return class == tfbClass;
+#else
+    NSString *className = NSStringFromClass(class);
+    return [className hasPrefix:@"NSCF"] || [className hasPrefix:@"__NSCF"];
+#endif
+}
+
+static BOOL IsConstantObject(id obj)
+{
+  NSUInteger retainCount = [obj retainCount];
+  return retainCount == UINT_MAX || retainCount == INT_MAX;
+}
+
+#if COREFOUNDATION_HACK_LEVEL >= 3
+void _CFRelease(CFTypeRef cf);
+
++ (void)releaseLater: (CFTypeRef)cf fromThread: (mach_port_t)thread
+{
+    BOOL retry = YES;
+    
+    while(retry)
+    {
+        BLOCK_QUALIFIER const void *pc;
+        // ensure that the PC is outside our inner code when fetching it,
+        // so we don't have to check for all the nested calls
+        WhileLocked({
+            pc = GetPC(thread);
+        });
+        
+        if(pc != kPCError)
+        {
+            if(pc == kPCThreadExited || pc < (void *)CustomCFFinalize || pc > (void *)IsTollFreeBridged)
+            {
+                Dl_info info;
+                int success = dladdr(pc, &info);
+                if(success)
+                {
+                    if(info.dli_saddr != _CFRelease)
+                    {
+                        retry = NO; // success!
+                        CFRelease(cf);
+                        mach_port_mod_refs(mach_task_self(), thread, MACH_PORT_RIGHT_SEND, -1 ); // "release"
+                    }
+                }
+            }
+        }
+    }
+}
+#endif
+
+static BOOL IsKVOSubclass(id obj)
+{
+#if KVO_HACK_LEVEL >= 1
+    return [obj respondsToSelector: @selector(_isKVOA)] && [obj _isKVOA];
+#else
+    return [obj class] == class_getSuperclass(object_getClass(obj));
+#endif
+}
+
+static Class CreatePlainCustomSubclass(Class class)
+{
+    NSString *newName = [NSString stringWithFormat: @"%s_MAZeroingWeakRefSubclass", class_getName(class)];
+    const char *newNameC = [newName UTF8String];
+    
+    Class subclass = objc_allocateClassPair(class, newNameC, 0);
+    
+    Method release = class_getInstanceMethod(class, @selector(release));
+    Method dealloc = class_getInstanceMethod(class, @selector(dealloc));
+    Method classForCoder = class_getInstanceMethod(class, @selector(classForCoder));
+    class_addMethod(subclass, @selector(release), (IMP)CustomSubclassRelease, method_getTypeEncoding(release));
+    class_addMethod(subclass, @selector(dealloc), (IMP)CustomSubclassDealloc, method_getTypeEncoding(dealloc));
+    class_addMethod(subclass, @selector(classForCoder), (IMP)CustomSubclassClassForCoder, method_getTypeEncoding(classForCoder));
+    
+    objc_registerClassPair(subclass);
+    
+    return subclass;
+}
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#endif
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+static void SetSuperclass(Class class, Class newSuper)
+{
+    class_setSuperclass(class, newSuper);
+}
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+static void RegisterCustomSubclass(Class subclass, Class superclass)
+{
+    [gCustomSubclassMap setObject: subclass forKey: superclass];
+    [gCustomSubclasses addObject: subclass];
+}
+
+static Class CreateCustomSubclass(Class class, id obj)
+{
+    if(IsTollFreeBridged(class, obj))
+    {
+#if COREFOUNDATION_HACK_LEVEL >= 2
+        CFTypeID typeID = CFGetTypeID(obj);
+        CFRuntimeClass *cfclass = _CFRuntimeGetClassWithTypeID(typeID);
+        
+        if(typeID >= gCFOriginalFinalizesSize)
+        {
+            gCFOriginalFinalizesSize = typeID + 1;
+            gCFOriginalFinalizes = realloc(gCFOriginalFinalizes, gCFOriginalFinalizesSize * sizeof(*gCFOriginalFinalizes));
+        }
+        
+        do {
+            gCFOriginalFinalizes[typeID] = cfclass->finalize;
+        } while(!OSAtomicCompareAndSwapPtrBarrier(gCFOriginalFinalizes[typeID], CustomCFFinalize, (void *)&cfclass->finalize));
+#else
+        NSCAssert2(0, @"Cannot create zeroing weak reference to object of type %@ with COREFOUNDATION_HACK_LEVEL set to %d", class, COREFOUNDATION_HACK_LEVEL);          
+#endif
+        return class;
+    }
+    else
+    {
+        Class classToSubclass = class;
+        Class newClass = nil;
+        BOOL isKVO = IsKVOSubclass(obj);
+        if(isKVO)
+        {
+            classToSubclass = class_getSuperclass(class);
+            newClass = [gCustomSubclassMap objectForKey: classToSubclass];
+        }
+        
+        if(!newClass)
+        {
+            newClass = CreatePlainCustomSubclass(classToSubclass);
+            if(isKVO)
+            {
+                SetSuperclass(class, newClass); // EVIL EVIL EVIL
+                
+                // if you thought setting the superclass was evil, wait until you get a load of this
+                // for some reason, KVO stores the superclass of the KVO class in the class's indexed ivars
+                // I don't know why they don't just use class_getSuperclass, but there we are
+                // this has to be set as well, otherwise KVO can skip over our dealloc, causing
+                // weak references not to get zeroed, doh!
+                id *kvoSuperclass = object_getIndexedIvars(class);
+                *kvoSuperclass = newClass;
+                
+                RegisterCustomSubclass(newClass, classToSubclass);
+            }
+        }
+        
+        return newClass;
+    }
+}
+
+static void EnsureCustomSubclass(id obj)
+{
+    if(!GetCustomSubclass(obj) && !IsConstantObject(obj))
+    {
+        Class class = object_getClass(obj);
+        Class subclass = [gCustomSubclassMap objectForKey: class];
+        if(!subclass)
+        {
+            subclass = CreateCustomSubclass(class, obj);
+            RegisterCustomSubclass(subclass, class);
+        }
+        
+        // only set the class if the current one is its superclass
+        // otherwise it's possible that it returns something farther up in the hierarchy
+        // and so there's no need to set it then
+        if(class_getSuperclass(subclass) == class)
+            object_setClass(obj, subclass);
+    }
+}
+
+static void RegisterRef(MAZeroingWeakRef *ref, id target)
+{
+    WhileLocked({
+        EnsureCustomSubclass(target);
+        AddWeakRefToObject(target, ref);
+#if COREFOUNDATION_HACK_LEVEL >= 3
+        if(IsTollFreeBridged(object_getClass(target), target))
+            CFSetAddValue(gCFWeakTargets, target);
+#endif
+    });
+}
+
+static void UnregisterRef(MAZeroingWeakRef *ref)
+{
+    WhileLocked({
+        id target = ref->_target;
+        
+        if(target)
+            RemoveWeakRefFromObject(target, ref);
+    });
+}
+
++ (BOOL)canRefCoreFoundationObjects
+{
+    return COREFOUNDATION_HACK_LEVEL >= 2 || objc_storeWeak_fptr;
+}
+
++ (id)refWithTarget: (id)target
+{
+    return [[[self alloc] initWithTarget: target] autorelease];
+}
+
+- (id)initWithTarget: (id)target
+{
+    if((self = [self init]))
+    {
+        if(objc_storeWeak_fptr)
+        {
+            objc_storeWeak_fptr(&_target, target);
+        }
+        else
+        {
+            _target = target;
+            RegisterRef(self, target);
+        }
+    }
+    return self;
+}
+
+- (void)dealloc
+{
+    if(objc_storeWeak_fptr)
+        objc_storeWeak_fptr(&_target, nil);
+    else
+        UnregisterRef(self);
+    
+#if NS_BLOCKS_AVAILABLE
+    [_cleanupBlock release];
+#endif
+    [super dealloc];
+}
+
+- (NSString *)description
+{
+    return [NSString stringWithFormat: @"<%@: %p -> %@>", [self class], self, [self target]];
+}
+
+#if NS_BLOCKS_AVAILABLE
+- (void)setCleanupBlock: (void (^)(id target))block
+{
+    block = [block copy];
+    [_cleanupBlock release];
+    _cleanupBlock = block;
+    
+    if(objc_loadWeak_fptr)
+    {
+        // wrap a pool around this code, otherwise it artificially extends
+        // the lifetime of the target object
+        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+        
+        id target = [self target];
+        if(target)
+        {
+            _MAZeroingWeakRefCleanupHelper *helper = [[_MAZeroingWeakRefCleanupHelper alloc] initWithRef: self target: target];
+            
+            static void *associatedKey = &associatedKey;
+            objc_setAssociatedObject(target, associatedKey, helper, OBJC_ASSOCIATION_RETAIN);
+            
+            [helper release];
+        }
+        
+        [pool release];
+    }
+}
+#endif
+
+- (id)target
+{
+    if(objc_loadWeak_fptr)
+    {
+        return objc_loadWeak_fptr(&_target);
+    }
+    else
+    {
+        BLOCK_QUALIFIER id ret;
+        WhileLocked({
+            ret = [_target retain];
+        });
+        return [ret autorelease];
+    }
+}
+
+- (void)_zeroTarget
+{
+    _target = nil;
+}
+
+- (void)_executeCleanupBlockWithTarget: (id)target
+{
+#if NS_BLOCKS_AVAILABLE
+    if(_cleanupBlock)
+    {
+        _cleanupBlock(target);
+        [_cleanupBlock release];
+        _cleanupBlock = nil;
+    }
+#endif
+}
+
+@end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Frameworks/MAZeroingWeakRef/Source/main.m	Sun Aug 21 16:17:51 2011 -0500
@@ -0,0 +1,536 @@
+//
+//  main.m
+//  ZeroingWeakRef
+//
+//  Created by Michael Ash on 7/5/10.
+//  Copyright 2010 __MyCompanyName__. All rights reserved.
+//
+
+
+#import <Foundation/Foundation.h>
+
+#import <objc/runtime.h>
+
+#import "MANotificationCenterAdditions.h"
+#import "MAZeroingWeakProxy.h"
+#import "MAZeroingWeakRef.h"
+#import "MAWeakArray.h"
+#import "MAWeakDictionary.h"
+
+
+@interface NotificationReceiver : NSObject
+{
+    int *_noteCounter;
+}
+
+- (id)initWithCounter: (int *)counter;
+
+@end
+
+@implementation NotificationReceiver
+
+- (id)initWithCounter: (int *)counter
+{
+    _noteCounter = counter;
+    return self;
+}
+
+- (void)gotNote: (NSNotification *)note
+{
+    (*_noteCounter)++;
+}
+
+@end
+
+@interface KVOTargetSuperclass : NSObject {} @end
+@implementation KVOTargetSuperclass @end
+
+@interface KVOTarget : KVOTargetSuperclass {} @end
+@implementation KVOTarget
+
+- (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];
+    block();
+    [pool release];
+}
+
+static int gFailureCount;
+
+void Test(void (*func)(void), const char *name)
+{
+    WithPool(^{
+        int failureCount = gFailureCount;
+        NSLog(@"Testing %s", name);
+        func();
+        NSLog(@"%s: %s", name, failureCount == gFailureCount ? "SUCCESS" : "FAILED");
+    });
+}
+
+BOOL TestException(void (^block)(void))
+{
+    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+    @try {
+        block();
+        return NO;
+    }
+    @catch (NSException * e) {        
+        return YES;
+    } @finally {
+      [pool drain];
+    }
+}
+
+#define TEST(func) Test(func, #func)
+
+#define TEST_EXCEPTION(block) do { \
+  if(!TestException(block)) { \
+    gFailureCount++; \
+    NSLog(@"%s:%d: assertion failed: exception was not thrown", __func__, __LINE__); \
+  } \
+} while(0)
+
+#define TEST_ASSERT(cond, ...) do { \
+    if(!(cond)) { \
+        gFailureCount++; \
+        NSString *message = [NSString stringWithFormat: @"" __VA_ARGS__]; \
+        NSLog(@"%s:%d: assertion failed: %s %@", __func__, __LINE__, #cond, message); \
+    } \
+} while(0)
+
+static BOOL WaitForNil(id (^block)(void))
+{
+    NSProcessInfo *pi = [NSProcessInfo processInfo];
+    
+    NSTimeInterval start = [pi systemUptime];
+    __block BOOL found;
+    do
+    {
+        WithPool(^{
+            found = block() != nil;
+        });
+    } while(found && [pi systemUptime] - start < 10);
+    
+    return !found;
+}
+
+static BOOL NilTarget(MAZeroingWeakRef *ref)
+{
+    return WaitForNil(^{ return [ref target]; });
+}
+
+static void TestBasic(void)
+{
+    NSObject *obj = [[NSObject alloc] init];
+    MAZeroingWeakRef *ref = [[MAZeroingWeakRef alloc] initWithTarget: obj];
+    WithPool(^{
+        TEST_ASSERT([ref target]);
+        [obj release];
+    });
+    TEST_ASSERT(NilTarget(ref), @"ref target still live after object destroyed: %@", ref);
+    [ref release];
+}
+
+static void TestRefDestroyedFirst(void)
+{
+    NSObject *obj = [[NSObject alloc] init];
+    MAZeroingWeakRef *ref = [[MAZeroingWeakRef alloc] initWithTarget: obj];
+    WithPool(^{
+        TEST_ASSERT([ref target]);
+        [ref release];
+    });
+    [obj release];
+}
+
+static void TestDoubleRef(void)
+{
+    NSObject *obj = [[NSObject alloc] init];
+    MAZeroingWeakRef *ref1 = [[MAZeroingWeakRef alloc] initWithTarget: obj];
+    MAZeroingWeakRef *ref2 = [[MAZeroingWeakRef alloc] initWithTarget: obj];
+    WithPool(^{
+        TEST_ASSERT([ref1 target]);
+        TEST_ASSERT([ref2 target]);
+        [obj release];
+    });
+    TEST_ASSERT(NilTarget(ref1), @"ref target still live after object destroyed: %@", ref1);
+    TEST_ASSERT(NilTarget(ref2), @"ref target still live after object destroyed: %@", ref2);
+    [ref1 release];
+    [ref2 release];
+}
+
+static void TestRefToRef(void)
+{
+    NSObject *obj = [[NSObject alloc] init];
+    MAZeroingWeakRef *ref1 = [[MAZeroingWeakRef alloc] initWithTarget: obj];
+    MAZeroingWeakRef *ref2 = [[MAZeroingWeakRef alloc] initWithTarget: ref1];
+    WithPool(^{
+        TEST_ASSERT([ref1 target]);
+        TEST_ASSERT([ref2 target]);
+        [obj release];
+    });
+    WithPool(^{
+        TEST_ASSERT(NilTarget(ref1), @"ref target still live after object destroyed: %@", ref1);
+        TEST_ASSERT([ref2 target], @"ref target dead even though target ref still alive: %@", ref2);
+        [ref1 release];
+    });
+    TEST_ASSERT(NilTarget(ref2), @"ref target still live after object destroyed: %@", ref2);
+    [ref2 release];
+}
+
+static void TestNSArrayTarget(void)
+{
+    if(![MAZeroingWeakRef canRefCoreFoundationObjects])
+    {
+        NSLog(@"MAZeroingWeakRef can't reference CF objects, not testing them");
+        return;
+    }
+    
+    NSMutableArray *array = [[NSMutableArray alloc] init];
+    MAZeroingWeakRef *ref = [[MAZeroingWeakRef alloc] initWithTarget: array];
+    WithPool(^{
+        TEST_ASSERT([ref target]);
+        [array release];
+    });
+    TEST_ASSERT(NilTarget(ref), @"ref target still live after object destroyed: %@", ref);
+    [ref release];
+}
+
+static void TestNSStringTarget(void)
+{
+    if(![MAZeroingWeakRef canRefCoreFoundationObjects])
+    {
+        NSLog(@"MAZeroingWeakRef can't reference CF objects, not testing them");
+        return;
+    }
+    
+    NSString *str = [[NSMutableString alloc] initWithString: @"Test String"];
+    MAZeroingWeakRef *ref = [[MAZeroingWeakRef alloc] initWithTarget: str];
+    WithPool(^{
+        TEST_ASSERT([ref target]);
+        [str release];
+    });
+    [ref release];
+}
+
+static void TestNSConstantTarget(void)
+{
+    if ([MAZeroingWeakRef canRefCoreFoundationObjects]) {
+      NSLog(@"MAZeroingWeakRef can reference CF objects, not testing constant object");
+      return;
+    }
+    
+    NSString *str = @"Constant String";
+    MAZeroingWeakRef *ref = [[MAZeroingWeakRef alloc] initWithTarget: str];
+    WithPool(^{
+      TEST_ASSERT([ref target]);
+      [str release];
+    });
+    [ref release];  
+
+    TEST_EXCEPTION(^{
+      NSString *str = [[NSMutableString alloc] initWithString: @"Not Constant String"];
+      MAZeroingWeakRef *ref = [[MAZeroingWeakRef alloc] initWithTarget: str];
+      [ref release];
+    });
+}
+
+static void TestCleanup(void)
+{
+    __block BOOL cleanedUp = NO;
+    NSObject *obj = [[NSObject alloc] init];
+    MAZeroingWeakRef *ref = [[MAZeroingWeakRef alloc] initWithTarget: obj];
+    [ref setCleanupBlock: ^(id target) { cleanedUp = YES; }];
+    [obj release];
+    TEST_ASSERT(cleanedUp);
+    [ref release];
+}
+
+static void TestCFCleanup(void)
+{
+    if(![MAZeroingWeakRef canRefCoreFoundationObjects])
+    {
+        NSLog(@"MAZeroingWeakRef can't reference CF objects, not testing them");
+        return;
+    }
+    
+    __block volatile BOOL cleanedUp = NO;
+    NSObject *obj = [[NSMutableString alloc] init];
+    MAZeroingWeakRef *ref = [[MAZeroingWeakRef alloc] initWithTarget: obj];
+    [ref setCleanupBlock: ^(id target) { cleanedUp = YES; }];
+    [obj release];
+    TEST_ASSERT(WaitForNil(^{ return (id)!cleanedUp; })
+);
+    [ref release];
+}
+
+static void TestNotification(void)
+{
+    int notificationCounter = 0;
+    NotificationReceiver *receiver = [[NotificationReceiver alloc] initWithCounter: &notificationCounter];
+    [[NSNotificationCenter defaultCenter] addWeakObserver: receiver selector: @selector(gotNote:) name: @"name" object: @"object"];
+    [[NSNotificationCenter defaultCenter] postNotificationName: @"name" object: @"object"];
+    TEST_ASSERT(notificationCounter == 1);
+    [receiver release];
+    [[NSNotificationCenter defaultCenter] postNotificationName: @"name" object: @"object"];
+    TEST_ASSERT(notificationCounter == 1);
+}
+
+static void TestWeakArray(void)
+{
+    if(![MAZeroingWeakRef canRefCoreFoundationObjects])
+    {
+        NSLog(@"MAZeroingWeakRef can't reference CF objects, not testing them");
+        return;
+    }
+    
+    NSString *str1 = [[NSMutableString alloc] initWithString: @"Test String 1"];
+    NSString *str2 = [[NSMutableString alloc] initWithString: @"Test String 2"];
+    NSString *str3 = [[NSMutableString alloc] initWithString: @"Test String 3"];
+    
+    MAWeakArray *array = [[MAWeakArray alloc] init];
+    [array addObject: str1];
+    [array addObject: str2];
+    [array addObject: str3];
+    
+    [str2 release];
+    
+    WithPool(^{
+        TEST_ASSERT([array objectAtIndex: 0]);
+        TEST_ASSERT(WaitForNil(^{ return [array objectAtIndex: 1]; }));
+        TEST_ASSERT([array objectAtIndex: 2]);
+    });
+    
+    [str1 release];
+    [str3 release];
+    
+    TEST_ASSERT(WaitForNil(^{ return [array objectAtIndex: 0]; }));
+    TEST_ASSERT(WaitForNil(^{ return [array objectAtIndex: 1]; }));
+    TEST_ASSERT(WaitForNil(^{ return [array objectAtIndex: 2]; }));
+    [array release];
+}
+
+static void TestWeakDictionary(void)
+{
+    if(![MAZeroingWeakRef canRefCoreFoundationObjects])
+    {
+        NSLog(@"MAZeroingWeakRef can't reference CF objects, not testing them");
+        return;
+    }
+    
+    NSString *str1 = [[NSMutableString alloc] initWithString: @"Test String 1"];
+    NSString *str2 = [[NSMutableString alloc] initWithString: @"Test String 2"];
+    NSString *str3 = [[NSMutableString alloc] initWithString: @"Test String 3"];
+    
+    MAWeakDictionary *dict = [[MAWeakDictionary alloc] init];
+    [dict setObject: str1 forKey: @"str1"];
+    [dict setObject: str2 forKey: @"str2"];
+    [dict setObject: str3 forKey: @"str3"];
+    
+    [str2 release];
+    
+    WithPool(^{
+        TEST_ASSERT([dict objectForKey: @"str1"]);
+        TEST_ASSERT([dict objectForKey: @"str2"] == nil);
+        TEST_ASSERT([dict objectForKey: @"str3"]);
+    });
+    
+    [str1 release];
+    [str3 release];
+    
+    TEST_ASSERT([dict objectForKey: @"str1"] == nil);
+    TEST_ASSERT([dict objectForKey: @"str2"] == nil);
+    TEST_ASSERT([dict objectForKey: @"str3"] == nil);
+    [dict release];
+}
+
+static void TestWeakProxy(void)
+{
+    if(![MAZeroingWeakRef canRefCoreFoundationObjects])
+    {
+        NSLog(@"MAZeroingWeakRef can't reference CF objects, not testing them");
+        return;
+    }
+    
+    NSMutableString *str = [[NSMutableString alloc] init];
+    NSMutableString *proxy = [[MAZeroingWeakProxy alloc] initWithTarget: str];
+    
+    WithPool(^{
+        TEST_ASSERT([proxy isEqual: @""]);
+        [proxy appendString: @"Hello, world!"];
+        TEST_ASSERT([proxy isEqual: @"Hello, world!"]);
+        TEST_ASSERT([proxy length] == [@"Hello, world!" length]);
+        [proxy deleteCharactersInRange: NSMakeRange(0, 7)];
+        TEST_ASSERT([proxy isEqual: @"world!"]);
+    });
+    
+    [str release];
+    
+    TEST_ASSERT([proxy length] == 0);
+    TEST_ASSERT([(id)proxy zeroingProxyTarget] == nil);
+    [proxy release];
+}
+
+static void TestCleanupBlockReleasingZWR(void)
+{
+    NSObject *obj = [[NSObject alloc] init];
+    WithPool(^{
+        __block MAZeroingWeakRef *ref1 = [[MAZeroingWeakRef alloc] initWithTarget: obj];
+        __block MAZeroingWeakRef *ref2 = [[MAZeroingWeakRef alloc] initWithTarget: obj];
+        __block MAZeroingWeakRef *ref3 = [[MAZeroingWeakRef alloc] initWithTarget: obj];
+        
+        id cleanupBlock = ^{
+            [ref1 release];
+            ref1 = nil;
+            [ref2 release];
+            ref2 = nil;
+            [ref3 release];
+            ref3 = nil;
+        };
+        
+        [ref1 setCleanupBlock: cleanupBlock];
+        [ref2 setCleanupBlock: cleanupBlock];
+        [ref3 setCleanupBlock: cleanupBlock];
+    });
+    [obj release];
+}
+
+static void TestAccidentalResurrectionInCleanupBlock(void)
+{
+    NSObject *obj = [[NSObject alloc] init];
+    WithPool(^{
+        __block MAZeroingWeakRef *ref1 = [[MAZeroingWeakRef alloc] initWithTarget: obj];
+        __block MAZeroingWeakRef *ref2 = [[MAZeroingWeakRef alloc] initWithTarget: obj];
+        
+        id cleanupBlock = ^{
+            [ref1 target];
+            [ref2 target];
+        };
+        
+        [ref1 setCleanupBlock: cleanupBlock];
+        [ref2 setCleanupBlock: cleanupBlock];
+        
+        [obj release];
+        [ref1 release];
+        [ref2 release];
+    });
+}
+
+static void TestKVOTarget(void)
+{
+    KVOTarget *target = [[KVOTarget alloc] init];
+    void (^describe)(void) = ^{
+        return;
+        
+        Class nsClass = [target class];
+        NSString *nsName = [nsClass description];
+        Class objcClass = object_getClass(target);
+        const char *objcName = class_getName(objcClass);
+        
+        NSLog(@"%@, %s %@ %p %p", target, objcName, nsName, objcClass, nsClass);
+    };
+    
+    describe();
+    
+    [target addObserver: target forKeyPath: @"key" options: 0 context: NULL];
+    describe();
+    
+    MAZeroingWeakRef *ref = [[MAZeroingWeakRef alloc] initWithTarget: target];
+    describe();
+    
+    [target setKey: @"value"];
+    describe();
+    
+    [ref release];
+    describe();
+}
+
+static void TestClassForCoder(void)
+{
+    NSObject *obj = [[NSObject alloc] init];
+    TEST_ASSERT([obj classForCoder] == [NSObject class]);
+    [[[MAZeroingWeakRef alloc] initWithTarget: obj] autorelease];
+    TEST_ASSERT([obj classForCoder] == [NSObject class]);
+}
+
+static void TestKVOReleaseNoCrash(void)
+{
+	KVOTarget *target = [[KVOTarget alloc] init];
+    
+	MAZeroingWeakRef *ref = [[MAZeroingWeakRef alloc] initWithTarget: target];
+    
+	[target addObserver: target forKeyPath: @"key" options: 0 context: NULL];
+    
+	[target setKey: @"value"];
+    
+    // destroying target without removing the observer tosses a warning to the console
+    // but it's necessary in order to test this failure mode
+	[target release];	
+	[ref target];
+    
+	[ref release];
+}
+
+static void TestKVOReleaseCrash(void)
+{
+	KVOTarget *target = [[KVOTarget alloc] init];
+    
+	[target addObserver: target forKeyPath: @"key" options: 0 context: NULL];
+    
+	MAZeroingWeakRef *ref = [[MAZeroingWeakRef alloc] initWithTarget: target];
+    
+	[target setKey: @"value"];
+    
+	[target release];	
+	[ref target];
+    
+	[ref release];
+}
+
+int main(int argc, const char * argv[])
+{
+    WithPool(^{
+        TEST(TestBasic);
+        TEST(TestRefDestroyedFirst);
+        TEST(TestDoubleRef);
+        TEST(TestRefToRef);
+        TEST(TestNSArrayTarget);
+        TEST(TestNSStringTarget);
+        TEST(TestNSConstantTarget);
+        TEST(TestCleanup);
+        TEST(TestCFCleanup);
+        TEST(TestNotification);
+        TEST(TestWeakArray);
+        TEST(TestWeakDictionary);
+        TEST(TestWeakProxy);
+        TEST(TestCleanupBlockReleasingZWR);
+        TEST(TestAccidentalResurrectionInCleanupBlock);
+        TEST(TestKVOTarget);
+        TEST(TestClassForCoder);
+        TEST(TestKVOReleaseNoCrash);
+        TEST(TestKVOReleaseCrash);
+        
+        NSString *message;
+        if(gFailureCount)
+            message = [NSString stringWithFormat: @"FAILED: %d total assertion failure%s", gFailureCount, gFailureCount > 1 ? "s" : ""];
+        else
+            message = @"SUCCESS";
+        NSLog(@"Tests complete: %@", message);
+    });
+    return 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Frameworks/MAZeroingWeakRef/ZeroingWeakRef.xcodeproj/project.pbxproj	Sun Aug 21 16:17:51 2011 -0500
@@ -0,0 +1,257 @@
+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 46;
+	objects = {
+
+/* Begin PBXBuildFile section */
+		C208C96011EBB8F100A8E38D /* MANotificationCenterAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = C208C95F11EBB8F100A8E38D /* MANotificationCenterAdditions.m */; };
+		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 */; };
+		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 */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+		C2D7540511E2588600816068 /* CopyFiles */ = {
+			isa = PBXCopyFilesBuildPhase;
+			buildActionMask = 2147483647;
+			dstPath = /usr/share/man/man1/;
+			dstSubfolderSpec = 0;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 1;
+		};
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+		C208C95E11EBB8F100A8E38D /* MANotificationCenterAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MANotificationCenterAdditions.h; sourceTree = "<group>"; };
+		C208C95F11EBB8F100A8E38D /* MANotificationCenterAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MANotificationCenterAdditions.m; sourceTree = "<group>"; };
+		C25675EF11E25C6A00CAB48E /* MAZeroingWeakRef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MAZeroingWeakRef.h; sourceTree = "<group>"; };
+		C25675F011E25C6A00CAB48E /* MAZeroingWeakRef.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MAZeroingWeakRef.m; sourceTree = "<group>"; };
+		C26F610311F207270080EC96 /* MAZeroingWeakProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MAZeroingWeakProxy.h; sourceTree = "<group>"; };
+		C26F610411F207270080EC96 /* MAZeroingWeakProxy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MAZeroingWeakProxy.m; sourceTree = "<group>"; };
+		C2D7540711E2588600816068 /* ZeroingWeakRef */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ZeroingWeakRef; sourceTree = BUILT_PRODUCTS_DIR; };
+		C2D7540B11E2588600816068 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
+		C2D7540F11E2588600816068 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
+		C2D7541211E2588600816068 /* ZeroingWeakRef_Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ZeroingWeakRef_Prefix.pch; sourceTree = "<group>"; };
+		C2DF1F2411ED2C1300EFC8AE /* MAWeakArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MAWeakArray.h; sourceTree = "<group>"; };
+		C2DF1F2511ED2C1300EFC8AE /* MAWeakArray.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MAWeakArray.m; sourceTree = "<group>"; };
+		C2DF1F2911ED2C4700EFC8AE /* MAWeakDictionary.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MAWeakDictionary.h; sourceTree = "<group>"; };
+		C2DF1F2A11ED2C4700EFC8AE /* MAWeakDictionary.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MAWeakDictionary.m; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+		C2D7540411E2588600816068 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				C2D7540C11E2588600816068 /* Foundation.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+		C2D753FA11E2588500816068 = {
+			isa = PBXGroup;
+			children = (
+				C2D7540111E2588600816068 /* Source */,
+				C2D7540811E2588600816068 /* Products */,
+				C2D7540A11E2588600816068 /* Frameworks */,
+				C2D7541111E2588600816068 /* Other Sources */,
+			);
+			sourceTree = "<group>";
+		};
+		C2D7540111E2588600816068 /* Source */ = {
+			isa = PBXGroup;
+			children = (
+				C2D7540F11E2588600816068 /* main.m */,
+				C25675EF11E25C6A00CAB48E /* MAZeroingWeakRef.h */,
+				C25675F011E25C6A00CAB48E /* MAZeroingWeakRef.m */,
+				C26F610311F207270080EC96 /* MAZeroingWeakProxy.h */,
+				C26F610411F207270080EC96 /* MAZeroingWeakProxy.m */,
+				C208C95E11EBB8F100A8E38D /* MANotificationCenterAdditions.h */,
+				C208C95F11EBB8F100A8E38D /* MANotificationCenterAdditions.m */,
+				C2DF1F2411ED2C1300EFC8AE /* MAWeakArray.h */,
+				C2DF1F2511ED2C1300EFC8AE /* MAWeakArray.m */,
+				C2DF1F2911ED2C4700EFC8AE /* MAWeakDictionary.h */,
+				C2DF1F2A11ED2C4700EFC8AE /* MAWeakDictionary.m */,
+			);
+			path = Source;
+			sourceTree = "<group>";
+		};
+		C2D7540811E2588600816068 /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				C2D7540711E2588600816068 /* ZeroingWeakRef */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		C2D7540A11E2588600816068 /* Frameworks */ = {
+			isa = PBXGroup;
+			children = (
+				C2D7540B11E2588600816068 /* Foundation.framework */,
+			);
+			name = Frameworks;
+			sourceTree = "<group>";
+		};
+		C2D7541111E2588600816068 /* Other Sources */ = {
+			isa = PBXGroup;
+			children = (
+				C2D7541211E2588600816068 /* ZeroingWeakRef_Prefix.pch */,
+			);
+			name = "Other Sources";
+			sourceTree = "<group>";
+		};
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+		C2D7540611E2588600816068 /* ZeroingWeakRef */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = C2D7541511E2588600816068 /* Build configuration list for PBXNativeTarget "ZeroingWeakRef" */;
+			buildPhases = (
+				C2D7540311E2588600816068 /* Sources */,
+				C2D7540411E2588600816068 /* Frameworks */,
+				C2D7540511E2588600816068 /* CopyFiles */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = ZeroingWeakRef;
+			productName = ZeroingWeakRef;
+			productReference = C2D7540711E2588600816068 /* ZeroingWeakRef */;
+			productType = "com.apple.product-type.tool";
+		};
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+		C2D753FC11E2588500816068 /* Project object */ = {
+			isa = PBXProject;
+			buildConfigurationList = C2D753FF11E2588500816068 /* Build configuration list for PBXProject "ZeroingWeakRef" */;
+			compatibilityVersion = "Xcode 3.2";
+			developmentRegion = English;
+			hasScannedForEncodings = 0;
+			knownRegions = (
+				English,
+				Japanese,
+				French,
+				German,
+			);
+			mainGroup = C2D753FA11E2588500816068;
+			productRefGroup = C2D7540811E2588600816068 /* Products */;
+			projectDirPath = "";
+			projectRoot = "";
+			targets = (
+				C2D7540611E2588600816068 /* ZeroingWeakRef */,
+			);
+		};
+/* End PBXProject section */
+
+/* Begin PBXSourcesBuildPhase section */
+		C2D7540311E2588600816068 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				C2D7541011E2588600816068 /* main.m in Sources */,
+				C25675F111E25C6A00CAB48E /* MAZeroingWeakRef.m in Sources */,
+				C208C96011EBB8F100A8E38D /* MANotificationCenterAdditions.m in Sources */,
+				C2DF1F2611ED2C1300EFC8AE /* MAWeakArray.m in Sources */,
+				C2DF1F2B11ED2C4700EFC8AE /* MAWeakDictionary.m in Sources */,
+				C26F610511F207270080EC96 /* MAZeroingWeakProxy.m in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+		C2D7541311E2588600816068 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				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;
+		};
+		C2D7541411E2588600816068 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				PREBINDING = NO;
+				SDKROOT = macosx10.6;
+			};
+			name = Release;
+		};
+		C2D7541611E2588600816068 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				COPY_PHASE_STRIP = NO;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+				GCC_MODEL_TUNING = G5;
+				GCC_PRECOMPILE_PREFIX_HEADER = YES;
+				GCC_PREFIX_HEADER = ZeroingWeakRef_Prefix.pch;
+				INSTALL_PATH = /usr/local/bin;
+				PRODUCT_NAME = ZeroingWeakRef;
+			};
+			name = Debug;
+		};
+		C2D7541711E2588600816068 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				COPY_PHASE_STRIP = YES;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+				GCC_MODEL_TUNING = G5;
+				GCC_PRECOMPILE_PREFIX_HEADER = YES;
+				GCC_PREFIX_HEADER = ZeroingWeakRef_Prefix.pch;
+				INSTALL_PATH = /usr/local/bin;
+				PRODUCT_NAME = ZeroingWeakRef;
+			};
+			name = Release;
+		};
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+		C2D753FF11E2588500816068 /* Build configuration list for PBXProject "ZeroingWeakRef" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				C2D7541311E2588600816068 /* Debug */,
+				C2D7541411E2588600816068 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		C2D7541511E2588600816068 /* Build configuration list for PBXNativeTarget "ZeroingWeakRef" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				C2D7541611E2588600816068 /* Debug */,
+				C2D7541711E2588600816068 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+/* End XCConfigurationList section */
+	};
+	rootObject = C2D753FC11E2588500816068 /* Project object */;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Frameworks/MAZeroingWeakRef/ZeroingWeakRef_Prefix.pch	Sun Aug 21 16:17:51 2011 -0500
@@ -0,0 +1,7 @@
+//
+// Prefix header for all source files of the 'ZeroingWeakRef' target in the 'ZeroingWeakRef' project
+//
+
+#ifdef __OBJC__
+#endif
+