Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions MMAnonymousClass/MMAnonymousClass.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//
// MMAnonymousClass.h
// Runtime
//
// Created by Anton Bukov on 24.02.15.
// Copyright (c) 2015 Anton Bukov. All rights reserved.
//

#import <Foundation/Foundation.h>

@class MMAnonymousClass;
id MM_ANON(void(^block)(MMAnonymousClass *anon));

@interface MMAnonymousClass : NSObject

+ (MMAnonymousClass *)anonWithBlock:(void(^)(MMAnonymousClass *anon))block;

- (void)addMethod:(SEL)sel fromProtocol:(Protocol *)proto blockImp:(id)block;
- (void)addMethod:(SEL)sel fromClass:(Class)class blockImp:(id)block;

@end
123 changes: 123 additions & 0 deletions MMAnonymousClass/MMAnonymousClass.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
//
// MMAnonymousClass.m
// Runtime
//
// Created by Anton Bukov on 24.02.15.
// Copyright (c) 2015 Anton Bukov. All rights reserved.
//

#import <objc/runtime.h>
#import <objc/message.h>
#import "MMAnonymousClass.h"

id MM_ANON(void(^block)(MMAnonymousClass *anon))
{
return [MMAnonymousClass anonWithBlock:block];
}

@interface MMAnonymousClass ()

@property (nonatomic, strong) NSMutableDictionary *blocks;
@property (nonatomic, strong) NSMutableDictionary *protocols;
@property (nonatomic, strong) NSMutableDictionary *classes;

@end

@implementation MMAnonymousClass

- (NSMutableDictionary *)blocks
{
if (_blocks == nil)
_blocks = [NSMutableDictionary dictionary];
return _blocks;
}

- (NSMutableDictionary *)protocols
{
if (_protocols == nil)
_protocols = [NSMutableDictionary dictionary];
return _protocols;
}

- (NSMutableDictionary *)classes
{
if (_classes == nil)
_classes = [NSMutableDictionary dictionary];
return _classes;
}

- (const char *)typesForSelector:(SEL)sel
{
NSString *protoStr = self.protocols[NSStringFromSelector(sel)];
if (protoStr) {
Protocol *proto = NSProtocolFromString(protoStr);
struct objc_method_description descript = protocol_getMethodDescription(proto, sel, NO, YES);
if (descript.types == nil)
descript = protocol_getMethodDescription(proto, sel, YES, YES);
return descript.types;
}

NSString *classStr = self.classes[NSStringFromSelector(sel)];
if (classStr) {
Class class = NSClassFromString(classStr);
Method method = class_getInstanceMethod(class, sel);
if (method)
return method_getTypeEncoding(method);
}

return nil;
}

#pragma mark - Public Methods

+ (MMAnonymousClass *)anonWithBlock:(void(^)(MMAnonymousClass *anon))block
{
MMAnonymousClass *anon = [[MMAnonymousClass alloc] init];
block(anon);
return anon;
}

- (void)addMethod:(SEL)sel fromProtocol:(Protocol *)proto blockImp:(id)block
{
NSString *selStr = NSStringFromSelector(sel);
self.blocks[selStr] = block;
self.protocols[selStr] = NSStringFromProtocol(proto);
}

- (void)addMethod:(SEL)sel fromClass:(Class)class blockImp:(id)block
{
NSString *selStr = NSStringFromSelector(sel);
self.blocks[selStr] = block;
self.classes[selStr] = NSStringFromClass(class);
}

#pragma mark - Messsage Forwarding

- (BOOL)respondsToSelector:(SEL)aSelector
{
for (NSString *key in self.blocks)
if (NSSelectorFromString(key) == aSelector)
return YES;
return [super respondsToSelector:aSelector];
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
const char *types = [self typesForSelector:aSelector];
return [NSMethodSignature signatureWithObjCTypes:types];
}

- (void)forwardInvocation:(NSInvocation *)anInvocation
{
for (NSString *key in self.blocks) {
if (NSSelectorFromString(key) == anInvocation.selector) {
id block = self.blocks[key];
anInvocation.selector = nil;
[anInvocation invokeWithTarget:block];
return;
}
}
return [super forwardInvocation:anInvocation];
}

@end
41 changes: 18 additions & 23 deletions MMAnonymousClass/NSObject+MMAnonymousClass.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,31 +8,26 @@

#import <Foundation/Foundation.h>

#define MM_DEFAULT_REUSE_ID [NSString stringWithFormat:@"%s_%d", __PRETTY_FUNCTION__, __LINE__]

// Excceptions
extern NSString *const kMMExeptionMethodError;
extern NSString *const kMMExeptionSelector;

// C help functions
extern inline BOOL OVERRIDE(SEL sel, id blockIMP);
extern inline BOOL ADD_METHOD(SEL sel, Protocol *p, id blockIMP);
extern inline BOOL ADD_METHOD_C(SEL sel, Class c, id blockIMP);

// Category
@interface NSObject(MMAnonymousClass)

// MARK: - DEPRECATED!
- (id)modifyMethods:(void(^)())blockOv __attribute__((deprecated));
- (id)addMethod:(SEL)sel fromProtocol:(Protocol *)p isRequired:(BOOL)isReq blockImp:(id)block __attribute__((deprecated));
- (id)overrideMethod:(SEL)sel blockImp:(id)block __attribute__((deprecated));
- (IMP)removeInstanceMethod:(SEL)sel;

// MARK: - Allowed
+ (id)allocAnon:(void(^)())blockOv __attribute__((deprecated));
+ (id)allocAnonWithReuserID:(NSString*)reuseID :(void(^)())blockOv;
+ (id)newInstAnon:(void(^)())blockOv __attribute__((deprecated));
+ (id)newInstAnonWithReuseID:(NSString*)reuseID :(void(^)())blockOv;
+ (Class)anonWithReuserID:(NSString*)reuseID;
#define MM_REUSE [NSString stringWithFormat:@"MMAnonymousClass_%s_%d", __PRETTY_FUNCTION__, __LINE__]

Class MM_CREATE_CLASS(NSString *reuseID, Class superclass, void(^block)(__strong Class class));
Class MM_CREATE_CLASS_ALWAYS(Class superclass, void(^block)(__strong Class class));
id MM_CREATE(NSString *reuseID, void(^block)(__strong Class class));
id MM_CREATE_ALWAYS(void(^block)(__strong Class class));

@interface NSObject (MMAnonymousClass)

+ (Class)subclassWithReuseID:(NSString *)reuseID
configBlock:(void(^)(Class))block;

+ (void)addMethod:(SEL)sel fromProtocol:(Protocol *)proto blockImp:(id)block;
+ (void)addMethod:(SEL)sel fromClass:(Class)class blockImp:(id)block;
+ (void)overrideMethod:(SEL)sel blockImp:(id)block;
+ (void)removeMethod:(SEL)sel __attribute__((deprecated));
+ (void)removeClassMethod:(SEL)sel __attribute__((deprecated));
+ (void)deleteClass;

@end
Loading