NSProxy and Key Value Observing - objective-c

NSProxy seems to work very well as stand-in objects for those that don't yet exist. For example.
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
return [self.target methodSignatureForSelector:sel];
}
- (void)forwardInvocation:(NSInvocation *)invocation {
[invocation invokeWithTarget:self.target];
}
The above code will transparently pass any method invocation to the target that the proxy represents. However, it doesn't seem to handle KVO observations and notifications on the target. I tried to use a NSProxy subclass as standing for objects to be passed to NSTableView, but I'm getting the following error.
Cannot update for observer <NSAutounbinderObservance 0x105889dd0> for
the key path "objectValue.status" from <NSTableCellView 0x105886a80>,
most likely because the value for the key "objectValue" has changed
without an appropriate KVO notification being sent. Check the
KVO-compliance of the NSTableCellView class.
Is there a way to make transparent NSProxy that is KVO compliant?

The crux of the issue is that the guts of Key-Value Observing lives in NSObject, and NSProxy doesn't inherit from NSObject. I'm reasonably confident that any approach will require the NSProxy object to keep its own list of observances (i.e. what outside folks are hoping to observe about it.) This alone would add considerable weight to your NSProxy implementation.
Observe the target
It looks like you've already tried having observers of the proxy actually observe the real object -- in other words, if the target were always populated, and you simply forwarded all invocations to the target, you would also be forwarding addObserver:... and removeObserver:... calls. The problem with this is that you started out by saying:
NSProxy seems to work very well as stand-in objects for those that
don't yet exist
For completeness, I'll describe some of the guts of this approach and why it can't work (at least for the general case):
In order for this to work, your NSProxy subclass would have to collect invocations of the registration methods that were called before the target was set, and then pass them through to the target when it gets set. This quickly gets hairy when you consider that you must also process removals; you wouldn't want to add an observation that was subsequently removed (since the observing object could have been dealloc'ed). You also probably don't want your method of tracking observations to retain any of the observers, lest this create unintended retain cycles. I see the following possible transitions in target value that would need to be handled
Target was nil on init, becomes non-nil later
Target was set non-nil, becomes nil later
Target was set non-nil, then changes to another non-nil value
Target was nil (not on init), becomes non-nil later
...and we run into problems right away in case #1. We would probably be all right here if the KVO observer only observed objectValue (since that will always be your proxy), but say an observer has observed a keyPath that goes through your proxy/real-object, say objectValue.status. This means that the KVO machinery will have called valueForKey: objectValue on the target of the observation and gotten your proxy back, then it will call valueForKey: status on your proxy and will have gotten nil back. When the target becomes non-nil, KVO will have considered that value to have changed out from under it (i.e. not KVO compliant) and you'll get that error message you quoted. If you had a way to temporarily force the target to return nil for status, you could turn that behavior on, call -[target willChangeValueForKey: status], turn the behavior off, then call -[target didChangeValueForKey: status]. Anyway, we can stop here at case #1 because they have the same pitfalls:
nil won't do anything if you call willChangeValueForKey: on it (i.e. the KVO machinery will never know to update its internal state during a transition to or from nil)
forcing any target object to have a mechanism whereby it will temporarily lie and return nil from valueForKey: for all keys seems like a pretty onerous requirement, when the stated desire was a "transparent proxy".
what does it even mean to call setValue:forKey: on a proxy with a nil target? do we keep those values around? waiting for the real target? do we throw? Huge open issue.
One possible modification to this approach would be to use a surrogate target when the real target is nil, perhaps an empty NSMutableDictionary, and forward KVC/KVO invocations to the surrogate. This would solve the problem of not being able to meaningfully call willChangeValueForKey: on nil. All that said, assuming you've maintained your list of observations, I'm not optimistic that KVO will tolerate the following sequence that would be involved with setting the target here in case #1:
outside observer calls -[proxy addObserver:...], proxy forwards to dictionary surrogate
proxy calls -[surrogate willChangeValueForKey:] because target is being set
proxy calls -[surrogate removeObserver:...] on surrogate
proxy calls -[newTarget addObserver:...] on new target
proxy calls -[newTarget didChangeValueForKey:] to balance call #2
It's not clear to me that this won't also lead to the same error. This whole approach is really shaping up to be a hot mess, isn't it?
I did have a couple alternate ideas, but #1 is fairly trivial and #2 and #3 aren't simple enough or confidence-inspiring enough to make me want to burn the time to code them up. But, for posterity, how about:
1. Use NSObjectController for your proxy
Sure, it gums up your keyPaths with an extra key to get through the controller, but this is sort of NSObjectController's whole reason for being, right? It can have nil content, and will handle all the observation set up and tear-down. It doesn't achieve the goal of a transparent, invocation forwarding proxy, but for example, if the goal is to have a stand-in for some asynchronously generated object, it would probably be fairly straightforward to have the asynchronous generation operation deliver the final object to the controller. This is probably the lowest-effort approach, but doesn't really address the 'transparent' requirement.
2. Use an NSObject subclass for your proxy
NSProxy's primary feature isn't that it has some magic in it -- the primary feature is that it doesn't have (all) the NSObject implementation in it. If you're willing to go to the effort to override all NSObject behaviors that you don't want, and shunt them back around into your forwarding mechanism, you can end up with the same net value provided by NSProxy but with the KVO support mechanism left in place. From there, it's a matter of your proxy watching all the same key paths on the target that were observed on it, and then rebroadcasting willChange... and didChange... notifications from the target so that outside observers see them as coming from your proxy.
...and now for something really crazy:
3. (Ab)Use the runtime to bring the NSObject KVC/KVO behavior into your NSProxy subclass
You can use the runtime to get the method implementations related to KVC and KVO from NSObject (i.e. class_getMethodImplementation([NSObject class], #selector(addObserver:...))), and then you can add those methods (i.e. class_addMethod([MyProxy class], #selector(addObserver:...), imp, types)) to your proxy subclass.
This will likely lead to a guess-and-check process of figuring out all the private/internal methods on NSObject that the public KVO methods call, and then adding those to the list of methods that you wholesale over. It seems logical to assume that the internal data structures that maintain KVO observances would not be maintained in ivars of NSObject (NSObject.h indicates no ivars -- not that that means anything these days) since that would mean that every NSObject instance would pay the space price. Also, I see a lot of C functions in stack traces of KVO notifications. I think you could probably get to a point where you had brought in enough functionality for the NSProxy to be a first-class participant in KVO. From that point forward, this solution looks like the NSObject based solution; you observe the target and rebroadcast the notifications as if they came from you, additionally faking up willChange/didChange notifications around any changes to the target. You might even be able to automate some of this in your invocation forwarding mechanism by setting a flag when you enter any of the KVO public API calls, and then attempting to bring over all methods called on you until you clear the flag when the public API call returns -- the hitch there would be trying to guarantee that bringing over those methods didn't otherwise ruin the transparency of your proxy.
Where I suspect this will fall down is in the mechanism whereby KVO creates dynamic subclasses of your class at runtime. The details of that mechanism are opaque, and would probably lead to another long train of figuring out private/internal methods to bring in from NSObject. In the end, this approach is also completely fragile, lest any of the internal implementation details change.
...in conclusion
In the abstract, the problem boils down to the fact that KVO expects a coherent, knowable, consistently updated (via notifications) state across it's key space. (Add "mutable" to that list if you want to support -setValue:forKey: or editable bindings.) Barring dirty tricks, being first class participants means being NSObjects. If one of those steps in the chain implements it's functionality by calling through to some other internal state, that's its prerogative, but it'll be responsible for fulfilling all its obligations for KVO compliance.
For that reason, I posit that if any of these solutions are worth the effort, I'd put my money on the "using an NSObject as the proxy and not NSProxy." So to get to the exact nature of your question, there may be a way to make an NSProxy subclass that is KVO compliant, but it hardly seems like it would worth it.

I don't have the exact same use case (no bindings) of OP but mine was similar: I am creating an NSProxy subclass that presents itself as another object that is actually loaded from a server. During the load, other objects can subscribe to the proxy and the proxy will forward the KVO as soon as the object arrives.
There is a simple NSArray property in the proxy that records all observers. Until the real object is loaded, the proxy returns nil in valueForKey:. When the realObject arrives, the proxy calls addObserver:forKeyPath:options:context: on the real object and then, through the magic of the runtime, walks through all properties of realObject and does this:
id old = object_getIvar(realObject, backingVar);
object_setIvar(realObject, backingVar, nil);
[realObject willChangeValueForKey:propertyName];
object_setIvar(realObject, backingVar, old);
[realObject didChangeValueForKey:propertyName];
This seems to work, at least I haven't gotten any KVO compliance errors yet. It does make sense though, first all properties are nil and then they change from nil to the actual value. It is all like ipmcc said in his first statement above, so this post is just a confirmation! Note that the second surrogate that he proposed actually isn't needed, you just have to keep track of observers yourself.

Related

When to use NSNotificationCenter

I want to have multiple observers on multiple events of a single object (1-to-N relationship).
A mechanism to achieve this task is provided by the NSNotificationCenter. The mechanism looks pretty overkill when used for my problem.
How I would do it manually without the use of NSNotificationCenter:
- (void)addDelegate:(id<DelegateProtocol>)delegate;
- (void)removeDelegate:(id<DelegateProtocol>)delegate;
to add and remove observers from my object.
- (void)someEventFired:(NSObject<NSCopying> *)eventData
{
for (id delegate in delegates) {
NSObject *data = [eventData copy];
[delegate someEventFired:data];
}
}
This mechanism is straight-forward and simple to implement without the objects having to share additional strings.
Is there an official pattern for 1-to-N delegates (like C# events) in an iOS framework besides the NSNotificationCenter?
When should the NSNotificationCenter be used and when not?
When should an implementation like the one I am suggesting here be used and when not?
By convention, delegates should probably only be used for 1:1 relationships. If you really need 1:N relationships for this type of functionality, you have two options:
As you mentioned, NSNotificationCenter.
Key-Value Observing (also known as KVO).
KVO is appropriate if you only care about when a particular property of an object changes. Otherwise, you should really just consider using NSNotificationCenter. You can even be notified only when a specific object posts that notification by passing that object into the addObserver:selector:name:object: method.
Apple uses NSNotification in similar scenarios (like the notifications defined for UITextField, including UITextFieldTextDidBeginEditingNotification, UITextFieldTextDidChangeNotification, and UITextFieldTextDidEndEditingNotification).
using notifications is broadcasting: 1 sender just sends an information and who ever tuned in, receives it. Petty much like a radio station, there is no channel back (lets for the moment forget about telephones)
delegation is something different. Th object, that asks a deleagte to do something, usually needs a result of that request, there fore delegation is a 1-to-1 communication, that is always initiated by the object, not the delegate (while the object can have methods that can be called to inform the object to initiate the communication, ie [tableView reloadData]).
So if the sender needs to get data back, it is delegation. If the sender doesn't care about anything after broadcasting, go with notifications.
If you run into the situation, that you need delegation, but several objects should implement the protocol. you should have 1 delegate, that hold references to the other objects and calls the methods on the senders behalf — or you could go with blocks.
NSNotificationCenter is not overkill for what you are suggesting, it is exactly the right solution. It prevents the observed object having to know or care about its observers, making your code more loosely coupled and cleaner.
Sharing strings for notification names is trivial and they can be defined in either a shared constants file or in the header of the observed object, if your observers need to import this header to do their jobs.
Your proposed solution is neither simpler than using NSNotificationCenter nor is it thread safe.
To make your solution thread safe, you would need to provide a mechanism to prevent the delegates array from changing while the event dispatch for loop is running.
Your solution also requires that you maintain the delegates array in your class. With the NotificationCenter you can simply use the default center and you don't need to implement the add/remove methods in your class. Instead, instances can register themselves to receive notifications as they see best fit (selector/block, queue, source). Your source class doesn't have to worry about those details. It only needs to register itself as a source of notifications of a specified type. Using blocks to handle notifications is really convenient.
An alternative to the notification center is to use Key-Value-Observing if that meets the needs of your use case.
Ultimately, the mechanism you decide to use depends on how best it applies to your specific use case.
A 1-to-N delegate relationship doesn't make sense. Have a look at
- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
for example. What if this object really had n delegates? How should it decide which of the n views it gets back from all its delegates should be used? Delegates are exactly this 1-to-1 principle.
The NSNotificationCenter is the right approach. Simply use
addObserver:selector:name:object:
respectively
postNotification:
This is definitely not too much code. And it's very easy for you as the center handles all calls.
You don't want to use NSNotificationCenter for anything other than system-wide events (e.g. the appearance of the keyboard or some similar event). The reason is that it is completely not type-safe, can make everything dependent on everything and that you get no compile time checks or usage search results anymore.
KVO in my opinion should not be used to observe changes outside of the object you're listening to since it has similar down sides (no compile time checks, crashes if you don't remove listeners properly or register them twice).
The addDelegate/removeDelegate pattern that you pose is completely the right path in my opinion since that has the advantage of maintaining type-safety and compiler checks and makes dependencies explicit. The only problem is that Apple doesn't supply an out-of-the-box solution for this pattern, since you need a collection type that weakly retains its elements to avoid retain cycles.
However, see code from my BMCommons framework which solves this problem neatly using BMNullableArray and macros. See the BMCore.h header for a definition of those macros:
BM_LISTENER_METHOD_DECLARATION(protocol)
BM_LISTENER_METHOD_IMPLEMENTATION(protocol)
The implementation ensures that the same listener will never be added twice and also that listeners are weakly retained, not causing any crash even if they forget to deregister themselves upon deallocation (although I prefer to catch this condition with an assert since it is a programming mistake).
I say NSNotificationCenter should ALWAYS be used, over the delegate model, except in situations where you query a delegate on information (e.g. -webView:shouldLoadRequest:). It is more stable, easier to implement, and results in cleaner code then trying to use a delegate. The other alternative is blocks, which can be good, but they can be a pain when it comes to memory-managment.
In the end, it's up to you, but I think that NSNotificationCenter is the best way to go in almost any situation, if only for the multiple observer functionality.

How to manage unsafe_unretained ivars/properties?

I started objective-c and iOS a couple of weeks ago (worth bearing in mind), and I apologise in advance for the awful diagram!!
The above diagram shows the structure of my calls to a webservice. Thin arrows denote an object creating another object, whereas thick arrows denote an object holding a strong (retained) reference to the pointed-to object.
I believe that this contains what is called a "circular reference" and will create problems when it comes to deallocating the objects.
I understand that the easy answer would be to replace some of the strong references to weak ones, which I'd love to do, except my project is also targeting iOS 3.2 (not my decision - I can't really change this fact!). So, I think I'm right in saying that I have to use __unsafe_unretained instead, but I'm quite worried about the fact that these won't auto-zero, as I'll end up with EXC_BAD_ACCESS problems when objects get deallocated...
So my problem is firstly that I have circular references. To solve, I would have to use __unsafe_unretained, which leads to my second problem: How to correctly manage these?
A question that might be related is: How does NSURLConnection manage it's strong references? I have heard from various sources that it retains its delegate? So...if I retain an NSURLConnection, (and am also its delegate) and it retains me, this would also be a circular reference, no? How does it get around my problem?
Any advice is very welcome!
Regards,
Nick
When a parent has a reference to a child object, it should use a strong reference. When a child has a reference to it's parent object, it should use a weak reference, aka unsafe_unretained.
By convention, delegate relationships in iOS are usually weak references, so you'll find that most delegate properties on Apple's own classes are declared as unsafe_unretained.
So your controller retains the services that it is using, but the services only weakly link back to the controller. That way, if the controller is released, the whole lot can be safely disposed of without any circular references.
The danger with this is that if the web service is doing some long-running task, and the controller gets released before it has finished, the service is left with a dangling pointer to it's now-deallocated delegate. If it tries to send a message to the delegate, such as "I have finished" it will crash.
There are a few approaches to help solve this (they aren't mutually exclusive - you should try to do them all whenever possible):
1) Always set the delegate properties of your services to nil in your controller's dealloc method. This ensures that when the controller is released, the delegate references to it are set to nil (sort of a crude, manual equivalent of what ARC's weak references do automatically).
2) When creating your own service classes that have delegates, make them retain their delegate while they are running and then release the delegate when they are done. That way the delegate object can't get deallocated while the service is still sending it messages, but it will still get released once the service has finished (NSTimer's and NSURLConnections both work this way - they retain their delegate while they are running and release it when they are done).
3) Try not to have long-running services owned by something transient like a view controller. Consider creating singleton objects (shared static object instances) that own your services, that way the service can do it's job in the background regardless of what's going on in the view layer. The controller can still call the service, but doesn't own it - the service is owned by a static object that will exist for the duration that the app is running, and so there's no risk of leaks or premature releases. The service can communicate with the controller via NSNotifications instead of delegate calls, so there is no need for it to have a reference to an object that may vanish. NSNotifications are a great way to communicate between multiple classes without creating circular references.
All of your questions and concerns are correct, and this problem with the previous use of assign (now better named __unsafe_unretained) is why Apple developed auto-zeroing for weak. But we've dealt reasonably safely with assign delegates for many years, so as you suspect, there are ways to do it.
First, as a matter of practice, you should always clear yourself as the delegate when your release an object you were delegate for. Pre-ARC, this was traditionally done in dealloc:
- (void)dealloc {
[tableView_ setDelegate:nil];
[tableView_ release];
tableView_ = nil;
}
You should still include that setDelegate:nil in your dealloc if delegate is __unsafe_unretained. This will address the most common form of the problem (when the delegate is deallocated before the delegating object).
Regarding NSURLConnection, you are also correct that it retains its delegate. This is ok because it has a lifespan typically much shorter than its delegate (versus a table view delegate which almost always has the same lifespan as the table view). See " How to work around/handle delegation EXC_BAD_ACCESS errors? Obj C " for more discussion on this in a pre-ARC context (the same concepts apply in the new world of strong/weak).

