Latest 1.2.0
Homepage https://github.com/ThePantsThief/MirrorKit
License MIT
Platforms ios 7.0, osx 10.8, requires ARC
Authors

CI Status
Version
License
Platform

Inspired by Swift’s MirrorType and MAObjcRuntime, this framework aims to simplify working with the Objective-C runtime and offer a simple way to reflect classes and objects.

Installation

MirrorKit is available through CocoaPods. To install
it, simply add the following line to your Podfile:

pod "MirrorKit"

Usage

Documentation for MirrorKit is on Cocoadocs.

#import "MirrorKit.h"
...

XZYObject *foo = [[XZYObject alloc] initWithBar:bar];
MKMirror *reflection = [MKMirror reflect:foo]; // works for classes too

// Get a list of foo's properties, retrieve information about a property
NSArray *properties = reflection.properties;
MKProperty *property = properties.firstObject;
NSString *propertyName = property.name;
BOOL readwrite = !property.isReadOnly;

// Discover all loaded subclasses of any class!
NSArray *subclasses = [NSDictionary allSubclasses];
NSLog(subclasses); // 20+ classes... wow

Here’s where the real fun begins. Let’s create a class at runtime:

// Start here by naming it. Your class will implicitly inherit from NSObject.
MKClassBuilder *builder = [MKClassBuilder allocateClass:@"NSAtom"];

// Create and add IVars...
MKIVarBuilder *nameIvar name:@"_name" size:sizeof(id) alignment:log2(sizeof(id)) typeEncoding:@(@encode(id))];
MKIVarBuilder *lengthIvar = [MKIVarBuilder name:@"_length" size:sizeof(NSUInteger) alignment:log2(sizeof(NSUInteger)) typeEncoding:@(@encode(NSUInteger))];
[builder addIVars:@[nameIvar, lengthIvar]];

// Create some methods...
NSString *initTypes  = [NSString stringWithFormat:@"%s%s%s", @encode(id), @encode(id), @encode(SEL)];
NSString *fooTypes   = [NSString stringWithFormat:@"%s%s%s%s", @encode(void), @encode(id), @encode(SEL), @encode(id)];
MKSimpleMethod *init = [MKSimpleMethod buildMethodNamed:@"init" withTypes:initTypes implementation:imp_implementationWithBlock(^(id self) {
self = [super init];
if (self) {
NSUInteger len = 5;
[self setIVarByName:lengthIvar.name value:&len size:sizeof(len)];
[self setIVarByName:nameIvar.name object:@"ThePantsThief"];
NSLog(@"Called init");
}
return self;
})];
MKSimpleMethod *fooMethod = [MKSimpleMethod buildMethodNamed:@"foo:" withTypes:fooTypes implementation:imp_implementationWithBlock(^(id self, id someObject) {
NSLog(@"-[%@ foo:] %lu: %@", NSStringFromClass([self class]), [self length], [self name], [someObject description]);
})];

// Create some property attributes, using either MKMutablePropertyAttributes or a dictionary to create an MKPropertyAttributes object
MKMutablePropertyAttributes *nameAttributes = [MKMutablePropertyAttributes attributes];
nameAttributes.isReadOnly  = YES;
nameAttributes.backingIVar = nameIvar.name;
[nameAttributes setTypeEncodingChar:MKTypeEncodingObjcObject];
NSDictionary *lengthAttributesDict = @{MKPropertyAttributeKeyNonAtomic:       @YES,
MKPropertyAttributeKeyTypeEncoding:    [NSString stringWithFormat:@"%c", (char)MKTypeEncodingUnsignedLongLong],
MKPropertyAttributeKeyBackingIVarName: lengthIvar.name};
MKPropertyAttributes *lengthAttributes = [MKPropertyAttributes attributesFromDictionary:lengthAttributesDict];

// Initialize some properties with those attributes...
MKProperty *nameProperty   = [MKProperty propertyWithName:@"name" attributes:nameAttributes];
MKProperty *lengthProperty = [MKProperty propertyWithName:@"length" attributes:lengthAttributes];
// Properties need getters and setters! These aren't too straightforward, sadly.
// Casting is necessary. These macros make it kinda simple.
MKSimpleMethod *getName   = MKPropertyGetter(pName, id __strong);
MKSimpleMethod *getLength = MKPropertyGetter(pLength, NSUInteger);
MKSimpleMethod *setLength = MKPropertySetter(pLength, NSUInteger);

// Add the methods, and properties
[builder addMethods:@[init, fooMethod, getName, getLength, setLength]];
[builder addProperties:@[nameProperty, lengthProperty]];

// Register the class and create an instance of it!
Class myClass = [builder registerClass];
id myAtom     = [myClass new];

To-do

  • Finish testing
  • Add OS X demo

Author

Tanner Bennett, [email protected]

License

MirrorKit is available under the MIT license. See the LICENSE file for more info.

Latest podspec

{
    "name": "MirrorKit",
    "version": "1.2.0",
    "summary": "A library for reflection in Objectice-C.",
    "homepage": "https://github.com/ThePantsThief/MirrorKit",
    "license": "MIT",
    "authors": {
        "ThePantsThief": "[email protected]"
    },
    "source": {
        "git": "https://github.com/ThePantsThief/MirrorKit.git",
        "tag": "1.2.0"
    },
    "social_media_url": "https://twitter.com/ThePantsThief",
    "requires_arc": true,
    "platforms": {
        "ios": "7.0",
        "osx": "10.8"
    },
    "source_files": [
        "Pod/**/*",
        "Pod/*"
    ]
}

Pin It on Pinterest

Share This