Commits

Ronald Oussoren committed 1ce7b84

- copyWithZone: should now work correctly in all cases.

- That is, given::

class Foo(...):
def copyWithZone_(self, zone):
...

You should end up with a working copyWithZone: method whether
the super_class implements NSCopying or not. This is implemented with
two mechanisms:

1) A copyWithZone: implementation for python subclasses of classes that
implement NSCopying. This subclass adjust the refcounts of PyObject*
slots and copies the __dict__

2) If the ObjC superclass implements NSCopying and the first python child
also implements copyWithZone_ an intermediate class is constructed that
contains just the method mentioned in item 1.

Comments (0)

Files changed (12)

 <li><a href="#complete-cocoa-wrapping" id="id10" name="id10">Complete Cocoa wrapping</a></li>
 <li><a href="#pickle-support" id="id11" name="id11">Pickle support</a></li>
 <li><a href="#nscoder-support" id="id12" name="id12">NSCoder support</a></li>
-<li><a href="#copy" id="id13" name="id13"><code><span>-copy</span></code></a></li>
-<li><a href="#known-issues" id="id14" name="id14">Known issues</a></li>
-<li><a href="#code-cleanup" id="id15" name="id15">Code cleanup</a></li>
-<li><a href="#cleanup-examples" id="id16" name="id16">Cleanup Examples</a></li>
-<li><a href="#performance-tuning-testing" id="id17" name="id17">Performance tuning/testing</a></li>
-<li><a href="#add-freelists" id="id18" name="id18">Add freelists</a></li>
-<li><a href="#formal-protocols-distributed-objects" id="id19" name="id19">Formal Protocols, Distributed Objects</a></li>
-<li><a href="#links-to-apple-documentation" id="id20" name="id20">Links to Apple documentation</a></li>
-<li><a href="#implement-more-of-nsmutabledictionary-in-oc-pythondictionary" id="id21" name="id21">Implement more of NSMutableDictionary in OC_PythonDictionary</a></li>
-<li><a href="#clean-up-oc-pythonobject" id="id22" name="id22">Clean up OC_PythonObject</a></li>
-<li><a href="#rewrite-scripts-find-raw-pointers-py" id="id23" name="id23">Rewrite scripts/find-raw-pointers.py</a></li>
-<li><a href="#finish-refactoring-of-the-code-generator-scripts" id="id24" name="id24">Finish refactoring of the code-generator scripts</a></li>
-<li><a href="#setup-py-cleanup" id="id25" name="id25">setup.py cleanup</a></li>
-<li><a href="#unique-proxies-for-python-objects" id="id26" name="id26">Unique proxies for Python objects</a></li>
-<li><a href="#nsset-vs-set" id="id27" name="id27">NSSet vs set</a></li>
-<li><a href="#python-2-4" id="id28" name="id28">Python 2.4</a></li>
-<li><a href="#nslog-stringwithformat" id="id29" name="id29">NSLog, stringWithFormat, ...</a></li>
+<li><a href="#known-issues" id="id13" name="id13">Known issues</a></li>
+<li><a href="#code-cleanup" id="id14" name="id14">Code cleanup</a></li>
+<li><a href="#cleanup-examples" id="id15" name="id15">Cleanup Examples</a></li>
+<li><a href="#performance-tuning-testing" id="id16" name="id16">Performance tuning/testing</a></li>
+<li><a href="#add-freelists" id="id17" name="id17">Add freelists</a></li>
+<li><a href="#links-to-apple-documentation" id="id18" name="id18">Links to Apple documentation</a></li>
+<li><a href="#implement-more-of-nsmutabledictionary-in-oc-pythondictionary" id="id19" name="id19">Implement more of NSMutableDictionary in OC_PythonDictionary</a></li>
+<li><a href="#clean-up-oc-pythonobject" id="id20" name="id20">Clean up OC_PythonObject</a></li>
+<li><a href="#rewrite-scripts-find-raw-pointers-py" id="id21" name="id21">Rewrite scripts/find-raw-pointers.py</a></li>
+<li><a href="#finish-refactoring-of-the-code-generator-scripts" id="id22" name="id22">Finish refactoring of the code-generator scripts</a></li>
+<li><a href="#setup-py-cleanup" id="id23" name="id23">setup.py cleanup</a></li>
+<li><a href="#nsset-vs-set" id="id24" name="id24">NSSet vs set</a></li>
+<li><a href="#python-2-4" id="id25" name="id25">Python 2.4</a></li>
+<li><a href="#nslog-stringwithformat" id="id26" name="id26">NSLog, stringWithFormat, ...</a></li>
 </ul>
 </li>
 </ul>
 the wrong value (type, number of values)</li>
 <li>Add tests for accepting any sequence when depythonifying structs and arrays.</li>
 <li>Add more tests for objc_support.m to unittest.c</li>
-<li>Add tests for OC_PythonArray, OC_PythonDict to unittest.c</li>
 </ul>
 <p>The first two bullets require at least some GUI tests.</p>
 <h2><a href="#id6" name="less-important-items">Less important items</a></h2>
 <ul>
 <li>Likewise for class-builder.m, this file is way to large.</li>
 <li>Allow ivars of Objective-C classes to be introspected
-(but not directly from the __dict__?)</li>
+(but not directly from the __dict__?)<p>NOTE: instance-var.[hm] implements most of this, it just needs to be
+wired up correctly. I'd do this by adding <code><span>pyobjc_instancevars</span></code> to
+instances (simular to <code><span>pyobjc_instanceMethods</span></code>). They cannot be added
+directly to the <code><span>__dict__</span></code> because of this common idiom:</p>
+<pre>
+@interface Foo : NSObject
+{
+   int myvar;
+}
+-(int)myvar;
+-(void)setMyvar:(int)value;
+@end
+</pre>
+</li>
 <li>We've several types that wrap pointer values, such as <code><span>SessionWrapper</span></code> in
 <code><span>Modules/AppKit</span></code>. Should add a function for creating these types, 
 possibly exposed to C code.</li>
 implement these.  Note that property list types should already be serializable
 (<code><span>int</span></code>, <code><span>long</span></code>, <code><span>unicode</span></code>, <code><span>list</span></code>, <code><span>tuple</span></code>, <code><span>dict</span></code>).</p>
 <p>See also <cite>Pickle support</cite>.</p>
-<h3><a href="#id13" name="copy"><code><span>-copy</span></code></a></h3>
-<p>There are issues with implementing <code><span>-copy</span></code> in python, these need to be fixed.</p>
-<p>Specifically, overriding an existing <code><span>-copy</span></code> implementation does not work 
-unless <code><span>__slots__</span> <span>==</span> <span>()</span></code></p>
-<h3><a href="#id14" name="known-issues">Known issues</a></h3>
+<h3><a href="#id13" name="known-issues">Known issues</a></h3>
 <p>It is impossible to support methods with a variable number of arguments in the
 generic code (you have to re-implement almost all of the logic of these 
 methods in order to know how many and which types of arguments are expected).
 we should provide custom wrappers, otherwise we should document alternatives.</p>
 <p>Limitations such as the above should be clearly documented elsewhere, these
 are not necessarily TODO items.</p>
