MFDynamic eliminates stringly-typed User Defaults, NSCoding boilerplate and more.
MFDynamicDefaults
wraps NSUserDefaults
in a super-nice manner:
- Makes accessing user defaults syntactically lighter (see below).
- Makes setting and retrieving values from the user defaults system type-safe through dynamically-implemented properties.
- Removes the need to create constants for or hard-code user defaults key strings.
- Automatically archives objects that conform to
NSCoding
asNSData
and back for seamless storage in user defaults, including your ownNSCoding
-compatible objects. - No need to manually convert
UIColor
andNSColor
toNSData
and back; it's all done for you. - Some types are transparently converted to human-readable formats and back for storage in User Defaults for easy editing in Plist editors (such as colors and URLs).
- Helps you remember to provide default values in your registered defaults by emitting warnings for missing default values when registering defaults (optional).
Work with User Defaults like this:
[[MYDefaults sharedDefaults] setBackgroundColor:newBackgroundColor];
UIColor *color = [[MYDefaults sharedDefaults] backgroundColor];
... instead of like this:
FOUNDATION_EXPORT static NSString *MYBackgroundColorKey;
...
NSData *colorData = [NSKeyedArchiver archivedDataWithRootObject:color];
[[NSUserDefaults standardUserDefaults] setObject:colorData forKey:MYBackgroundColor];
NSData *colorData = [[NSUserDefaults standardUserDefaults] objectForKey:MYBackgroundColor];
UIColor *color = [NSKeyedUnarchiver unarchiveObjectWithData:colorData];
-
Subclass
MFDynamicDefaults
. -
Define
@dynamic
properties for each user default:Interface
@interface MYAppDefaults : MFDynamicDefaults @property BOOL autoPlayVoiceOver; @property NSTimeInterval loginTimeoutInterval; @property NSDate *lastUpdate; @end
Implementation
@implementation MYAppDefaults @dynamic autoPlayVoiceOver; @dynamic loginTimeoutInterval; @dynamic lastUpdate; @end
-
Use the shared instance of your
MYAppDefaults
class to access user defaults:[[MYDefaults sharedDefaults] setAutoPlayVoiceOver:YES]; BOOL autoPlayVoiceOver = [[MYDefaults sharedDefaults] autoPlayVoiceOver];
Like NSUserDefaults
, MFDynamicDefaults
allows registering defaults from a dictionary:
NSDictionary *defaults = [NSDictionary dictionaryWithContentsOfFile:@"/Path/To/Plist/File"];
[[MYAppDefaults sharedDefaults] registerDefaults:defaults emitMissingDefaultValueWarnings:YES];
By default, MFDynamicDefaults
emits a warning when one of its dynamic properties doesn't have a default value in the registered defaults dictionary. This can help you remember to provide default values for your user defaults. Warnings can be disabled per-property by implementing the -shouldEmitWarningForProperty:
template method in your MFDynamicDefaults
subclass.
MFDynamicStorage
works exactly like MFDynamicDefault
but uses a simple dictionary as its backing store instead of NSUserDefaults
. The main use case for MFDynamicStorage
is a model class that must be stored to disk. Instead of using "normal" synthesized properties and implementing NSCoding
manually (which can be very error-prone and is quite tedious), you simply subclass MFDynamicStorage
and use @dynamic
properties.
-
Subclass
MFDynamicStorage
. -
Define properties that must be archived as
@dynamic
:Interface
@interface MYModelClass : MFDynamicStorage @property UIColor *backgroundColor; @property float brightness; @property NSURL *someURL; @property (copy) NSString *propertyThatWontBeArchived; @end
Implementation
@implementation MYModelClass @dynamic backgroundColor; @dynamic brightness; @dynamic someURL; // Because "propertyThatWontBeArchived" is not defined as @dynamic, // it acts as a normal synthesized property and won't be saved to disk. @end
-
Save and load your objects from disk with zero
NSCoding
boilerplate:[modelClass saveToFile:@"/Users/Michael/Desktop/MyFile"]; MYModelClass *modelClass = [MYModelClass loadFromFile:@"/Users/Michael/Desktop/MyFile"];
- Almost all Objective-C value types are supported. An exception is thrown when a property is of an unsupported type. Feel free to send a pull request if you find that a type you need is missing; support for additional types is exceedingly easy to implement.
- Most property qualifiers (such as
assign
,copy
,weak
andstrong
) are ignored (which is why you don't see them used anywhere in the samples above). The only exception to this rule isreadonly
. If a property is declared asreadonly
, MFDynamicBase won't implement a setter for that property.
When MFDynamic stores objects in its backing store (be it NSUserDefaults
like MFDynamicDefaults
or a simple NSDictionary
like MFDynamicStorage
), it does so by capitalizing the first letter of the property name and using the resulting string as the key:
Property Name | User Defaults Key | Explanation |
---|---|---|
launchAtStartup | LaunchAtStartup | First letter was capitalized (recommended Objective-C style) |
MYSuperPropertyName | MYSuperPropertyName | The key is the same as the property name because the first letter was already capitalized |
MySuperPropertyName | MySuperPropertyName | The key is the same as the property name because the first letter was already capitalized |
MFDynamic is available through CocoaPods, to install it simply add the following line to your Podfile:
pod "MFDynamic"
Michaël Fortin (fortinmike@irradiated.net)
MFDynamic is available under the MIT license. See the LICENSE file for more info.