Using a custom setter with @property and @synthesize

In the last example, I replaced getter / setter code with auto-generated code. Unfortunately, I lost the ability to ensure that the Gas Can is not filled beyond capacity. To keep this limitation in place, I'd like to use the auto-generated getter, but create a custom setter.

To achieve this, two things are required:

  1. Specify that the property named level is marked nonatomic
  2. Uncomment the setter

To achieve item 1, add the nonatomic property to the code as follows:

  1. @property (nonatomic) float level;

(The details of being nonatomic are beyond the scope of this session, but at a high level, this means that multi-threaded apps can't be guaranteed to avoid a racing condition.)

To achieve item 2, simply uncomment the code.

  1. -(void)setLevel: (float)l {
  2. level = (l > size) ? size : l;
  3. }

Now, in the main program, attempt to add 7.2 gallons of gas into the can:

  1. #include "GasCan.h"
  2.  
  3. int main(int argc, char * argv[]) {
  4. @autoreleasepool {
  5. GasCan *gc = [[GasCan alloc] init];
  6. [gc setLevel:7.2];
  7. NSString *message = @"The level in your gas can is: ";
  8. NSLog(@"%@ %f",message, gc.level);
  9.  
  10. [gc pourContents];
  11.  
  12. [gc openSpout:true andValve:false];
  13.  
  14. [gc pourContents];
  15.  
  16. NSLog(@"%@ %f",message, [gc level]);
  17. }
  18. }

When the program is run, you'll see the following line:

  1. 2012-09-12 11:56:40.943 GasCan[992:303] The level in your gas can is: 5.000000

The supporting setter logic has been successfully invoked.

(Note: In general, it's probably best to implement both the setter and getter, or to auto-generate both of them. However, if you find the need to do one and not the other, you now know how to do it.)