-<h3><a href="#id15" name="code-cleanup">Code cleanup</a></h3>
+<h3><a href="#id14" name="code-cleanup">Code cleanup</a></h3>
 <ul>
 <li>Check all error/exception messages</li>
 <li>Check/cleanup error handling</li>
 <code><span>Modules/objc/struct-wrapper.m</span></code>)</li>
 <li>Use the <code><span>CArray</span></code> API whenever appropriate.</li>
 </ul>
-<h3><a href="#id16" name="cleanup-examples">Cleanup Examples</a></h3>
+<h3><a href="#id15" name="cleanup-examples">Cleanup Examples</a></h3>
 <p>The CurrencyConverter example should be removed, this should be the same as the
 final step of the tutorial. It isn't at the moment because additional cruft in
 the example.</p>
 <ul>
-<li>dictionary.py
-Should be a unittest, and should be added to the (non-existing) manual</li>
+<li>dictionary.py and subclassing-objective-c.py
+These are doctests and should be moved to the documentation (with a hook
+in the unittests for making sure the code keeps working).</li>
 <li>pydict-to-objcdict.py
 Move to unittests</li>
-<li>subclassing-objective-c.py
-Move to documentation (unittest?)</li>
 <li>super-call.py
 Move to documentation  (unittest?)</li>
 </ul>
 <li>how to integrate with MacPython</li>
 <li>how to use PIL with Cocoa</li>
 </ul>
-<h3><a href="#id17" name="performance-tuning-testing">Performance tuning/testing</a></h3>
+<h3><a href="#id16" name="performance-tuning-testing">Performance tuning/testing</a></h3>
 <p>Design and implement a set of performance tests for the bridge. Use this to 
 investigate and fix any possible performance problems.</p>
-<h3><a href="#id18" name="add-freelists">Add freelists</a></h3>
+<h3><a href="#id17" name="add-freelists">Add freelists</a></h3>
 <p>PyObjCSelector objects and PyObjCObject objects are created on
 a regular basis, we should check if using freelists would speed this up. See
 also <cite>Performance tuning/testing</cite>.</p>
-<h3><a href="#id19" name="formal-protocols-distributed-objects">Formal Protocols, Distributed Objects</a></h3>
-<p><code><span>DO</span></code> seems to use formal protocols, we don't fully support those. There is 
-an equivalent to <code><span>@protocol(Foo)</span></code>, and classes can declare that they
-implement formal protocols, but it is not yet possible to define
-a new formal protocol in Python.</p>
-<h3><a href="#id20" name="links-to-apple-documentation">Links to Apple documentation</a></h3>
+<p>NOTE: first add performance tests then experiment with freelists.</p>
+<h3><a href="#id18" name="links-to-apple-documentation">Links to Apple documentation</a></h3>
 <p>Links to Apple documentation are not stable, can we add a layer of indirection
 here, e.g. link to the PyObjC website that will redirect to the right
 location?</p>
 <p>We should also provide links to locally installed documentation,
 especially in the documentation that will be installed on the users machine.</p>
-<h3><a href="#id21" name="implement-more-of-nsmutabledictionary-in-oc-pythondictionary">Implement more of NSMutableDictionary in OC_PythonDictionary</a></h3>
+<h3><a href="#id19" name="implement-more-of-nsmutabledictionary-in-oc-pythondictionary">Implement more of NSMutableDictionary in OC_PythonDictionary</a></h3>
 <p>The implementation of OC_PythonDictionary is very minimal, we should add
 additional methods in the NSMutableDictionary interface if those can be 
 implemented efficiently. The default implementation will take care of the
 methods we cannot implement efficiently.</p>
 <p>And the same is true of OC_PythonArray</p>
-<h3><a href="#id22" name="clean-up-oc-pythonobject">Clean up OC_PythonObject</a></h3>
+<h3><a href="#id20" name="clean-up-oc-pythonobject">Clean up OC_PythonObject</a></h3>
 <p>The code is a mess.</p>
-<h3><a href="#id23" name="rewrite-scripts-find-raw-pointers-py">Rewrite scripts/find-raw-pointers.py</a></h3>
+<h3><a href="#id21" name="rewrite-scripts-find-raw-pointers-py">Rewrite scripts/find-raw-pointers.py</a></h3>
 <p>This is a script for finding 'difficult' methods. The script should be 
 refactored to make it easier to create readable reports.</p>
-<h3><a href="#id24" name="finish-refactoring-of-the-code-generator-scripts">Finish refactoring of the code-generator scripts</a></h3>
+<h3><a href="#id22" name="finish-refactoring-of-the-code-generator-scripts">Finish refactoring of the code-generator scripts</a></h3>
 <ol type="1">
 <li>Change code-generator scripts to use loadBundleFunctions, etc.</li>
 <li>Move the code-generator scripts to <code><span>PyObjCTools</span></code>, to make it easier
 for others to generate wrappers.</li>
 <li>Install <code><span>pyobjc-api.h</span></code>.</li>
 </ol>
-<h3><a href="#id25" name="setup-py-cleanup">setup.py cleanup</a></h3>
+<h3><a href="#id23" name="setup-py-cleanup">setup.py cleanup</a></h3>
 <ul>
 <li>Use 'WrapperGenerator.py', probably need to create a custom build action
 for that.</li>
 </ul>
-<h3><a href="#id26" name="unique-proxies-for-python-objects">Unique proxies for Python objects</a></h3>
-<p>Some Cocoa/CoreFoundation API's basically require that <code><span>a[0]</span> <span>is</span> <span>a[0]</span></code>. The
-container wrappers contain support for that, but we should try to move that
-into the generic core: there should be at most one Objective-C proxy object
-alive for every Python object (just like there's at most one Python proxy for
-every Objective-C object).</p>
-<h3><a href="#id27" name="nsset-vs-set">NSSet vs set</a></h3>
+<h3><a href="#id24" name="nsset-vs-set">NSSet vs set</a></h3>
 <p>Check if it is possible to wrap <code><span>NSSet</span></code> using <code><span>set</span></code> (and v.v.).</p>
 <p>Only implement this when it is possible to convert without loss of information.</p>
-<h3><a href="#id28" name="python-2-4">Python 2.4</a></h3>
+<p><strong>Ronald, 20050130</strong>: <i>converting</i> is not an option: PyObjC takes care to
+preserve the identity of ObjC objects when passed through python. This is 
+necessary for at least some APIs.   Furthermore, both <code><span>NSSet</span></code> and 
+<code><span>__builtin__.set</span></code> are mutable!</p>
+<h3><a href="#id25" name="python-2-4">Python 2.4</a></h3>
 <p>Python 2.4 introduces a decorator syntax. Add convenience functions that
 make it easier to use decorators with PyObjC.</p>
 <p>Also add example programs using decorators. Actually, first add the example(s)
         def myIntMethod_(self, value):
                 pass
 </pre>
-<h3><a href="#id29" name="nslog-stringwithformat">NSLog, stringWithFormat, ...</a></h3>
+<h3><a href="#id26" name="nslog-stringwithformat">NSLog, stringWithFormat, ...</a></h3>
 <p>Functions and methods that use format strings are not properly wrapped. Fix
 that.</p>
 </body>
 
 * Add more tests for objc_support.m to unittest.c
 
-* Add tests for OC_PythonArray, OC_PythonDict to unittest.c
-
 
 The first two bullets require at least some GUI tests.
 
 * Allow ivars of Objective-C classes to be introspected
   (but not directly from the __dict__?)
 