Is there a way to tell when KVO starts/ends for a particular value?

I have some values that are computed over collections, and may or may not be displayed (and thus may or may not have an observer) at any given time. I would rather not have to track all the members of the collection if nobody is observing my computed values.
Can I tell if anyone is currently observing a value, and can I tell when they start observing?
I know for a given object foo I can use [foo observationInfo] to get a list of observers with key paths registered with a root at foo, but that doesn't automatically get all paths TO foo (in fact it only gets ones registered to observe foo's self key).
That’s not a good idea from the design point of view. If you really insist on not updating the contents when nobody needs them (which could be a legitimate case, for example if the updates are expensive), you can introduce methods to start/stop the updates:
- (void) beginUpdatingContents;
- (void) endUpdatingContents;
These should be tied to a counter inside the class and if the counter is > 0, you know somebody wants to keep the contents updated. This solution is explicit and therefore better than silent magic with KVO.
If you want more magic, how about overriding addObserver:forKeyPath:options:context: and removeObserver:forKeyPath: and tracking what is still observing you?
The way I've actually done this in the past is by making wrapper objects (I called them bindings) which set up KVO and also register themselves with the target. So, a user would call MyBinding *binding = [targetObject bindKeyPath:#"foo" ...] and then later [binding detach]. You then have the binding use KVO under the hood and keep a list of themselves so you know when it's empty.

