Objective-C data records made easy.
magic-property generates immutable Objective-C classes with init, copy, isEqual, hash, and description methods from a simple header file with just a list of properties.
- Automatically generates immutable Objective-C classes
- correct
isEqual:
andhash
implementation - init, new and copy methods for/with all properties
description
method with human-readable output- all property attributes (e.g. nonatomic, strong) supported
- ARC support
- NSCopying, NSCoding and NSSecureCoding support
- support for extra method implementations and custom property setters and accessors
- support for custom typedefs and enums
- support for generating correct
isEqual:
,hash
, anddescription
for handwritten classes - no special compiler features needed
A simple header like this is enough to generate the immutable Objective-C class:
#import <Foundation/Foundation.h>
#import "Address.h"
@interface PhonebookEntry : NSObject
@property (nonatomic, strong, readonly) NSString *name;
@property (nonatomic, strong, readonly) NSString *email;
@property (nonatomic, strong, readonly) NSArray *phoneNumbers;
@property (nonatomic, strong, readonly) NSString *birthday;
@property (nonatomic, strong, readonly) Address *address;
@end
Just process the header file with the magic-property script and the actual class header and implementation file will be generated by the script.
magic-property expands the interface to the code shown below.
The generated code in the .m file also contains meaningful
implementations of isEqual:
, hash
, and description
.
// added support for NSCopying and NSCoding
@interface PhonebookEntry : NSObject <NSCopying, NSCoding>
@property (nonatomic, strong, readonly) NSString *name;
@property (nonatomic, strong, readonly) NSString *email;
@property (nonatomic, strong, readonly) NSArray *phoneNumbers;
@property (nonatomic, strong, readonly) NSString *birthday;
@property (nonatomic, strong, readonly) Address *address;
// added init and new methods
- (id)initWithName:(NSString *)name
email:(NSString *)email
phoneNumbers:(NSArray *)phoneNumbers
birthday:(NSString *)birthday
address:(Address *)address;
+ (PhonebookEntry *)newWithName:(NSString *)name
email:(NSString *)email
phoneNumbers:(NSArray *)phoneNumbers
birthday:(NSString *)birthday
address:(Address *)address;
// copy methods for all properties.
- (PhonebookEntry *)copyWithName:(NSString *)name;
- (PhonebookEntry *)copyWithEmail:(NSString *)email;
- (PhonebookEntry *)copyWithPhoneNumbers:(NSArray *)phoneNumbers;
- (PhonebookEntry *)copyWithBirthday:(NSString *)birthday;
- (PhonebookEntry *)copyWithAddress:(Address *)address;
// meaningful implementations of isEqual:, hash, and description
// are placed in the .m file
@end
The magic-property script supports the following commandline options, see below for Xcode integration.
usage: magic-property [-h] -o DIR [--no-arc] [--force] [--custom-ints FILE]
[--enums FILE] [--only-eq-hash-description]
[--eq-hash-description-outfile FILE]
[--eq-hash-macro-base-name NAME]
[--description-macro-base-name NAME]
[--eq-hash-description-macro-base-name NAME]
[INPUT_FILE [INPUT_FILE ...]]
Objective-C data records made easy
positional arguments:
INPUT_FILE input files for case-class generation (.h and .m
files)
optional arguments:
-h, --help show this help message and exit
-o DIR, --output-dir DIR
output directory
--no-arc generate code without ARC support
--force force code generation
--custom-ints FILE file with custom integer types (newline separated)
--enums FILE file with enum definitions
--only-eq-hash-description
generate only the IsEqualHashDescription macros
--eq-hash-description-outfile FILE
output file for the IsEqualHashDescription macros,
default: MPEqHashDescription.h
--eq-hash-macro-base-name NAME
basename for the IsEqualHash macro, default:
MPGenerateIsEqualHash
--description-macro-base-name NAME
basename for the Description macro, default:
MPGenerateDescription
--eq-hash-description-macro-base-name NAME
basename for the IsEqualHashDescription macro,
default: MPGenerateIsEqualHashDescription
magic-property can use custom and extra methods to override the default behavior. Simply add the methods to override or to add in an m-file. There is no need to manually add any of the generated methods.
@implementation PhonebookEntry
+ (PhonebookEntry *)parseFromString:(NSString *)
{
... // the method is added to the final class by the script
}
- (NSString *)serializeToString
{
... // this becomes a method of the immutable class
}
@end
TODO
magic-property also simplifies definition of enumeration types. To define
an enumeration type NetworkState
with two states Offline
and Online
,
just place the following line in some file and pass the file to magic-property
via the --enums
flag.
NetworkState: Offline Online
magic-property then generates the following .h file and a suitable .m file:
// the definition of the enumeration
typedef enum {
NetworkStateOffline = 1,
NetworkStateOnline = 2,
} NetworkState;
// a function for converting enum values to strings
NSString *stringFromNetworkState(NetworkState x);
// support for meaningful description methods if the enumeration type is used
// in a property in classes processed by magic-property (see below under "Custom Integers")
@interface MPIntegerNetworkState : MPInteger
+ (NSString *)descriptionOf:(NSInteger)i;
@end
TODO
magic-property can be used as standalone script but XCode integration can be setup with these simple steps:
Copy the scripts
folder to your project.
Create a folder where the generated code will be placed (e.g. gen
) and a folder
where all your property header files will go (e.g. property-classes
). Place the
property header files (*.h) you want to use to this folder.
Add a "Run script" build phase to XCode.
Make sure the script build phase is before compiling sources and add the following code:
scripts/magic-property -o gen property-classes/*.h property-classes/*.m
Make sure to change the paths to the correct location you chose for the
magic-property script, generated code folder and input folder. Add the
property-classes/*.m
argument only if you have at least one .m
file in
property-classes
.
Add the files from the objective-c
folder to your project. Build your project
once. The build will generate all the necessary files from your property class
headers. Add the generated headers and implementation files to your XCode
project. Note that you have to add the files again for each new property class
header file you create, but not if you change the contents of a property header
file.