+  NOTE: instance-var.[hm] implements most of this, it just needs to be
+  wired up correctly. I'd do this by adding ``pyobjc_instancevars`` to
+  instances (simular to ``pyobjc_instanceMethods``). They cannot be added
+  directly to the ``__dict__`` because of this common idiom::
+
+    @interface Foo : NSObject
+    {
+       int myvar;
+    }
+    -(int)myvar;
+    -(void)setMyvar:(int)value;
+    @end
+
 * We've several types that wrap pointer values, such as ``SessionWrapper`` in
   ``Modules/AppKit``. Should add a function for creating these types, 
   possibly exposed to C code.
 
 See also `Pickle support`.
 
-``-copy``
-.........
-
-There are issues with implementing ``-copy`` in python, these need to be fixed.
-
-Specifically, overriding an existing ``-copy`` implementation does not work 
-unless ``__slots__ == ()``
-
-
 Known issues
 ............
 
 final step of the tutorial. It isn't at the moment because additional cruft in
 the example.
 
-* dictionary.py
-  Should be a unittest, and should be added to the (non-existing) manual
+* dictionary.py and subclassing-objective-c.py
+  These are doctests and should be moved to the documentation (with a hook
+  in the unittests for making sure the code keeps working).
 
 * pydict-to-objcdict.py
   Move to unittests
 
-* subclassing-objective-c.py
-  Move to documentation (unittest?)
-
 * super-call.py
   Move to documentation  (unittest?)
 
 a regular basis, we should check if using freelists would speed this up. See
 also `Performance tuning/testing`.
 
+NOTE: first add performance tests then experiment with freelists.
+
 Links to Apple documentation
 ............................
 
 * Use 'WrapperGenerator.py', probably need to create a custom build action
   for that.
 
-Unique proxies for Python objects
-.................................
-
-Some Cocoa/CoreFoundation API's basically require that ``a[0] is a[0]``. The
-container wrappers contain support for that, but we should try to move that
-into the generic core: there should be at most one Objective-C proxy object
-alive for every Python object (just like there's at most one Python proxy for
-every Objective-C object).
-
 NSSet vs set
 ............
 
 :copyright: 2003-2005 The PyObjC Project -->
 <h2>Contents</h2>
 <ul>
-<li><a href="#preface" id="id5" name="id5">Preface</a></li>
-<li><a href="#objective-c-for-pyobjc-users" id="id6" name="id6">Objective-C for PyObjC users</a></li>
-<li><a href="#overview-of-the-bridge" id="id7" name="id7">Overview of the bridge</a><ul>
-<li><a href="#classes" id="id8" name="id8">Classes</a></li>
-<li><a href="#messages-and-functions" id="id9" name="id9">Messages and Functions</a></li>
-<li><a href="#reference-counting" id="id10" name="id10">Reference counting</a></li>
-<li><a href="#informal-protocols" id="id11" name="id11">(Informal) protocols</a></li>
-<li><a href="#cocoa-bindings" id="id12" name="id12">Cocoa Bindings</a></li>
-<li><a href="#categories" id="id13" name="id13">Categories</a></li>
+<li><a href="#preface" id="id6" name="id6">Preface</a></li>
+<li><a href="#objective-c-for-pyobjc-users" id="id7" name="id7">Objective-C for PyObjC users</a></li>
+<li><a href="#overview-of-the-bridge" id="id8" name="id8">Overview of the bridge</a><ul>
+<li><a href="#classes" id="id9" name="id9">Classes</a></li>
+<li><a href="#messages-and-functions" id="id10" name="id10">Messages and Functions</a></li>
+<li><a href="#reference-counting" id="id11" name="id11">Reference counting</a></li>
+<li><a href="#informal-protocols" id="id12" name="id12">(Informal) protocols</a></li>
+<li><a href="#cocoa-bindings" id="id13" name="id13">Cocoa Bindings</a></li>
+<li><a href="#categories" id="id14" name="id14">Categories</a></li>
 </ul>
 </li>
-<li><a href="#cocoa-for-python-programmers" id="id14" name="id14">Cocoa for Python programmers</a></li>
-<li><a href="#notes-on-specific-tasks" id="id15" name="id15">Notes on specific tasks</a><ul>
-<li><a href="#working-with-threads" id="id16" name="id16">Working with threads</a></li>
-<li><a href="#finalizers" id="id17" name="id17">Finalizers</a></li>
+<li><a href="#cocoa-for-python-programmers" id="id15" name="id15">Cocoa for Python programmers</a></li>
+<li><a href="#notes-on-specific-tasks" id="id16" name="id16">Notes on specific tasks</a><ul>
+<li><a href="#working-with-threads" id="id17" name="id17">Working with threads</a></li>
+<li><a href="#finalizers" id="id18" name="id18">Finalizers</a></li>
+<li><a href="#copying" id="id19" name="id19">Copying</a></li>
 </ul>
 </li>
-<li><a href="#building-applications" id="id18" name="id18">Building applications</a><ul>
-<li><a href="#py2app-setup-py" id="id19" name="id19">&quot;py2app&quot; :  setup.py</a></li>
-<li><a href="#ide-approach-xcode" id="id20" name="id20">&quot;IDE approach&quot; : Xcode</a></li>
+<li><a href="#building-applications" id="id20" name="id20">Building applications</a><ul>
+<li><a href="#py2app-setup-py" id="id21" name="id21">&quot;py2app&quot; :  setup.py</a></li>
+<li><a href="#ide-approach-xcode" id="id22" name="id22">&quot;IDE approach&quot; : Xcode</a></li>
 </ul>
 </li>
 </ul>
-<h2><a href="#id5" name="preface">Preface</a></h2>
+<h2><a href="#id6" name="preface">Preface</a></h2>
 <p>PyObjC is a bridge between Python and Objective-C.  It allows you to write 
 Python scripts that use and extend existing Objective-C class libraries, 
 most importantly the <a href="http://developer.apple.com/referencelibrary/API_Fundamentals/Cocoa-api-date.html">Cocoa libraries</a> by <a href="http://www.apple.com/">Apple</a>.</p>
 <p>This document describes how to use Objective-C class libraries from Python
 scripts and how to interpret the documentation of those libraries from the 
 point of view of a Python programmer.</p>
-<h2><a href="#id6" name="objective-c-for-pyobjc-users">Objective-C for PyObjC users</a></h2>
+<h2><a href="#id7" name="objective-c-for-pyobjc-users">Objective-C for PyObjC users</a></h2>
 <p>It is recommended that you take the time to understand a little bit about
 Objective-C before jumping into PyObjC development.  The class libraries
 that you will be using from Cocoa are not documented in Python, and their
 <ul>
 <li><a href="http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC/index.html">The Objective-C Programming Language</a> at <a href="http://www.apple.com/">Apple</a>.</li>
 </ul>
-<h2><a href="#id7" name="overview-of-the-bridge">Overview of the bridge</a></h2>
-<h3><a href="#id8" name="classes">Classes</a></h3>
+<h2><a href="#id8" name="overview-of-the-bridge">Overview of the bridge</a></h2>
+<h3><a href="#id9" name="classes">Classes</a></h3>
 <p>Objective-C classes are visible as (new-style) Python classes and can be 
 subclassed just like normal Python classes.  All the usual introspection
 mechanisms work as well, as do <code><span>__slots__</span></code> and descriptors.  The major 
 initializer (typically starts with <code><span>init</span></code>).  Some classes have class methods
 which perform this behind the scenes, especially classes that create cached,
 immutable, or singleton instances.</p>