NSNotification concept - what piece of code goes where?

Part of me thinks I understand the NSNotification concept. It's a centralized broadcast system with string based notifications. Post on one side, observe on one or multiple other sides and act accordingly. Another part of me though, the part that has to write the code, gets confused every time I need a notification. What piece of code goes into which header/implementation, what files actually do the observing and how do I keep it from becoming a mess? Time to straighten it out, will you help me verify these assumptions? I'm fairly confident up to number 4, but number 5 hits the confusion jackpot.
NSNotifications are created with help from the [NSNotification defaultCenter], one does not alloc/init a NSNotification. Correct?
The object performing the postNofification feat always passes self into the posting code: [[NSNotificationCenter defaultCenter] postNotificationName:#"note name" object:self]. Correct?
Event bubbling exists in other languages, but not in Objective-C with NSNotification. You don't pass along notifications, you make the notification name specific enough for the global broadcast. Correct?
If you still want to pass along a notification posted by object A, you observe it in B, handle it and post a new, more specific notification for object C to observe. Eg. #"MenuItemTapped" from A to B, and #"NavigateTo" from B to C. Correct?
The name of a notification is a NSString. Because both the poster and the observer want to avoid typos, we store the NSString constant in a [extern const|define|class method|none of the above]. Could you help me pick one?
One attempt was to create something like a NotificationNames.h file, which would contain all the extern NSString *const NOTE_NAME declarations. Yet that undermines the portability of a notification.
Another attempt was to subclass NSNotification (with an XCode template to keep the creation fast), but because this concept is taken from subclassing the Event-class in AS3, it seemed very un-objective-c-ish. There's also the weirdness that you can't call [super init] on a NSNotification, so things started to get out of hand.
My troubles with this one arise from the cumbersome #import statements. How to minimize typo's, yet keep the constants/defines portable?
You've mostly got it. Your numbers 1-3 are generally correct.
You shouldn't ever need to alloc your own NSNotification object.
You generally pass "self" as the "object" of the notification as you say, but you could also pass something else in if you are notifying "on behalf of" something else, conceptually. But that would be less common case.
Notifications aren't the same as "events" in the UI. Cocoa does have events; they are mouse/keyboard/touch events, and they do "bubble" up the "responder chain" through the UI objects. Notifications are a totally independent mechanism that is not tied to UI, and it is used for generally global broadcast among otherwise decoupled/independent objects. It's more akin to having multiple delegates for an object.
Yes, you should define the name of the notification somewhere that everyone who uses it can see. In Cocoa itself, this is usually a public header with a declaration like extern NSString *const UIKeyboardDidShowNotification. In some private implementation file is the definition.
A special note regarding your #4 above. Think of notifications as notifications, not as instructions. They usually capture state changes or broadly interesting events. "MenuItemTapped" is a reasonable thing to notify about, but "NavigateTo" usually isn't, because the implication is that you're telling some specific object to navigate somewhere. If that's the case, that object should probably be a delegate (or should be a property) of the thing that wants the navigation, and you should cause it to happen directly. This isn't a requirement, of course, and you can use the mechanism for whatever you want. But the Cocoa design patterns generally don't use notifications for "telling objects what to do", only for "telling whoever cares what will/did happen". Make sense?
Finally, specifically re: your examples in #4-- those sound like genuine UI events, and seem like the whole thing could be handled via delegation, unless there's some reason why those objects need to be so decoupled.
You can directly create NSNotification objects if you so wish. postNotificationName:object: is just a convenience method that creates, configures and posts a notification object for you.
You can pass any object you like. Its purpose is to allow notification subscribers to only receive notifications about a particular object, so ideally you pass in the object the notification is about, which will often - but not always - be self.
Notifcations are not events. They're global broadcasts within the application.
You don't send notifications to a particular object - They're broadcasts. If you want to send a message to a particular object, you just call a method on that object.
Externs in the header file are fine.

In ObjC, how to describe balance between alloc/copy/retain and auto-/release, in terms of location

As is common knowledge, calls to alloc/copy/retain in Objective-C imply ownership and need to be balanced by a call to autorelease/release. How do you succinctly describe where this should happen? The word "succinct" is key. I can usually use intuition to guide me, but would like an explicit principle in case intuition fails and that can be use in discussions.
Properties simplify the matter (the rule is auto-/release happens in -dealloc and setters), but sometimes properties aren't a viable option (e.g. not everyone uses ObjC 2.0).
Sometimes the release should be in the same block. Other times the alloc/copy/retain happens in one method, which has a corresponding method where the release should occur (e.g. -init and -dealloc). It's this pairing of methods (where a method may be paired with itself) that seems to be key, but how can that be put into words? Also, what cases does the method-pairing notion miss? It doesn't seem to cover where you release properties, as setters are self-paired and -dealloc releases objects that aren't alloc/copy/retained in -init.
It feels like the object model is involved with my difficulty. There doesn't seem to be an element of the model that I can attach retain/release pairing to. Methods transform objects from valid state to valid state and send messages to other objects. The only natural pairings I see are object creation/destruction and method enter/exit.
Background:
This question was inspired by: "NSMutableDictionary does not get added into NSMutableArray". The asker of that question was releasing objects, but in such a way that might cause memory leaks. The alloc/copy/retain calls were generally balanced by releases, but in such a way that could cause memory leaks. The class was a delegate; some members were created in a delegate method (-parser:didStartElement:...) and released in -dealloc rather than in the corresponding (-parser:didEndElement:...) method. In this instance, properties seemed a good solution, but the question still remained of how to handle releasing when properties weren't involved.
Properties simplify the matter (the rule is auto-/release happens in -dealloc and setters), but sometimes properties aren't a viable option (e.g. not everyone uses ObjC 2.0).
This is a misunderstanding of the history of properties. While properties are new, accessors have always been a key part of ObjC. Properties just made it easier to write accessors. If you always use accessors, and you should, than most of these questions go away.
Before we had properties, we used Xcode's built-in accessor-writer (in the Script>Code menu), or with useful tools like Accessorizer to simplify the job (Accessorizer still simplifies property code). Or we just typed a lot of getters and setters by hand.
The question isn't where it should happen, it's when.
Release or autorelease an object if you have created it with +alloc, +new or -copy, or if you have sent it a -retain message.
Send -release when you don't care if the object continues to exist. Send -autorelease if you want to return it from the method you're in, but you don't care what happens to it after that.
I wouldn't say that dealloc is where you would call autorelease. And unless your object, whatever it may be, is linked to the life of a class, it doesn't necessarily need to be kept around for a retain in dealloc.
Here are my rules of thumb. You may do things in other ways.
I use release if the life of the
object I am using is limited to the
routine I am in now. Thus the object
gets created and released in that
routine. This is also the preferred
way if I am creating a lot of objects
in a routine, such as in a loop, and
I might want to release each object
before the next one is created in the
loop.
If the object I created in a method
needs to be passed back to the
caller, but I assume that the use of
the object will be transient and
limited to this run of the runloop, I
use autorelease. Here, I am trying to mimic many of Apple's convenience routines. (Want a quick string to use for a short period? Here you go, don't worry about owning it and it will get disposed appropriately.)
If I believe the object is to be kept
on a semi-permanent basis (like
longer than this run of the runloop),
I use create/new/copy in my method
name so the caller knows that they
are the owner of the object and will
have to release the object.
Any objects that are created by a
class and kept as a property with
retain (whether through the property
declaration or not), I release those
in dealloc (or in viewDidUnload as
appropriate).
Try not to let all this memory management overwhelm you. It is a lot easier than it sounds, and looking at a bunch of Apple's samples, and writing your own (and suffering bugs) will make you understand it better.