Skip to content

Commit

Permalink
add protocols
Browse files Browse the repository at this point in the history
  • Loading branch information
Randy Becker committed Sep 25, 2010
2 parents 37d6bc9 + 73735e9 commit 59372db
Show file tree
Hide file tree
Showing 8 changed files with 203 additions and 3 deletions.
3 changes: 3 additions & 0 deletions MARTNSObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#import <Foundation/Foundation.h>


@class RTProtocol;
@class RTIvar;
@class RTProperty;
@class RTMethod;
Expand All @@ -20,6 +21,8 @@
+ (Class)rt_setSuperclass: (Class)newSuperclass;
+ (size_t)rt_instanceSize;

+ (NSArray *)rt_protocols;

+ (NSArray *)rt_methods;
+ (RTMethod *)rt_methodForSelector: (SEL)sel;

Expand Down
14 changes: 14 additions & 0 deletions MARTNSObject.m
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#import <objc/runtime.h>

#import "RTProtocol.h"
#import "RTIvar.h"
#import "RTProperty.h"
#import "RTMethod.h"
Expand Down Expand Up @@ -80,6 +81,19 @@ + (size_t)rt_instanceSize
return class_getInstanceSize(self);
}

+ (NSArray *)rt_protocols
{
unsigned int count;
Protocol **protocols = class_copyProtocolList(self, &count);

NSMutableArray *array = [NSMutableArray array];
for(unsigned i = 0; i < count; i++)
[array addObject: [RTProtocol protocolWithObjCProtocol: protocols[i]]];

free(protocols);
return array;
}

+ (NSArray *)rt_methods
{
unsigned int count;
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
all: tests

tests:
gcc -framework Foundation --std=c99 main.m MARTNSObject.m RTMethod.m RTIvar.m RTProperty.m RTUnregisteredClass.m
gcc -framework Foundation --std=c99 main.m MARTNSObject.m RTProtocol.m RTMethod.m RTIvar.m RTProperty.m RTUnregisteredClass.m

clean:
rm -f a.out
23 changes: 23 additions & 0 deletions RTProtocol.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@

#import <Foundation/Foundation.h>
#import <objc/runtime.h>


@interface RTProtocol : NSObject
{
}

+ (NSArray *)allProtocols;

+ (id)protocolWithObjCProtocol: (Protocol *)protocol;
+ (id)protocolWithName: (NSString *)name;

- (id)initWithObjCProtocol: (Protocol *)protocol;
- (id)initWithName: (NSString *)name;

- (Protocol *)objCProtocol;
- (NSString *)name;
- (NSArray *)incorporatedProtocols;
- (NSArray *)methodsRequired: (BOOL)isRequiredMethod instance: (BOOL)isInstanceMethod;

@end
122 changes: 122 additions & 0 deletions RTProtocol.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@

#import "RTProtocol.h"
#import "RTMethod.h"


@interface _RTObjCProtocol : RTProtocol
{
Protocol *_protocol;
}
@end

@implementation _RTObjCProtocol

- (id)initWithObjCProtocol: (Protocol *)protocol
{
if((self = [self init]))
{
_protocol = protocol;
}
return self;
}

- (Protocol *)objCProtocol
{
return _protocol;
}

@end

@implementation RTProtocol

+ (NSArray *)allProtocols
{
unsigned int count;
Protocol **protocols = objc_copyProtocolList(&count);

NSMutableArray *array = [NSMutableArray array];
for(unsigned i = 0; i < count; i++)
[array addObject: [[[self alloc] initWithObjCProtocol: protocols[i]] autorelease]];

free(protocols);
return array;
}

+ (id)protocolWithObjCProtocol: (Protocol *)protocol
{
return [[[self alloc] initWithObjCProtocol: protocol] autorelease];
}

+ (id)protocolWithName: (NSString *)name
{
return [[[self alloc] initWithName: name] autorelease];
}

- (id)initWithObjCProtocol: (Protocol *)protocol
{
[self release];
return [[_RTObjCProtocol alloc] initWithObjCProtocol: protocol];
}

- (id)initWithName: (NSString *)name
{
return [self initWithObjCProtocol:objc_getProtocol([name cStringUsingEncoding:[NSString defaultCStringEncoding]])];
}

- (NSString *)description
{
return [NSString stringWithFormat: @"<%@ %p: %@>", [self class], self, [self name]];
}

- (BOOL)isEqual: (id)other
{
return [other isKindOfClass: [RTProtocol class]] &&
[[self objCProtocol] isEqual: [other objCProtocol]];
}

- (NSUInteger)hash
{
return [[self objCProtocol] hash];
}

- (Protocol *)objCProtocol
{
[self doesNotRecognizeSelector: _cmd];
return nil;
}

- (NSString *)name
{
return [NSString stringWithUTF8String: protocol_getName([self objCProtocol])];
}

- (NSArray *)incorporatedProtocols
{
unsigned int count;
Protocol **protocols = protocol_copyProtocolList([self objCProtocol], &count);

NSMutableArray *array = [NSMutableArray array];
for(unsigned i = 0; i < count; i++)
[array addObject: [RTProtocol protocolWithObjCProtocol: protocols[i]]];

free(protocols);
return array;
}

- (NSArray *)methodsRequired: (BOOL)isRequiredMethod instance: (BOOL)isInstanceMethod
{
unsigned int count;
struct objc_method_description *methods = protocol_copyMethodDescriptionList([self objCProtocol], isRequiredMethod, isInstanceMethod, &count);

NSMutableArray *array = [NSMutableArray array];
for(unsigned i = 0; i < count; i++)
{
NSString *signature = [NSString stringWithCString: methods[i].types encoding: [NSString defaultCStringEncoding]];
[array addObject: [RTMethod methodWithSelector: methods[i].name implementation: NULL signature: signature]];
}

free(methods);
return array;
}

@end
2 changes: 2 additions & 0 deletions RTUnregisteredClass.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#import <Foundation/Foundation.h>


@class RTProtocol;
@class RTIvar;
@class RTMethod;

Expand All @@ -14,6 +15,7 @@

- (id)initWithClass: (Class)c;

- (void)addProtocol: (RTProtocol *)protocol;
- (void)addIvar: (RTIvar *)ivar;
- (void)addMethod: (RTMethod *)method;

Expand Down
6 changes: 6 additions & 0 deletions RTUnregisteredClass.m
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@

#import "RTUnregisteredClass.h"

#import "RTProtocol.h"
#import "RTIvar.h"
#import "RTMethod.h"

Expand All @@ -21,6 +22,11 @@ - (id)initWithClass: (Class)c
return self;
}

- (void)addProtocol: (RTProtocol *)protocol
{
class_addProtocol(_class, [protocol objCProtocol]);
}

- (void)addIvar: (RTIvar *)ivar
{
const char *typeStr = [[ivar typeEncoding] UTF8String];
Expand Down
34 changes: 32 additions & 2 deletions main.m
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// gcc -framework Foundation --std=c99 main.m MARTNSObject.m RTMethod.m RTIvar.m RTProperty.m RTUnregisteredClass.m
// gcc -framework Foundation --std=c99 main.m MARTNSObject.m RTProtocol.m RTMethod.m RTIvar.m RTProperty.m RTUnregisteredClass.m

#import "MARTNSObject.h"
#import "RTProtocol.h"
#import "RTIvar.h"
#import "RTProperty.h"
#import "RTMethod.h"
Expand Down Expand Up @@ -154,16 +155,44 @@ static void TestSetMethod(void)
[obj release];
}

@interface SampleClass : NSObject
@protocol SampleProtocol <NSObject>
+ (void)requiredClassMethod;
- (void)requiredInstanceMethod;
@optional
+ (void)optionalClassMethod;
- (void)optionalInstanceMethod;
@end
@interface SampleClass : NSObject <SampleProtocol>
{
id someIvar;
}
@property (assign, getter=customGetter) id someProperty;
@end
@implementation SampleClass
@synthesize someProperty=someIvar;
+ (void)requiredClassMethod
{
return;
}
- (void)requiredInstanceMethod
{
return;
}
@end

static void TestProtocolQuery(void)
{
NSArray *protocols = [SampleClass rt_protocols];
TEST_ASSERT([[protocols valueForKey: @"name"] containsObject: @"SampleProtocol"]);

Protocol *protocol = [RTProtocol protocolWithObjCProtocol: NSProtocolFromString(@"SampleProtocol")];
TEST_ASSERT([[protocol incorporatedProtocols] containsObject: [RTProtocol protocolWithObjCProtocol: NSProtocolFromString(@"NSObject")]]);
TEST_ASSERT([[[protocol methodsRequired: YES instance: YES] valueForKey: @"selectorName"] containsObject: @"requiredInstanceMethod"]);
TEST_ASSERT([[[protocol methodsRequired: YES instance: NO] valueForKey: @"selectorName"] containsObject: @"requiredClassMethod"]);
TEST_ASSERT([[[protocol methodsRequired: NO instance: YES] valueForKey: @"selectorName"] containsObject: @"optionalInstanceMethod"]);
TEST_ASSERT([[[protocol methodsRequired: NO instance: NO] valueForKey: @"selectorName"] containsObject: @"optionalClassMethod"]);
}

static void TestIvarQuery(void)
{
NSArray *ivars = [SampleClass rt_ivars];
Expand Down Expand Up @@ -281,6 +310,7 @@ int main(int argc, char **argv)
TEST(TestAddMethod);
TEST(TestMethodFetching);
TEST(TestSetMethod);
TEST(TestProtocolQuery);
TEST(TestIvarQuery);
TEST(TestPropertyQuery);
TEST(TestIvarAdd);
Expand Down

0 comments on commit 59372db

Please sign in to comment.