-<h3><a href="#id9" name="messages-and-functions">Messages and Functions</a></h3>
+<h3><a href="#id10" name="messages-and-functions">Messages and Functions</a></h3>
 <p>Objective-C methods are bridged to Python methods.  Because Objective-C
 message dispatch syntax can not be translated directly to Python, a few
 simple translations must take place.  The rules for these translations are:</p>
 
         someMethod_ = objc.selector(someMethod_, ...)
 </pre>
-<h3><a href="#id10" name="reference-counting">Reference counting</a></h3>
+<h3><a href="#id11" name="reference-counting">Reference counting</a></h3>
 <p>The <a href="http://developer.apple.com/referencelibrary/API_Fundamentals/Cocoa-api-date.html">Cocoa libraries</a>, and most (if not all) other class libraries for 
 Objective-C use explicit reference counting to manage memory. The methods
 <code><span>retain</span></code>, <code><span>release</span></code> and <code><span>autorelease</span></code> are used to manage these 
 subclasses of <code><span>NSObject</span></code> to represent the nodes in the outline view.</p>
 <p>Another gotcha is that <code><span>obj.setDelegate_()</span></code> often does <i>not</i> retain the
 delegate, so a reference should be maintained elsewhere.</p>
-<h3><a href="#id11" name="informal-protocols">(Informal) protocols</a></h3>
+<h3><a href="#id12" name="informal-protocols">(Informal) protocols</a></h3>
 <p>Cocoa defines a number of formal and informal protocols that specify methods
 that should be implemented by a class if it is to be used in a specific role,
 such as the data source for an <code><span>NSTableView</span></code>.</p>
 <p>PyObjC will automatically use the information in the <code><span>informal_protocol</span></code> 
 objects to add the right method signatures to methods, and to warn about
 classes that partially implement a protocol.</p>
-<h3><a href="#id12" name="cocoa-bindings">Cocoa Bindings</a></h3>
+<p>See <a href="protocols.html">PyObjC protocol support</a> for more information.</p>
+<h3><a href="#id13" name="cocoa-bindings">Cocoa Bindings</a></h3>
 <p>In Mac OS X 10.3 Apple introduced <a href="http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaBindings/">Cocoa Bindings</a>, a method to make it easier
 to create and use <i>Controller</i> objects using <a href="http://developer.apple.com/documentation/Cocoa/Conceptual/KeyValueObserving/">Key-Value Observing</a> and <a href="http://developer.apple.com/documentation/Cocoa/Conceptual/KeyValueCoding/">Key-Value
 Coding</a>.  In order to create accessors compatible with this, you
 must use <code><span>objc.accessor</span></code> to create an appropriate selector descriptor.</p>
-<h3><a href="#id13" name="categories">Categories</a></h3>
+<h3><a href="#id14" name="categories">Categories</a></h3>
 <p>Objective-C has a mechanism for modularize a class definition, it is possible
 to add methods to an existing class in a separate compilation unit and even
 a separate library. This mechanism is named categories and is used to enhance
 <p>To make it clear that <code><span>objc.Category</span></code> performs a special task the name in
 the class definition must be the same as the <code><span>__name__</span></code> of the argument
 to <code><span>objc.Category</span></code>.</p>
-<h2><a href="#id14" name="cocoa-for-python-programmers">Cocoa for Python programmers</a></h2>
+<h2><a href="#id15" name="cocoa-for-python-programmers">Cocoa for Python programmers</a></h2>
 <p>Cocoa frameworks are mapped onto Python packages with the same name; that is
 the classes, constants and functions from the AppKit framework are available
 after you import <code><span>AppKit</span></code> in your Python script.</p>
 <li><a href="http://www.stepwise.com/">stepwise.com</a></li>
 <li>Your local bookstore or library</li>
 </ul>
-<h2><a href="#id15" name="notes-on-specific-tasks">Notes on specific tasks</a></h2>
-<h3><a href="#id16" name="working-with-threads">Working with threads</a></h3>
+<h2><a href="#id16" name="notes-on-specific-tasks">Notes on specific tasks</a></h2>
+<h3><a href="#id17" name="working-with-threads">Working with threads</a></h3>
 <p>When you create a thread and want to use PyObjC from that thread you will
 have to create an <code><span>NSAutoreleasePool</span></code> in that thread and clean it up when
 you're done. The easiest way to that is to create an instance of that class
 bound to a local variable. If the thread is long-lived you may want to arrange
 for recycling the pool once in a while.</p>
-<h3><a href="#id17" name="finalizers">Finalizers</a></h3>
+<h3><a href="#id18" name="finalizers">Finalizers</a></h3>
 <p>In Python you can use the method <code><span>__del__</span></code> to clean up resources when your
 object is garbage collected. In Objective-C/Cocoa this is done with a method 
 named <code><span>dealloc</span></code>.</p>
 <p>In PyObjC you should always use the <code><span>__del__</span></code> method, the <code><span>dealloc</span></code> method
 can safely be ignored and the bridge will complain when you try to override
 this method.</p>
-<h2><a href="#id18" name="building-applications">Building applications</a></h2>
+<h3><a href="#id19" name="copying">Copying</a></h3>
+<p>It is possible to implement the <code><span>NSCopying</span></code> protocol in your classes. Some
+care must be taken when you inherit from a class that already implements 
+that protocol.</p>
+<p>Some classes copy the template object manually, you'll have to copy your 
+own fields manually in that case. Other classes use a convenience function
+that creates the copy. In that case you wont have to copy your own fields.
+However, the fields in the copy will rever to the same objects as the 
+fields in the original (that is, the copy will share some state with the
+original). This is no problem when the fields rever to immutable values (such
+as integers), but is probably not what you want when the fields rever to
+mutable values (such as lists).</p>
+<p>NOTE: PyObjC might introduce a helper class when you inherit from a class
+that implements <code><span>NSCopying</span></code>. You should not rely on the existance of this
+class.</p>
+<p>NOTE2: You shouldn't assign to <code><span>SomeClass.copyWithZone_</span></code> unless that class
+already implements <code><span>copyWithZone:</span></code>. If you do you may end up with seemingly
+random memory coruption.</p>
+<h2><a href="#id20" name="building-applications">Building applications</a></h2>
 <p>There are two different ways to build applications with PyObjC. py2app
 should be the preferred method, however using the Xcode template can
 be convenient for development.</p>
-<h3><a href="#id19" name="py2app-setup-py">&quot;py2app&quot; :  setup.py</a></h3>
+<h3><a href="#id21" name="py2app-setup-py">&quot;py2app&quot; :  setup.py</a></h3>
 <p>The PyObjC installer includes a copy of the <code><span>py2app</span></code> package. This package
 offers a way to build distutils scripts for building (standalone)
 applications and plugin bundles.</p>
 <pre>
 python setup.py py2app --help
 </pre>
-<h3><a href="#id20" name="ide-approach-xcode">&quot;IDE approach&quot; : Xcode</a></h3>
+<h3><a href="#id22" name="ide-approach-xcode">&quot;IDE approach&quot; : Xcode</a></h3>
 <p>PyObjC includes a number of Xcode templates that can be used to 
 develop applications. Those templates are used like any other
 Xcode template. The only non-obvious detail is that you have to
 can safely be ignored and the bridge will complain when you try to override
 this method.
 
