Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save beccadax/5098807 to your computer and use it in GitHub Desktop.
Save beccadax/5098807 to your computer and use it in GitHub Desktop.
Property list serialization protocol/category. This allows you to easily make an NSObject subclass generate a plist version of itself, or initialize itself from a plist. Simply conform to the TsPropertyListRepresentation protocol and call the +includeKeyInPropertyListRepresentation:... methods at an appropriate time, such as an +initialize metho…
//
// NSObject+TsPropertyListRepresentation.h
// PressKit
//
// Created by Brent Royal-Gordon on 3/6/13.
// Copyright (c) 2013 Novelty Publishers. All rights reserved.
//
#import <Foundation/Foundation.h>
@protocol TsPropertyListRepresentation <NSObject>
// These all automatically become available to NSObject subclasses which conform to this protocol.
@optional
- (id)initWithPropertyListRepresentation:(NSDictionary*)rep;
@property (readonly) NSDictionary* propertyListRepresentation;
- (instancetype)willInitWithPropertyListRepresentation:(NSDictionary*)rep;
- (instancetype)didInitWithPropertyListRepresentation:(NSDictionary*)rep;
// Call these from a +initialize method
+ (void)includeKeyInPropertyListRepresentation:(NSString*)key;
+ (void)includeKeyInPropertyListRepresentation:(NSString*)key withValueTransformer:(NSValueTransformer*)transformer;
+ (void)includeKeyInPropertyListRepresentation:(NSString*)key withValueTransformer:(NSValueTransformer*)transformer propertyListKey:(NSString*)plistKey;
@end
//
// NSObject+TsPropertyListRepresentation.m
// PressKit
//
// Created by Brent Royal-Gordon on 3/6/13.
// Copyright (c) 2013 Novelty Publishers. All rights reserved.
//
#import "NSObject+TsPropertyListRepresentation.h"
#import <objc/runtime.h>
@interface TsNoOpValueTransformer : NSValueTransformer @end
@implementation NSObject (TsPropertyListRepresentation)
+ (NSMutableDictionary*)ts_propertyListRepresentationKeysForThisClassOnly {
NSMutableDictionary * dict = objc_getAssociatedObject(self, _cmd);
if(!dict) {
dict = [NSMutableDictionary new];
objc_setAssociatedObject(self, _cmd, dict, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
return dict;
}
+ (NSDictionary*)ts_propertyListRepresentationKeys {
NSMutableDictionary * dict = ([self.superclass ts_propertyListRepresentationKeys] ?: @{}).mutableCopy;
[dict addEntriesFromDictionary:[self ts_propertyListRepresentationKeysForThisClassOnly]];
return dict;
}
+ (void)includeKeyInPropertyListRepresentation:(NSString*)key withValueTransformer:(NSValueTransformer*)transformer propertyListKey:(NSString *)plistKey {
if(![self conformsToProtocol:@protocol(TsPropertyListRepresentation)]) {
[self doesNotRecognizeSelector:_cmd];
}
[self ts_propertyListRepresentationKeysForThisClassOnly][key] = @{ @"plistKey": plistKey, NSValueTransformerBindingOption: transformer ?: [TsNoOpValueTransformer new] };
}
+ (void)includeKeyInPropertyListRepresentation:(NSString*)key withValueTransformer:(NSValueTransformer *)transformer {
[self includeKeyInPropertyListRepresentation:key withValueTransformer:transformer propertyListKey:key];
}
+ (void)includeKeyInPropertyListRepresentation:(NSString*)key {
[self includeKeyInPropertyListRepresentation:key withValueTransformer:nil];
}
- (id)initWithPropertyListRepresentation:(NSDictionary*)plist {
if(![self conformsToProtocol:@protocol(TsPropertyListRepresentation)]) {
[self doesNotRecognizeSelector:_cmd];
return nil;
}
if((self = [self init])) {
self = [self willInitWithPropertyListRepresentation:plist];
for(NSString * key in [self.class ts_propertyListRepresentationKeys]) {
NSDictionary * info = [self.class ts_propertyListRepresentationKeys][key];
id value = plist[info[@"plistKey"]];
if(!value) {
continue;
}
value = [info[NSValueTransformerBindingOption] reverseTransformedValue:value];
[self setValue:value forKey:key];
}
self = [self didInitWithPropertyListRepresentation:plist];
}
return self;
}
- (instancetype)willInitWithPropertyListRepresentation:(NSDictionary*)rep { return self; }
- (instancetype)didInitWithPropertyListRepresentation:(NSDictionary*)rep { return self; }
- (NSDictionary*)propertyListRepresentation {
if(![self conformsToProtocol:@protocol(TsPropertyListRepresentation)]) {
[self doesNotRecognizeSelector:_cmd];
return nil;
}
NSMutableDictionary * plist = [NSMutableDictionary new];
for(NSString * key in [self.class ts_propertyListRepresentationKeys]) {
NSDictionary * info = [self.class ts_propertyListRepresentationKeys][key];
id value = [self valueForKey:key];
value = [info[NSValueTransformerBindingOption] transformedValue:value];
if(!value) {
continue;
}
plist[info[@"plistKey"]] = value;
}
return plist.copy;
}
@end
@implementation TsNoOpValueTransformer
+ (BOOL)allowsReverseTransformation {
return YES;
}
- (id)transformedValue:(id)value {
return value;
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment