BNZAtomicPropertyChange



Abstract

A generic implementation of BNZAtomicChange that can be used for simple one-valued properties (i.e., no lists or other collections are supported)

Discussion

The BNZAtomicPropertyChange is a generic implementation for changes on properties that are not lists or arrays or other collections.

It implements the BNZAtomicChange protocol and provides static helper methods that greatly simplify the implementation of transactional objects.

For setter and getter methods of an object, a static method of BNZAtomicChange is provided to gain all the functionality like transactions and showing changes within the same thread but hiding them from other threads until committed.

The convention to use this generic change implementation (especially the easy-to-use static methods) is as follows:

for each property like "firstName" provide a public setter "setFirstName:" and getter "firstName" (however, for readonly or writeonly, a getter or setter may be ommitted and the exact names are not really important) Implement the getter and setter like in the example below Provide accessor methods (also getter and setter) that allow the change object to access the iVar directly. Naming scheme is: "setFirstName_internal:" and "firstName_internal" These names are important, if you use the static helper methods of this class. If the accessors are named differently, directly use the initWithTarget:newValue:setterMethod:getterMethod:andChangeType: instead.

Note: it may be possible to get rid of the accessor methods by providing some pointers to the fields. However, there still may be a reason to encapsulate field access because some fields may have to be calculated or reading/setting a field may trigger some other things.

Example implementation of an transactional object's setter and getter:

- setFirstName:(NSString*)name {
[BNZAtomicPropertyChange createAtomicChangeOfProperty:"firstName" onTarget:self toNewValue:name];
return self;
}
- (NSString*)firstName {
return [BNZAtomicPropertyChange transactionalValueForProperty:"firstName" ofTarget:self];
}


//internal methods for communication between change objects and the person, not part of the header! - (void)setFirstName_internal:(NSString*)newName { firstName = newName; } - (NSString*)firstName_internal { return firstName; }





Methods

createAtomicChangeOfProperty:onTarget:toNewValue:

Abstract: a helper for implementing the setters of a transactional object
+ (void)createAtomicChangeOfProperty:(NSString*)property onTarget:(id)target toNewValue:(id)newValue; 

Instead of directly changing their internal fields when a setter is called, transactional objects create a change object that will do this at a later point in time when the change is committed. This static method is a helper for doing this in one step. It will try to figure out the internal property accessor methods (see getterAccessorForProperty: and setterAccessorForProperty:) and create a new instance of BNZAtomicPropertyChange. Then it will fetch the current transaction from the BNZTransactionalNotificationCenter and add the change to the transaction.

Parameters

NameDescription
propertythe name of the property
targetthe object that contains the property
newValuethe value to which the property should be set

getterAccessorForProperty:

Abstract: retreive the standard selector for accessing the property internally
+ (SEL)getterAccessorForProperty:(NSString*)property; 

Objects that are using the BNZAtomicPropertyChange implementation's static helper methods are required to offer a _internal method for retreiving the property value. Example: firstName property => - (id)firstName_internal method expected. This method tries to construct such a selector from the property string.

Parameters

NameDescription
propertythe name of the property
Result: a selector constructed from the name of the property plus the suffix "_internal"

initWithTarget:newValue:setterMethod:getterMethod:andChangeType:

Abstract: inits a new instance of this class
- (id)initWithTarget:(id)target newValue:(id)newValue setterMethod:(SEL)setter getterMethod:(SEL)getter andChangeType:(id)type; 

Inits the fields of the BNZAtomicPropertyChange the oldValue field is retreived through the getterMethod.

Parameters

NameDescription
targetthe target object of this change
newValuethe value the property should be changed to
setterMethodan internal setter of the target to directly set the property
getterMethodan internal getter of the target to directly get the property
changeTypea unique identifier identifying this type of change
Result: a BNZAtomicPropertyChange

initWithTarget:propertyName:newValue

Abstract: inits the new instance of this class
- (id)initWithTarget:(id)target propertyName:(NSString*)property newValue:(id)newValue; 

This initializer will try to figure out the getter and setter accessor methods (see getterAccessorForProperty: and setterAccessorForProperty:) according to the property name and construct a change type by calling proposedChangeTypeForProperty:ofTarget and call the initWithTarget:newValue:setterMethod:getterMethod:andChangeType:

Parameters

NameDescription
targetthe target object of this change
propertythe name of the property that should be changed
newValuethe value the property should be changed to
Result: a BNZAtomicPropertyChange

newValue

- (id)newValue; 

Result: the value the property should have after committing the change

oldValue

- (id)oldValue; 

Result: the value of the property before the change

proposedChangeTypeForProperty:ofClass:

Abstract: generates an identifier for a change on the given property of the given target
+ (id)proposedChangeTypeForProperty:(NSString*)property ofClass:(Class)clazz; 

Given that a property name is unique within a class, this method constructs a unique identifier string for a property change by combining the class name, the property name, and applying the suffix "Change". Example: Class Person with a property "firstName" will produce: "PersonFirstNameChange"

Parameters

NameDescription
propertyname of the property that ought to be changed
clazza class that contains the property that should be changed
Result: a unique change type

proposedChangeTypeForProperty:ofTarget:

Abstract: calls proposedChangeTypeForProperty:ofClass: with the class of the target
+ (id)proposedChangeTypeForProperty:(NSString*)property ofTarget:(id)target; 


setterAccessorForProperty:

Abstract: retreive the standard selector for setting the property internally
+ (SEL)setterAccessorForProperty:(NSString*)property; 

Objects that are using the BNZAtomicPropertyChange implementation's static helper methods are required to offer a set_internal method for setting the property value. Example: firstName property => - (void)setFirstName_internal: method expected. This method tries to construct such a selector from the property string

Parameters

NameDescription
propertythe name of the property
Result: a selector constructed from the name of the property plus the prefix "set" and the suffix "_internal"

transactionalValueForProperty:ofTarget

Abstract: a helper for implementing getters in transactional objects
+ (id)transactionalValueForProperty:(NSString*)property ofTarget:(id)target; 

Objects that participate in uncommitted transactions need to return different values for their fields to callers from different threads (i.e., hide uncommitted changes to other threads and show them to the own thread). This method implements this behavior. When called, it tries to find the last change of the given property in the transaction of the current thread. If it finds one, it returns the [change newValue] and therefore "pretends that the change has already been done" for the caller thread. If it doen't find any change of the property in the current thread, it returns the real field value of the target as it is retrieved by the getterAccessorForProperty:

Parameters

NameDescription
propertythe name of the property
targetthe object that contains the property
Result: the current value of the property of this target in the calling thread

(Last Updated 8/31/2006)