+Copying
+.......
+
+It is possible to implement the ``NSCopying`` protocol in your classes. Some
+care must be taken when you inherit from a class that already implements 
+that protocol. 
+
+Some classes copy the template object manually, you'll have to copy your 
+own fields manually in that case. Other classes use a convenience function
+that creates the copy. In that case you wont have to copy your own fields.
+However, the fields in the copy will rever to the same objects as the 
+fields in the original (that is, the copy will share some state with the
+original). This is no problem when the fields rever to immutable values (such
+as integers), but is probably not what you want when the fields rever to
+mutable values (such as lists).
+
+NOTE: PyObjC might introduce a helper class when you inherit from a class
+that implements ``NSCopying``. You should not rely on the existance of this
+class.
+
+NOTE2: You shouldn't assign to ``SomeClass.copyWithZone_`` unless that class
+already implements ``copyWithZone:``. If you do you may end up with seemingly
+random memory coruption.
+
 Building applications
 ---------------------
 

Lib/Foundation/test/test_globals.py

             self.assert_("This is a test" in data)
 
     def testLoggingWithFormattingChars(self):
+        # XXX: This is wrong, we should expand the %-escapes ourselves!
         self.startCaptureStderr()
         try:
             Foundation.NSLog("This is a test %@")

Lib/Foundation/test/test_nsstring.py

             raise
 
 
-            
+    def testGetCString(self):
+        # Custom wrappers
+        v = NSString.stringWithString_(u"hello world")
+        
+        self.assertEquals(v, u"hello world")
+
+        x = v.getCString_maxLength_(16)
+        self.assertEquals(x, u"hello world")
+
+        self.assertRaises(objc.error, v.getCString_maxLength_, 4)
+
+        x, l = v.getCString_maxLength_range_remainingRange_(4, (1, 4))
+        self.assertEquals(x, "ello")
+        self.assertEquals(l.location, 5)
+        self.assertEquals(l.length, 0)
 
 
 class TestNSStringBridging(unittest.TestCase):
         v = pickle.loads(s)
         self.assertEquals(type(v), types.UnicodeType)
 
+
+
 if __name__ == '__main__':
     unittest.main()

Lib/objc/test/test_copying.py

+import unittest
+import objc
+
+NSObject = objc.lookUpClass("NSObject")
+NSAutoreleasePool = objc.lookUpClass("NSAutoreleasePool")
+from objc.test.copying import OC_CopyHelper, OC_CopyBase
+
+class OC_TestCopy1 (NSObject):
+    def init(self):
+        self = super(OC_TestCopy1, self).init()
+        if self is not None:
+            self.x = 1
+            self.y = 2
+        return self
+
+    def modify(self):
+        self.x = 42
+        self.y = 24
+        self.z = 0
+
+    def copyWithZone_(self, zone):
+        other = OC_TestCopy1.allocWithZone_(zone).init()
+        other.x = self.x
+        other.y = self.y
+        return other
+    # Argh, copyWithZone_ is a classmethod by default unless the
+    # superclass implements  -copyWithZone:
+    copyWithZone_ = objc.selector(copyWithZone_, 
+            signature=NSObject.copyWithZone_.signature, 
+            isClassMethod=False)
+
+class OC_TestCopy2 (OC_CopyBase):
+    def init(self):
+        self = super(OC_TestCopy2, self).initWithInt_(10)
+        if self is not None:
+            self.x = 1
+            self.y = 2
+        return self
+
+    def modify(self):
+        self.setIntVal_(40)
+        self.x = 42
+        self.y = 24
+        self.z = 0
+
+class OC_TestCopy3 (OC_CopyBase):
+    __slots__ = 'x y'.split()
+
+    def init(self):
+        self = super(OC_TestCopy3, self).initWithInt_(10)
+        if self is not None:
+            self.x = 1
+            self.y = 2
+        return self
+
+    def modify(self):
+        self.setIntVal_(40)
+        self.x = 42
+        self.y = 24
+
+class OC_TestCopy4 (OC_CopyBase):
+    def init(self):
+        self = super(OC_TestCopy4, self).initWithInt_(10)
+        if self is not None:
+            self.x = 1
+            self.y = 2
+        return self
+
+    def modify(self):
+        self.setIntVal_(40)
+        self.x = 42
+        self.y = 24
+        self.z = 0
+
+    def copyWithZone_(self, zone):
+        other = super(OC_TestCopy4, self).copyWithZone_(zone)
+        other.x = self.x
+        other.y = self.y
+        other.z = "hello"
+        return other
+
+class TestNSCopying (unittest.TestCase):
+    def testCopyingWithoutSuperFromObjC(self):
+        self.assert_(not OC_TestCopy1.copyWithZone_.isClassMethod)
+
+        p = NSAutoreleasePool.alloc().init()
+        o = OC_CopyHelper.doCopySetup_(OC_TestCopy1)
+        del p
+
+        self.assertEquals(o.x, 42)
+        self.assertEquals(o.y, 24)
+        self.assertRaises(AttributeError, getattr, o, 'z')
+
+    def testCopyingWithSuperFromObjC(self):
+        self.assert_(not OC_CopyBase.copyWithZone_.isClassMethod)
+        self.assert_(not OC_TestCopy2.copyWithZone_.isClassMethod)
+        self.assert_(not OC_TestCopy3.copyWithZone_.isClassMethod)
+        self.assert_(not OC_TestCopy4.copyWithZone_.isClassMethod)
+
+        p = NSAutoreleasePool.alloc().init()
+        o = OC_CopyHelper.doCopySetup_(OC_TestCopy2)
+        del p
+
+        self.assertEquals(o.x, 42)
+        self.assertEquals(o.y, 24)
+        self.assertEquals(o.intVal(), 40)
+
+        p = NSAutoreleasePool.alloc().init()
+        o = OC_CopyHelper.doCopySetup_(OC_TestCopy3)
+        del p
+
+        self.assertEquals(o.x, 42)
+        self.assertEquals(o.y, 24)
+        self.assertEquals(o.intVal(), 40)
+
+        p = NSAutoreleasePool.alloc().init()
+        o = OC_CopyHelper.doCopySetup_(OC_TestCopy4)
+        del p
+
+        self.assertEquals(o.x, 42)
+        self.assertEquals(o.y, 24)
+        self.assertEquals(o.z, "hello")
+        self.assertEquals(o.intVal(), 40)
+
+    def testCopyingWithoutSuper(self):
+        self.assert_(not OC_TestCopy1.copyWithZone_.isClassMethod)
+
+        v = OC_TestCopy1.alloc().init()
+        v.modify()
+
+        p = NSAutoreleasePool.alloc().init()
+        o = v.copy()
+        v.x = 20
+        del v
+        del p
+
+        self.assertEquals(o.x, 42)
+        self.assertEquals(o.y, 24)
+        self.assertRaises(AttributeError, getattr, o, 'z')
+
+    def testCopyingWithSuper(self):
+
+        self.assert_(not OC_CopyBase.copyWithZone_.isClassMethod)
+        self.assert_(not OC_TestCopy2.copyWithZone_.isClassMethod)
+        self.assert_(not OC_TestCopy3.copyWithZone_.isClassMethod)
+        self.assert_(not OC_TestCopy4.copyWithZone_.isClassMethod)
+
+        p = NSAutoreleasePool.alloc().init()
+        v = OC_TestCopy2.alloc().init()
+        v.modify()
+
+        o = v.copy()
+        v.x = 20
+        del v
+        del p
+
+        self.assertEquals(o.x, 42)
+        self.assertEquals(o.y, 24)
+        self.assertEquals(o.intVal(), 40)
+
+        p = NSAutoreleasePool.alloc().init()
+        v = OC_TestCopy3.alloc().init()
+        v.modify()
+
+        o = v.copy()
+        v.x = 20
+        del v
+        del p
+
+        self.assertEquals(o.x, 42)
+        self.assertEquals(o.y, 24)
+        self.assertEquals(o.intVal(), 40)
+
+        p = NSAutoreleasePool.alloc().init()
+        v = OC_TestCopy4.alloc().init()
+        v.modify()
+
+        o = v.copy()
+        v.x = 20
+        del v
+        del p
+
+        self.assertEquals(o.z, "hello")
+        self.assertEquals(o.y, 24)
+        self.assertEquals(o.x, 42)
+        self.assertEquals(o.intVal(), 40)
+
+if __name__ == "__main__":
+    unittest.main()

