ARC Creating New Objects in Method - cocoa

I just moved a project from MRR to ARC using Xcode's tool. I have a routine that works like this:
#interface myObject
{
NSMutableArray* __strong myItems;
}
#property NSMutableArray* myItems;
- (BOOL) readLegacyFormatItems;
#end
- (BOOL) readLegacyFormatItems
{
NSMutableArray* localCopyOfMyItems = [[NSMutableArray alloc]init];
//create objects and store them to localCopyOfMyItems
[self setMyItems: localCopyOfMyItems]
return TRUE;
}
This worked fine under MRR, but under ARC myItems is immediately released. How can I correct this?
I've read about __strong and __weak references, but I don't yet see how to apply them in this case.
Thanks very much in advance to all for any info!

This should work, as it is. But you don't need to declare the iVars anymore. Just use properties. You even don't need to synthesize them. Strong properties will retain any assigned object, weak properties won't.
Also class names should always be uppercase. And - since you store a mutable array - you can also add your objects directly to the property. No need for another local mutable array variable.
#interface MyObject
#property (nonatomic, strong) NSMutableArray *myItems;
- (BOOL)readLegacyFormatItems;
#end
#implementation MyObject
- (BOOL) readLegacyFormatItems
{
self.myItems = [[NSMutableArray alloc]init];
//create objects and store them directly to self.myItems
return TRUE;
}
#end

Related

how to store object to NSmutablearray in app delegate?

