Improve correspondence between ObjectiveC objects and Python wrappers
### What is the problem or limitation you are having?

In the process of building the Toga GUI testbed, we discovered #249. A fix for this problem was included in #246; however, that fix was really a safety catch for a specific set of circumstances. The bigger question: how did that set of circumstances happen in the first place?

At present, it is possible for an object to be disposed of by Objective C, but due to delays in propagating garbage collection, the `ObjCInstance` wrapping that object may not be immediately disposed of. This means the weak reference dictionary can contain stale objects.

#246 protected against this by protecting against the specific case where a memory address was *reused* - but if a Python object points at memory that has been disposed of and *not* reused, you'll generate a segfault. This is obviously undesirable.

### Describe the solution you'd like

Functionally - it should be impossible to generate a segfault from Python code.

An idea posited by @mhsmith in [the discussion about #249](https://github.com/beeware/rubicon-objc/issues/249#issuecomment-1399472658) was that we could maintain stronger reference to the ObjC object on the Python side. This would mean we add add a `retain` calls whenever a Python-side wrapper is created; `release`-ing only when *Python* has finished with the object. The idea here would be that it's better to have larger memory footprint (or even a small leak), than to have a segfault because a Python object has a stale memory reference.

### Describe alternatives you've considered

Do nothing. The status quo is stable(ish?), and while it, may be theoretically possible to get a stale ObjCInstance object, in practice we're not seeing that problem (after #246 landed, anyway).

### Additional context

Other than the general hesitation of fiddling with a complex area of code that *appears* to work at present - the complication to watch out for here is cyclic references between Python objects and Objective C objects that prevents Objective C from ever releasing memory. It's easy to avoid segfaults by never releasing... but eventually the memory will run out.
Foundation collection instances can be cached without their helper wrappers
### Describe the bug

When an instance of a Foundation collection class is created (e.g., NSMutableDictionary), Rubicon uses a collection class (e.g., ObjCMutableDictInstance) to ensure that Pythonic helpers such as `__setitem__` are available. 

It is also possible to create an ObjCInstance directly from an objc_id. If this happens, it may be cached as a raw ObjCInstance, and *not* have the helper methods. 

Rubicon caches object instances based on the object pointer, performing cache eviction only when the class name of the underlying object class doesn't match. However, an NSMutableDictionary created directly, and one created from an objc_id will have the same pointer, and the same underlying class name. As a result, it's possible for a recycled collection class instance to *not* have the helper methods as a result of a cache hit.



### Steps to reproduce

I haven't worked out a simple way to reproduce this programmatically.

beeware/toga-chart#191 contains an example that can reproduce the issue with reasonable reliability. Run the example app, and resize the window continuously. I can usually trigger the exception reported by that ticket within a couple of seconds.

### Expected behavior

Cached ObjC collection instances should always be returned with the appropriate wrapper, even if the memory address has previously been used by an object of the same type.

### Screenshots

_No response_

### Environment

- Operating System: macOS
- Python version: Any
- Software versions:
  - Rubicon 0.4.9+


### Logs

```

```


### Additional context

The workaround fix is to modify the conditions for a cache eviction so that we don't *just* look at the class name, but at the class instance as well. 

Even better would be to ensure that a non-wrapped instance isn't ever cached in the first place... but I'm having difficulty working out how the non-wrapped instance is being created.

Even better still would be to fix the issue with memory-based cache hits (#256).
Improve memory management documentation
Looking at old SO discussion (e.g. https://stackoverflow.com/a/6610/705086 ) it looks like when `SomeOBJCClass.alloc().init()` is called from Python code, it becomes Python's responsibility either to `.release()` the resulting object on the spot, or to mark it for GC at the bottom of event loop using `.autorelease()`.

Is that correct?

If that's correct, it must be documented...