Modules/objc/class-builder.m

 		void** args,
 		void* userarg);
 
+static char copyWithZone_signature[132] = { '\0' };
+static void object_method_copyWithZone_(
+		ffi_cif* cif __attribute__((__unused__)),
+		void* resp,
+		void** args,
+		void* userdata);
+
 /*
  * When we create a 'Class' we actually create the struct below. This allows
  * us to add some extra information to the class defintion.
 	return 0;
 }
 
+static Class
+build_intermediate_class(Class base_class, char* name)
+{
+	Class intermediate_class = nil;
+	Class meta_class = nil;
+	Class root_class;
+	int i;
+	struct objc_method_list* method_list = NULL;
+	PyObjCRT_Method_t meth;
+	IMP closure;
+	PyObjCMethodSignature* methinfo;
+
+	method_list = PyObjCRT_AllocMethodList(1);
+
+	if (method_list == NULL) {
+		PyErr_NoMemory();
+		goto error_cleanup;
+	}
+
+	if (copyWithZone_signature[0] == '\0') {
+		snprintf(copyWithZone_signature,
+			sizeof(copyWithZone_signature),
+			"@@:%s", @encode(NSZone*));
+	}
+
+	method_list->method_count = 0;
+	methinfo = PyObjCMethodSignature_FromSignature(copyWithZone_signature);
+	if (methinfo == NULL) goto error_cleanup; 
+	closure = PyObjCFFI_MakeClosure(methinfo, object_method_copyWithZone_,
+		base_class);
+	PyObjCMethodSignature_Free(methinfo); methinfo = NULL;
+	if (closure == NULL) goto error_cleanup;
+	meth = method_list->method_list + method_list->method_count++;
+
+	PyObjCRT_InitMethod(meth, @selector(copyWithZone:), 
+			copyWithZone_signature, (IMP)closure); \
+
+	root_class = base_class;
+	while (root_class->super_class != NULL) {
+		root_class = root_class->super_class;
+	}
+
+	intermediate_class = malloc(sizeof(struct objc_class));
+	if (intermediate_class == NULL) {
+		PyErr_NoMemory();
+		goto error_cleanup;
+	}
+
+	meta_class = malloc(sizeof(struct objc_class));
+	if (meta_class == NULL) {
+		PyErr_NoMemory();
+		goto error_cleanup;
+	}
+
+	i = PyObjCRT_SetupClass(
+		intermediate_class, 
+		meta_class, 
+		name,
+		base_class,
+		root_class,
+		base_class->instance_size, NULL,
+		NULL
+		);
+	if (i < 0) {
+		goto error_cleanup;
+	}
+
+	if (method_list) {
+		PyObjCRT_ClassAddMethodList(
+			intermediate_class,
+			method_list);
+		method_list = NULL;
+	}
+
+	objc_addClass(intermediate_class);
+
+	return intermediate_class;
+
+error_cleanup:
+	if (intermediate_class) free(intermediate_class);
+	if (meta_class) free(meta_class);
+	if (method_list) {
+		free(method_list);
+	}
+	if (methinfo) {
+		PyObjCMethodSignature_Free(methinfo);
+	}
+
+	return NULL;
+}
+
+
+
 /*
  * First step of creating a python subclass of an objective-C class
  *
 	char**                   curname;
 	PyObject*                py_superclass = NULL;
 	int                      item_size;
+	int			 have_intermediate = 0;
 
 	if (!PyList_Check(protocols)) {
 		PyErr_Format(PyObjCExc_InternalError,  
 	py_superclass = PyObjCClass_New(super_class);
 	if (py_superclass == NULL) return NULL;
 
+	/* We must override copyWithZone: for python classes because the
+	 * refcounts of python slots might be off otherwise. Yet it should
+	 * be possible to override copyWithZone: in those classes. 
+	 *
+	 * The solution: introduce an intermediate class that contains our
+	 * implementation of copyWithZone:. This intermediate class is only
+	 * needed when (1) the superclass implements copyWithZone: and (2)
+	 * the python subclass overrides that method.
+	 *
+	 * FIXME: Better code to look for copyWithZone: in the class dict
+	 */
+	if (PyDict_GetItemString(class_dict, "copyWithZone_") == NULL) {
+		PyErr_Clear();
+		i = 0;
+	} else {
+		i = 1;
+	}
+
+	if (i && !PyObjCClass_HasPythonImplementation(py_superclass) 
+          && [super_class instancesRespondToSelector:@selector(copyWithZone:)]){
+		Class intermediate_class;
+		char  buf[1024];
+
+		have_intermediate = 1;
+
+		snprintf(buf, 1024, "_PyObjCCopying_%s", super_class->name);
+		intermediate_class = objc_lookUpClass(buf);
+		if (intermediate_class == NULL) {
+			intermediate_class = build_intermediate_class(
+					super_class, buf);
+			if (intermediate_class == NULL) goto error_cleanup;
+		}
+
+		super_class = intermediate_class;
+		py_superclass = PyObjCClass_New(super_class);
+		if (py_superclass == NULL) return NULL;
+	}
+
+
 	if (do_slots(py_superclass, class_dict) < 0) {
 		goto error_cleanup;
 	}
 
 		ivar_count        += 0;
 		meta_method_count += 0; 
-		method_count      += 8;
+		method_count      += 9;
 	}
 
 	/* Allocate the class as soon as possible, for new selector objects */
 			if (methinfo == NULL) goto error_cleanup; \
 			closure = PyObjCFFI_MakeClosure(methinfo, imp, \
 					super_class); \
-			PyObjCMethodSignature_Free(methinfo); \
+			PyObjCMethodSignature_Free(methinfo); methinfo = NULL; \
 			if (closure == NULL) goto error_cleanup; \
 			meth = method_list->method_list + 		\
 				method_list->method_count++;		\
 			@selector(setValue:forKey:),
 			"v@:@@",
 			object_method_takeValue_forKey_);