I'm having a problem with storing and accessing objects with NSmutable array in app delegate. I have tried methods form other websites and stack overlay pages but yet no solution. I want to able to access the array data in another view. Currently nothing is working for me.
Heres my code.
AppDelegate.h :
#interface AppDelegate : UIResponder <UIApplicationDelegate>
{
NSMutableArray* sharedArray;
}
#property (nonatomic, retain) NSMutableArray* sharedArray;
ViewController.h :
#import "AppDelegate.h"
-(void)viewDidLoad{
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSMutableArray *model = appDelegate.sharedArray;
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
[dict setObject:#"hello" forKey:#"title"];
[dict setObject:#"urlhere" forKey:#"thumbnail"];
[model addObject:dict];
NSLog(#"submitted to array: %#",model);
}
Are you, at any point, initializing the sharedArray? The array must be instantiated before you can add objects to it. For example:
AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
self.sharedArray = [NSMutableArray array];
return YES;
}
Having done that, now attempts to add objects to this array from your view controllers should succeed.
Unrelated, but you should not define instance variables for your properties. Let the compiler synthesize that for you, e.g.:
AppDelegate.h:
#interface AppDelegate : UIResponder <UIApplicationDelegate>
// {
// NSMutableArray* sharedArray;
// }
#property (nonatomic, retain) NSMutableArray* sharedArray;
#end
What you have is technically acceptable, but it's inadvisable because of possible confusion between this sharedArray instance variable and the what the compiler will synthesize for you (e.g. if you don't have a #synthesize line, the compiler will automatically create an instance variable called _sharedArray, with a leading underscore, for you). Even if you had a #synthesize line that ensured that the instance variable was correct, having the explicitly declared instance variable is simply redundant.

Having problems adding objects to array

In the code below, I am trying to add objects to array. No error, but is not adding objects either. Sorry for asking this pretty basic question. Need help
The NS Object Definition
//DataDefinition.h
#import
#interface DataDefinition : NSObject
#property (nonatomic, retain) NSString *dataHeader;
#property (nonatomic, retain) NSMutableArray *dataDetails;
#end
The DataDefinition Implementation
#import "DataDefinition.h"
#implementation DataDefinition
#synthesize dataHeader;
#synthesize dataDetails;
#end
The Display header section
//DataDisplay.h
#import
#import "DataDefinition.h"
#interface DataDisplay : UITableViewController
#property (strong, nonatomic) NSMutableArray *dataSet;
#property (strong, atomic) DataDefinition *individualData;
#end
The Display implementation section
//DataDisplay.m
#import "DataDisplay.h"
#interface DataDisplay ()
#end
#implementation DataDisplay
#synthesize dataSet;
#synthesize individualData;
- (void)viewDidLoad
{
[super viewDidLoad];
individualData.dataHeader = #"Header1";
individualData.dataDetails = [[NSMutableArray alloc] initWithObjects:#"Header1-Detail1", #"Header1-Detail2", #"Header1-Detail3", nil];
//This didnot add
[dataSet addObject:individualData];
NSLog(#"Count of objects is %d:",[dataSet count]);
//Nor did this
dataSet = [[NSMutableArray alloc] initWithObjects:individualData, nil];
NSLog(#"Count of objects is %d:",[dataSet count]);
self.title = #"DataDisplay";
}
The issue is that individualData is never actually set to an instantiated object (in other words, it is never initialized).
These kinds of oversights are common due to Objective-C's non-error policy regarding sending messages to nil; it's perfectly legal and often useful principle. This means that your code will never complain until you try to pass it to some method which will crash if it sees nil. Unfortunately, you are using initWithObjects, which simply sees nil as the end of the (empty) list. If you had instead tried to use [NSArray arrayWithObject:individualData] you may have seen an error which would hint to you that you had nil instead of an object.
Note that setting properties on nil is particularly tricky, since it looks like you are simply dealing with a C-syle lvalue, when actually it translates to a message-send call at runtime:
individualData.dataHeader = #"Header1";
// is *literally* the same as:
[individualData setDataHeader:#"Header1"];
You can take your pick of solutions. The "cheap" way is to simply initialize it right there. The "better" way (usually) is lazy-instantiation (i.e. in the getter). Since the object is marked as atomic, you likely need to let the compiler write the getter for you, and just initialize it in viewDidLoad (or awakeFromNib, initWithCoder, or similar):
- (void)viewDidLoad
{
[super viewDidLoad];
self.individualData = [[DataDefinition alloc] init];
...

Multilevel cocoa bindings

When I bind to a multiple level keypath, say objectValue.person.photo, it does not update when the person changes, only when the photo changes. This would seem to be a problem with only the last key in the path being observed for changes.
Is it possible to observe multiple levels of bindings? For instance, in SproutCore, if you place an asterisk in the path, everything after it will be observed for changes (objectValue*person.photo).
If your bindings are not updating when objectValue.person is changed, then that usually means that whatever object is in objectValue is not Key-Value Observing compliant for the key person. With properly implemented objects, non-leaf mutations along a keyPath work fine. For instance, starting from the base non-document Cocoa Application template, I cooked up the following example:
Header:
#interface Person : NSObject
#property (copy) NSString* name;
#end
#interface Car : NSObject
#property (retain) Person* driver;
#end
#interface SOAppDelegate : NSObject <NSApplicationDelegate>
#property (assign) IBOutlet NSWindow *window;
#property (retain) Car* car;
- (IBAction)replaceCar:(id)sender;
- (IBAction)replaceDriver:(id)sender;
- (IBAction)changeName:(id)sender;
#end
Implementation:
#implementation Person
#synthesize name;
#end
#implementation Car
#synthesize driver;
#end
#implementation SOAppDelegate
#synthesize car = _car;
#synthesize window = _window;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
Person* person = [[[Person alloc] init] autorelease];
person.name = #"Default Name";
Car* car = [[[Car alloc] init] autorelease];
car.driver = person;
self.car = car;
}
- (IBAction)replaceCar:(id)sender
{
Person* person = [[[Person alloc] init] autorelease];
person.name = #"Replaced Car";
Car* newCar = [[[Car alloc] init] autorelease];
newCar.driver = person;
self.car = newCar;
}
- (IBAction)replaceDriver:(id)sender
{
Person* person = [[[Person alloc] init] autorelease];
person.name = #"Replaced Driver";
self.car.driver = person;
}
- (IBAction)changeName:(id)sender
{
self.car.driver.name = #"Changed Name";
}
#end
Then in the .xib, I added three buttons, calling each of the IBActions and added a label whose value property was bound to App Delegate with a keyPath of car.driver.name
Pushing any of the buttons will cause the bound label to update, despite the fact that only one of them actually modifies the exact value pointed to by the bindings keyPath (car.driver.name). KVO compliance comes for free with standard #synthesized properties, so we get proper updates no matter what level in the keyPath they come from.
In short, bindings work the way you want them to (i.e. they update for changes to non-leaf-node keys in a compound keyPath). There's something in the implementation of the objects in objectValue or person that's deficient and preventing this from working. I would look there.
Also note, in case one of these things is a collection, that observing a collection is not the same thing as observing all the objects in a collection. See this page for more info on that.
PS: Yes, I know the example leaks memory. You can imagine the relevant -dealloc methods for yourself.

retain/release issues

I just analyzed my iPhone project, and was very confused by the result XCode(4) gave me. For example, in one of my view controllers I have this code:
#property (nonatomic, retain) NSArray* menuItems;
#property (nonatomic, retain) NSArray* menuItemsOptions;
- (void)viewDidLoad
{
[super viewDidLoad];
self.menuItems = [[NSArray alloc] initWithObjects:
NSLocalizedString(#"Foo", nil),
NSLocalizedString(#"Bar", nil),
nil];
[self.menuItems release];
self.menuItemsOptions = [[NSArray alloc] initWithObjects:
NSLocalizedString(#"More foo", nil),
NSLocalizedString(#"more bar", nil),
nil];
[self.menuItemsOptions release];
...
}
menuItems as well as menuItemsOptionsare properties with the retainoption. If I press analyze, XCode will show an error for the line [self.menuItems release];:
http://i54.tinypic.com/2rqkfaf.png
To confuse me even more, XCode will not show errors for the line [self.menuItemsOptions release];
Similar situation in another method:
http://i55.tinypic.com/10hof9c.png
theSelectedBegin and theSelectedEnd are again properties with retain option.
The reason why I'm posting this is that my app will actually crash with a very cryptic/not understandable backtrace within a third party library unless I add the copy seen on the last picture but dont add the release. Adding the releaseor omitting the copy will make the app crash again, this is why i decided to run the analyzer.
What am I doing wrong?
Try changing someMethod to:
-(void) someMethod:(NSDate*)fromDate toDate:(NSDate*)toDate
{
if (editBegin)
{
NSDate *copiedDate = [fromDate copy];
self.theSelectedBegin = copiedDate;
[copiedDate release];
}
else
{
NSDate *copiedDate = [fromDate copy];
self.theSelectedEnd = copiedDate;
[copiedDate release];
}
}
If you are using copy for the properties theSelectedBegin and theSelectedEnd (which I recommend), like:
#property (nonatomic, copy) NSDate *theSelectedBegin;
#property (nonatomic, copy) NSDate *theSelectedEnd;
The following code is equivalent to the above, but more concise and clean.
-(void) someMethod:(NSDate*)fromDate toDate:(NSDate*)toDate
{
if (editBegin)
{
self.theSelectedBegin = fromDate;
}
else
{
self.theSelectedEnd = fromDate;
}
}
When you do[myObj copy] a new object is returned. Doing [myObj retain] returns the SAME object with an increased retain count. So effectively, the following is BAD code:
#property (nonatomic, copy) NSDate *myDate;
[...]
self.myDate = [someDate copy];
[self.myDate release];
Breaking it down looks more like...
#property (nonatomic, copy) NSDate *myDate;
[...]
NSDate *copyDate = [someDate copy]; // never gets released
self.myDate = copyDate; // good so far for self.myDate
[self.myDate release]; // just released self.myDate (note: copyDate not released)
The reason you're getting a warning from the analyzer is that a getter method is not required to actually return the exact same object as what you passed in to the setter. For example, imagine the following code:
- (void)doSomethingWithAString:(NSString *)aString {
self.myName = [[NSString alloc] initWithFormat:#"%# the Great", aString];
[self.myName release];
}
The string is created with an owning method (-init...), so you own it. Then you gave it to the myName property, which took ownership. Now you need to release the ownership you received from the -init... method, which is done by calling -release. Great.
The problem with the above code is that [self.myName release] might not release the same object you passed in to the setter. Imagine if the setter were implemented like this:
- (void)setMyName:(NSString *)someString {
// Make sure to trim whitespace from my name!
NSCharacterSet *whitespaceSet = [NSCharacterSet whitespaceCharacterSet];
NSString *strippedString = [someString stringByTrimmingCharactersInSet:whitespaceCharacterSet];
[myName autorelease];
myName = [strippedString retain];
}
Note that the object you passed into the setter is not the object that was stored to the backing ivar. When you call [self.myName release], you're releasing the stripped string, not your original string. The original string was now leaked, and the stripped string has been over-released.
In short, never assume that a getter returns the same object you passed to the setter.
One of the appealing features of properties is that the property accessors take care of retaining and releasing the objects they point to. I can't think of a case where one would explicitly retain or release a property.

Tableview with 2 columns y=mx example

How would I make a tableview with 2 columns (x and y) for a function of y=mx
Ive tried lots of things, all of which end in complete failure.
Can someone please make me a sample code and explain it.
Ive asked and asked and people have directed me to all sorts of tutorials of bool, and how to copy and paste contents, how to save to a file, how to make a list of open applications, none of which help me because they are overly complicated
i have this
//array.m
#import "array.h"
#implementation array
- (IBAction)makeArrays:(id)sender
{
int x,y;
NSNumber *multiplier=[NSNumber numberWithFloat:[mField floatValue]];
for (x=0;x++;x<181)
{
y=[multiplier floatValue]*x;
NSNumber *xValue = [NSNumber numberWithInt:x];
NSNumber *yValue = [NSNumber numberWithInt:x];
NSArray *xArray = [NSArray arrayWithObject:xValue];
NSArray *yArray = [NSArray arrayWithObject:yValue];
}
}
#end
and class file
//array.h
#import <Cocoa/Cocoa.h>
#interface array : NSObject {
IBOutlet id mField;
}
- (IBAction)makeArrays:(id)sender;
#end
where do i go from here?
The first thing you should do in OOP is consider the classes of objects. Cocoa uses an MVC (Model, View, Controller) architecture, so classes should fit in one of these three categories. Cocoa already provides the NSTableView class which works quite well, so that leaves the model and controller.
There are a number of different approaches to the model class you could take:
You could write a function table class that holds x and y values in separate arrays
You could write a function table class that has a single array of (x,y) pairs.
In either this or the previous implementation, you could provide a public interface that supports both arrangements (i.e. they'd have methods that return a y given an x, and properties that are x, y, and (x,y) collections). Some implementation details would depend on how you're connecting the table view to the data (bindings, or the older NSTableViewDataSource protocol).
You could also use an array of x values, and create a value transformer. With this approach, the y-values exist in the table view and not the model.
And so on
The application requirements will determine which approach to take. I'll show you the value transformer approach, as it requires the least amount of code.
For the controller, you could rely on NSArrayController (which works quite well with NSTableView), or create your own. For example, you could use an NSMutableArray as the model, and create a controller that maps the values from the array to other values. This controller could perform the mapping using blocks or some function classes that you define.
As you see, there are quite a few options. I'm going to go with the option that requires the least coding: a value transformer, an NSArrayController for the controller and an NSMutableArray (stored in an object that also stores a value transformer) for the model. In the following, code should be stored in files following the standard convention: each interface and implementation is in a separate file with name equal to the class, and an extension of ".h" for interfaces and ".m" for implementation. I also won't bother with the common import statements, such as for Cocoa/Cocoa.h and each class implementation's own interface.
First, the value transformer. Actually, there are two, an abstract superclass and a concrete subclass. This separation is so that you can easily add other function types later. The superclass, FunctionTransformer, is very simple. All that needs to be overridden from its base, NSValueTransformer, is the method that returns the class of transformed values, transformedValueClass:
#interface FunctionTransformer : NSValueTransformer
+ (Class)transformedValueClass;
#end
#implementation Function
+ (Class)transformedValueClass {
return [NSNumber class];
}
#end
The concrete subclass, LinearTransformer, needs to override the primary method of value transformers: transformedValue:. Since linear transforms are invertible, we'll also provide a reverseTransformedValue:. It will also need properties for the slope and intercept values.
#import "FunctionTransformer.h"
#interface LinearTransformer : FunctionTransformer {
NSNumber *m_;
NSNumber *b_;
}
#property (nonatomic,retain) NSNumber *slope;
#property (nonatomic,retain) NSNumber *intercept;
+ (BOOL)allowsReverseTransformation;
-(id)init;
-(id)initWithSlope:(float)slope;
-(id)initWithIntercept:(float)intercept;
-(id)initWithSlope:(float)slope intercept:(float)intercept;
-(void)dealloc;
-(NSNumber*)transformedValue:(id)value;
-(NSNumber*)reverseTransformedValue:(id)value;
#end
#implementation LinearTransformer
#synthesize slope=m_, intercept=b_;
+(BOOL)allowsReverseTransformation {
return YES;
}
-(id)initWithSlope:(float)m intercept:(float)b {
if ((self = [super init])) {
m_ = [[NSNumber alloc] initWithFloat:m];
b_ = [[NSNumber alloc] initWithFloat:b];
}
return self;
}
-(id)init {
return [self initWithSlope:1.0 intercept:0.0];
}
-(id)initWithSlope:(float)slope {
return [self initWithSlope:slope intercept:0.0];
}
-(id)initWithIntercept:(float)intercept {
return [self initWithSlope:1.0 intercept:intercept];
}
-(void)dealloc {
[b release];
[m release];
[super dealloc];
}
-(NSNumber*)transformedValue:(id)value {
return [NSNumber numberWithFloat:([value floatValue] * [m floatValue] + [b floatValue])];
}
-(NSNumber*)reverseTransformedValue:(id)value {
return [NSNumber numberWithFloat:(([value floatValue] - [b floatValue]) / [m floatValue])];
}
#end
A specific LinearTransformer needs to be registered to be used so that you can set the slope and intercept. The application delegate could own this transformer (along with the x value collection), or you could write a custom controller. We're going to write a model class that bundles together the x values and the value transformer, named FunctionTable. Setting the function transformer requires a sub tasks: registering the transformer as a value transformer (using +setValueTransformer:forName:). This means we'll need to provide our own setter (setF:) for the function transformer property (f).
#import "FunctionTransformer.h"
extern NSString* const kFunctionTransformer;
#interface FunctionTable : NSObject {
NSMutableArray *xs;
FunctionTransformer *f;
}
#property (nonatomic,retain) IBOutlet NSMutableArray *xs;
#property (nonatomic,retain) IBOutlet FunctionTransformer *f;
#end
// FunctionTable.m:
#import "LinearTransformer.h"
NSString* const kFunctionTransformer = #"Function Transformer";
#implementation FunctionTable
#synthesize xs, f;
-(id) init {
if ((self = [super init])) {
xs = [[NSMutableArray alloc] init];
self.f = [[LinearTransformer alloc] init];
[f release];
}
return self;
}
-(void)dealloc {
[f release];
[xs release];
[super dealloc];
}
-(void)setF:(FunctionTransformer *)func {
if (func != f) {
[f release];
f = [func retain];
[NSValueTransformer setValueTransformer:f forName:kFunctionTransformer];
}
}
#end
By default, FunctionTable uses a LinearTransformer. If you want to use a different one, simply set the FunctionTables's f property. You could do this in Interface Builder (IB) by using bindings. Note that in this simplistic implementation, the value transformer is always registered under the name "Function Transformer", effectively limiting you to one FunctionTable. A more complex scheme would be to give every FunctionTable their own function transformer name which would be used when registering their own FunctionTransformer.
To set everything up:
Open the app's main window nib in IB.
Instantiate an NSArrayController and a FunctionTable (and your custom app delegate, if any).
To the main window, add:
Buttons to add and remove elements,
labels and NSTextFields for the slope and intercept,
an NSTableView.
Set the table headers to "x" and "y" (not necessary for app to work)
Set up the connections:
Have the add & remove buttons send to the NSArrayController's add: and remove: actions.
Bind the NSTextFields values to the FunctionTables's f.slope and f.intercept key paths.
Bind the values of both columns of the NSTableView to FunctionTables's xs.
Set the value transformer for the second column to "Function Transformer"
Bind the NSArrayController's content array to the FunctionTable's xs key.
If you've got an app delegate, connect it to the File's Owner's delegate outlet.
Now build and run. You can use the add and remove buttons to add and remove rows to/from the table. You can edit the "x" and "y" column in a row (the latter is thanks to reverseTransformedValue:). You can sort by either the "x" or "y" columns. You can change the slope and intercept, though you won't notice the updates in the table unless you select the rows individually.
Advanced Topics
To fix the table view update problem, we need to propagate changes on one object's (a FunctionTransformer) properties to changes on another's (a FunctionTable) properties. We'll have the FunctionTable observe changes on its function transformer's properties and, when it FunctionTable receives a notice that any such property has changed, send a notice that the xs property has changed (which is a bit of an abuse, since xs hasn't actually changed). This is going to get a little magical, so bear with me.
An object subscribes to changes on another object using the KVO method addObserver:forKeyPath:options:context: of the other object, and unsubscribes using removeObserver:forKeyPath:. These methods just need to be called, not written. Notifications are handled by a observeValueForKeyPath:ofObject:change:context: method of the observing object, so this method needs to be written. Finally, an object can send its own notifications by calling willChangeValueForKey: and didChangeValueForKey:. Other methods exist to send notifications that only part of a collection has changed, but we won't use them here.
Our FunctionTable could handle the change subscription and unsubscription, but then it has to know which properties of the function transformer to observe, which means you couldn't change the type of the transformer. You could add methods to each concrete function transformer to subscribe and unsubscribe an observer:
#implementation LinearTransformer
...
-(void)addObserver:(NSObject *)observer
options:(NSKeyValueObservingOptions)options
context:(void *)context
{
[self addObserver:observer
forKeyPath:#"slope"
options:options
context:context];
[self addObserver:observer
forKeyPath:#"intercept"
options:options
context:context];
}
-(void)removeObserver:(id)observer {
[self removeObserver:observer forKeyPath:#"slope"];
[self removeObserver:observer forKeyPath:#"intercept"];
}
#end
However, this will require a fair bit of code repetition in each method and across each concrete function transformer. Using some magic (reflection and closures, or as they're called in Objective-C, blocks ([2])), we can add the methods (named addObserver:options:context: and removeObserver:, as they are functionally similar to the KVO methods for subscribing & unsubscribing) to FunctionTransformer, or even to NSObject. Since observing all properties on an object isn't just limited to FunctionTransformers, we'll add the methods to NSObject. For this to work, you'll need either OS X 10.6 or PLBlocks and OS X 10.5.
Let's start from the top down, with the changes to FunctionTable. There's now new subtasks when setting the function transformer: unsubscribing from changes to the old transformer and subscribing to changes to the new one. The setF: method thus needs to be updated to make use of NSObject's new methods, which will be defined in a header named "NSObject_Properties.h". Note we don't need to worry about the implementation of these methods yet. We can use them here, having faith that we will write suitable implementations later. FunctionTable also needs a new method to handle change notifications (the observeValueForKeyPath:ofObject:change:context: referred to earlier).
#import "NSObject_Properties.h"
#interface FunctionTable
...
-(void)setF:(FunctionTransformer *)func {
if (func != f) {
[f removeObserver:self];
[f release];
f = [func retain];
[f addObserver:self
options:NSKeyValueObservingOptionPrior
context:NULL];
[NSValueTransformer setValueTransformer:f forName:kFunctionTransformer];
}
}
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
if (object == f) {
if ([[change objectForKey:NSKeyValueChangeNotificationIsPriorKey] boolValue]) {
[self willChangeValueForKey:#"xs"];
} else {
[self didChangeValueForKey:#"xs"];
}
}
}
Next, we write the new methods on NSObject. The methods to subscribe or unsubscribe from changes will loop over the object's properties, so we'll want a helper method, forEachProperty, to perform the loop. This helper method will take a block that it calls on each property. The subscription and unsubscription methods will simply call forEachProperty, passing a block that calls the standard KVO methods (addObserver:forKeyPath:options:context: and removeObserver:forKeyPath:) on each property to add or remove subscriptions.
//NSObject_Properties.h
#import <Cocoa/Cocoa.h>
#import <objc/runtime.h>
#interface NSObject (Properties)
typedef void (^PropertyBlock)(objc_property_t prop, NSString *name);
-(void)forEachProperty:(PropertyBlock)block;
-(void)addObserver:(id)observer options:(NSKeyValueObservingOptions)options context:(void *)context;
-(void)removeObserver:(id)observer;
#end
// NSObject_Properties.m:
...
#implementation NSObject (Properties)
-(void)forEachProperty:(PropertyBlock)block {
unsigned int propCount, i;
objc_property_t * props = class_copyPropertyList([self class], &propCount);
NSString *name;
for (i=0; i < propCount; ++i) {
name = [[NSString alloc]
initWithCString:property_getName(props[i])
encoding:NSUTF8StringEncoding];
block(props[i], name);
[name release];
}
free(props);
}
-(void)addObserver:(NSObject *)observer
options:(NSKeyValueObservingOptions)options
context:(void *)context
{
[self forEachProperty:^(objc_property_t prop, NSString *name) {
[self addObserver:observer
forKeyPath:name
options:options
context:context];
}];
}
-(void)removeObserver:(id)observer {
[self forEachProperty:^(objc_property_t prop, NSString *name) {
[self removeObserver:observer forKeyPath:name];
}];
}
#end

Resources