+
+		if (!have_intermediate && [super_class instancesRespondToSelector:@selector(copyWithZone:)]) {
+			if (copyWithZone_signature[0] == '\0') {
+				snprintf(copyWithZone_signature,
+					sizeof(copyWithZone_signature),
+					"@@:%s", @encode(NSZone*));
+			}
+
+			METH(
+				"copyWithZone_",
+				@selector(copyWithZone:),
+				copyWithZone_signature,
+				object_method_copyWithZone_);
+		}
 #undef		METH
 	}
 
 			/* XXX: Add alignment! */
 
 			if (((PyObjCInstanceVariable*)value)->isSlot) {
-				/*
-				  XXX: Use @encode(PyObject**)?
-				       Why is this not (PyObject*)?
-				*/
-				var->ivar_type = "^v";
-				item_size = sizeof(PyObject**);
+				var->ivar_type = @encode(PyObject*);
+				item_size = sizeof(PyObject*);
 			} else {
 				var->ivar_type = PyObjCUtil_Strdup(((PyObjCInstanceVariable*)value)->type);
 				if (var->ivar_type == NULL) goto error_cleanup;
 			return NULL;
 		}
 		if (arg_self != ((PyObjCSelector*)pymeth)->sel_self) {
+
+			printf("self[%p]:%s sel_self[%p]:%s\n",
+				arg_self, PyObject_REPR(arg_self),
+				((PyObjCSelector*)pymeth)->sel_self,
+				PyObject_REPR(((PyObjCSelector*)pymeth)->sel_self));
+
+
 			PyErr_SetString(PyExc_TypeError,
 				"PyObjC_CallPython called with 'self' and "
 				"a method bound to another object");
 	NS_ENDHANDLER
 }
 
-#if 0
- /* This will one day be the copyWithZone: for subclasses of classes that define
-  * copyWithZone:. There's just one problem: how can we allow the user to
-  * hook into this (e.g. the user must be able to override copyWithZone:
-  * without introducing problems). 
-  *
-  * Luckily we can break existing code, that code is broken anyway :-)
-  *
-  * Why is this needed? In many cases the default copyWithZone: either doesn't
-  * copy python slots, or it copies them without updating the reference count.
-  * For __dict__ and values in __slots__ the second option is a serious 
-  * problem: there is nothing the user can do to fix this (those values are 
-  * PyObject*-s and there is no interface for changing their refcount from 
-  * Python).  The only workaround: have '__slots__ = ()' in the class (e.g.
-  * do NOT have additional instance variables).
-  */
-
 static void
 object_method_copyWithZone_(
 		ffi_cif* cif __attribute__((__unused__)),
 	id copy;
 	SEL _meth = *(SEL*)args[1];
 	NSZone* zone = *(NSZone**)args[2];
-	struct copyWithZoneData* data = (PyObject*)userdata;
+	Class cls;
 
 	struct objc_super super;
-	int r;
 	PyGILState_STATE state;
-	PyObjCRT_Ivar_t var;
 
 	/* Ask super to create a copy */
 
-	super.class = data->class;
+	super.class = (Class)userdata;
 	RECEIVER(super) = self;
 	copy = objc_msgSendSuper(&super, _meth, zone);
 
 	if (copy == nil) {
 		*(id*)resp = nil;
+		return;
 	}
 
 	state = PyGILState_Ensure();
 
-	/* Update the reference counts for slots/outlets */
+	cls = self->isa;
+	while (cls != (Class)userdata) {
+		struct objc_ivar_list* ivars = cls->ivars;
+		if (ivars != NULL) {
+			int i;
+			struct objc_ivar* v;
+			PyObject** p;
 
-	while (cls != NULL) {
-		Class     objcClass = PyObjCClass_GetClass(cls);
-		PyObject* clsDict; 
-		PyObject* clsValues;
-		PyObject* o;
-		int       len, i;
+			for (i = 0; i < ivars->ivar_count; i++) {
+				v = ivars->ivar_list + i;
+				if (strcmp(v->ivar_type, @encode(PyObject*))!=0)
+					continue;
 
-		if (objcClass == nil) break;
+				/* A PyObject, increase it's refcount */
+				p = (PyObject**)(((char*)copy)+v->ivar_offset);
+				if (*p == NULL) continue;
 
-		clsDict = PyObject_GetAttrString(cls, "__dict__");
-		if (clsDict == NULL) {
-			PyErr_Clear();
-			break;
-		}
-		
-		/* Class.__dict__ is a dictproxy, which is not a dict and
-		 * therefore PyDict_Values doesn't work.
-		 */
-		clsValues = PyObject_CallMethod(clsDict, "values", NULL);
-		Py_DECREF(clsDict);
-		if (clsValues == NULL) {
-			PyErr_Clear();
-			break;
+				if (strcmp(v->ivar_name, "__dict__") == 0) {
+					/* copy __dict__ */
+					*p = PyDict_Copy(*p);
+					if (*p == NULL) {
+						[copy release];
+						PyObjCErr_ToObjCWithGILState(
+								&state);
+						return;
+					}
+				} else {
+					Py_INCREF(*p);
+				}
+			}
+			
 		}
 
-		len = PyList_Size(clsValues);
-		/* Check type */
-		for (i = 0; i < len; i++) {
-			PyObjCInstanceVariable* iv;
-
-			o = PyList_GET_ITEM(clsValues, i);
-
-			if (o == NULL) continue;
-			if (!PyObjCInstanceVariable_Check(o)) continue;
-		
-			iv = ((PyObjCInstanceVariable*)o);
-
-			if (strcmp(iv->type, "@") != 0) continue;
-			if (iv->isOutlet) continue;
-
-			var = class_getInstanceVariable(objcClass, iv->name);
-			if (var == NULL) continue;
-
-			if (iv->isSlot) {
-				Py_XINCREF(*(PyObject**)(((char*)self) + 
-					var->ivar_offset));
-				*(PyObject**)(((char*)copy) + var->ivar_offset) =
-					*(PyObject**)(((char*)self) + var->ivar_offset);
-			} else {
-				[*(id*)(((char*)self) + var->ivar_offset) retain];
-				*(id*)(((char*)copy) + var->ivar_offset) = *(id*)(((char*)self) + var->ivar_offset);
-			}
-		}
-
-		Py_DECREF(clsValues);
-
-		o = PyObject_GetAttrString(cls, "__bases__");
-		if (o == NULL) {
-			PyErr_Clear();
-			cls = NULL;
-		}  else if (PyTuple_Size(o) == 0) {
-			PyErr_Clear();
-			cls = NULL;
-			Py_DECREF(o);
-		} else {
-			cls = PyTuple_GET_ITEM(o, 0);
-			if (cls == (PyObject*)&PyObjCClass_Type) {
-				cls = NULL;
-			}
-			Py_DECREF(o);
-		}
+		cls = cls->super_class;
 	}
 
-	/* And at the end copy the dict */
-	var = class_getInstanceVariable(PyObjCClass_GetClass(cls), "__dict__");
-	if (var != NULL) {
-		*(PyObject**)(((char*)copy) + var->ivar_offset) = 
-			PyDict_Copy(
-			    *(PyObject**)(((char*)self) + var->ivar_offset));
-
-		if (*(PyObject**)(((char*)copy) + var->ivar_offset) == NULL) {
-			[copy release];
-			*(id*)resp = nil;
-			PyObjCErr_ToObjCWithGILState(&state);
-			return;
-		}
-	}
-	
 	PyGILState_Release(state);
 	*(id*)resp = copy;
 }
-
-#endif

Modules/objc/objc-class.m

 		return NULL;
 	}
 
-#if 0
-	/* Use test in class-builder.m, that one is more useful */
-	if (PyObjCRT_LookUpClass(name) != NULL) {
-		PyErr_SetString(PyObjCExc_Error, 
-			"Class already exists in Objective-C runtime");
-		return NULL;
-	}
-#endif
-
 	if (!PyTuple_Check(bases)) {
 		PyErr_SetString(PyExc_TypeError, "'bases' must be tuple");
 		return NULL;
 		}
 	}
 
-	v = PyList_AsTuple(real_bases);
-	if (v == NULL) {
-		Py_DECREF(protocols);
-		Py_DECREF(real_bases);
-		return NULL;
-	}
-	Py_DECREF(real_bases);
-	real_bases = v;
 
 	/* First generate the objective-C class. This may change the
 	 * class dict.
 		return NULL;
 	}
 
+	/* PyObjCClass_BuildClass may have changed the super_class */
+	super_class = objc_class->super_class;
+	py_super_class = PyObjCClass_New(super_class);
+	if (py_super_class == NULL) {
+		PyObjCClass_UnbuildClass(objc_class);
+		Py_DECREF(protocols);
+		Py_DECREF(real_bases);
+		return NULL;
+	} else {
+		PyObjCClass_CheckMethodList(py_super_class, 1);
+	}
+
+	Py_INCREF(py_super_class);
+	Py_DECREF(PyList_GET_ITEM(real_bases, 0));
+	PyList_SET_ITEM(real_bases, 0, py_super_class);
+
+	v = PyList_AsTuple(real_bases);
+	if (v == NULL) {
+		PyObjCClass_UnbuildClass(objc_class);
+		Py_DECREF(protocols);
+		Py_DECREF(real_bases);
+		return NULL;
+	}
+	Py_DECREF(real_bases);
+	real_bases = v;
+
 	/* Verify that the class conforms to all protocols it claims to 
 	 * conform to.
 	 */

Modules/objc/test/copying.m

+/*
+ * This module is used in the unittests for object identity.
+ */
+#include "Python.h"
+#include "pyobjc-api.h"
+
+#import <Foundation/Foundation.h>
+
+@interface NSObject (OC_CopyHelper)
+-(void)modify;
+@end
+
+@interface OC_CopyHelper : NSObject
+{ }
++(NSObject*)doCopySetup:(Class)aClass;
+@end
+
+@implementation OC_CopyHelper
++(NSObject*)doCopySetup:(Class)aClass
+{
+	NSObject<NSCopying>* tmp;
+	NSObject* retval;
+
+	tmp = (NSObject*)[[aClass alloc] init];
+	[tmp modify];
+
+	retval = [tmp copyWithZone:nil];
+	[tmp release];
+	return retval;
+}
+@end
+
+@interface OC_CopyBase : NSObject <NSCopying>
+{
+	int intVal;
+}
+-init;
+-initWithInt:(int)intVal;
+-(int)intVal;
+-(void)setIntVal:(int)val;
+-copyWithZone:(NSZone*)zone;
+@end
+
+@implementation OC_CopyBase
+-init
+{
+	return [self initWithInt:0];
+}
+
+-initWithInt:(int)value
+{
+	self = [super init];
+	if (self == nil) return nil;
+
+	intVal = value;
+	return self;
+}
+
+-(int)intVal
+{
+	return intVal;
+}
+
+-(void)setIntVal:(int)val
+{
+	intVal = val;
+}
+
+-copyWithZone:(NSZone*)zone
+{
+	return NSCopyObject(self, 0, zone);
+}
+@end
+
+
+static PyMethodDef copying_methods[] = {
+	{ 0, 0, 0, 0 }
+};
+
+void initcopying(void);
+void initcopying(void)
+{
+	PyObject* m;
+
+	m = Py_InitModule4("copying", copying_methods, 
+			NULL, NULL, PYTHON_API_VERSION);
+
+	PyObjC_ImportAPI(m);
+	PyModule_AddObject(m, "OC_CopyHelper",
+		PyObjCClass_New([OC_CopyHelper class]));
+	PyModule_AddObject(m, "OC_CopyBase",
+		PyObjCClass_New([OC_CopyBase class]));
+}
 <p>An overview of the relevant changes in new, and older, releases.</p>
 <h2><a name="version-1-3-2005-03">Version 1.3 (2005-03-??)</a></h2>
 <ul>
+<li>The bridge now maintains object identity across the bridge
+in both directions. Previous versions of the bridge only did this when
+bridging from Objective-C to Python.<p>Exceptions: NSString and NSNumber do not have unique proxies. NSString
+never will have. Python numbers and strings are converted, not proxied and
+therefore also don't get unique proxies.</p>
+<p>And finally, any python object that is proxied using the <code><span>__pyobjc_object__</span></code>
+interface will only get a unique proxy if the <code><span>__pyobjc_object__</span></code> method
+implements that feature.</p>
+</li>
 <li>(UNFINISHED) New RemotePyInterpreter example that demonstrates an
 out-of-process Python interpreter (primarily for IDE uses).</li>
 <li>New <code><span>objc.protocolsForClass</span></code> function that returns a list of protocols
     # implementation
     pass
 </pre>
+<p>It is also possible to define new protocols:</p>
+<pre>
+MyProtocol = objc.formal_protocol(&quot;MyProtocol&quot;, None, [
+   selector(None, selector='mymethod', signature='v@:'),
+])
+</pre>
+<p>All formal protocols are instances of <code><span>objc.formal_protocol</span></code>.</p>
 </li>
 <li>PyObjCTools.KeyValueCoding has a new <code><span>kvc</span></code> class that allows
 Pythonic Key-Value Coding.<ul>
 as the wrapped object.</p>
 </li>
 <li><code><span>NSNumber</span></code> instances are bridged to a <code><span>float</span></code>, <code><span>long</span></code>, or <code><span>int</span></code>
-subclass that uses <code><span>__pyobjc_object__</span></code>.  <code><span>NSDecimalNumber</span></code> is bridged
-to <code><span>Foundation.NSDecimal</span></code>, which now supports <code><span>__pyobjc_object__</span></code>.
-This eliminates a HUGE amount of cruft in <code><span>objc._conveniences</span></code>.</li>
+subclass that uses <code><span>__pyobjc_object__</span></code>.  
+<code><span>NSDecimal</span></code> is converted to <code><span>NSDecimalNumber</span></code> when used as an object,
+<code><span>NSDecimalNumber</span></code> is not bridged to <code><span>NSDecimal</span></code> because the latter is
+a mutable type.</li>
 <li>The Python to Objective-C bridge now looks for a <code><span>__pyobjc_object__</span></code> 
 attribute to get a PyObjC object from a Python object.</li>
 <li>New IDNSnitch example in Inject that demonstrates how to write an
 to be used for application or plugin development.</li>
 <li><code><span>objc.registerPlugin()</span></code> and <code><span>objc.pluginBundle()</span></code> are now deprecated
 as they are no longer useful.</li>
+<li>It is now possible to subclass a class that implements <code><span>copyWithZone:</span></code>
+without setting <code><span>__slots__</span></code> to <code><span>()</span></code>.</li>
 </ul>
 <h2><a name="version-1-2-2004-12-29">Version 1.2 (2004-12-29)</a></h2>
 <ul>
 - ``objc.registerPlugin()`` and ``objc.pluginBundle()`` are now deprecated
   as they are no longer useful.
 
+- It is now possible to subclass a class that implements ``copyWithZone:``
+  without setting ``__slots__`` to ``()``. 
+
 Version 1.2 (2004-12-29)
 ------------------------