Skip to content

Commit

Permalink
complete project
Browse files Browse the repository at this point in the history
  • Loading branch information
GodL committed Dec 9, 2019
1 parent 4d3d73a commit 68d8842
Show file tree
Hide file tree
Showing 8 changed files with 130 additions and 19 deletions.
12 changes: 12 additions & 0 deletions ProtocolInjection/ProtocolInjection.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
C96A20B9239CF5A40011D5DC /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C96A20B7239CF5A40011D5DC /* LaunchScreen.storyboard */; };
C96A20BC239CF5A40011D5DC /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = C96A20BB239CF5A40011D5DC /* main.m */; };
C96A20C8239D16D60011D5DC /* ProtocolInjection.m in Sources */ = {isa = PBXBuildFile; fileRef = C96A20C7239D16D60011D5DC /* ProtocolInjection.m */; };
C96A20CB239E163B0011D5DC /* Runnable.m in Sources */ = {isa = PBXBuildFile; fileRef = C96A20CA239E163B0011D5DC /* Runnable.m */; };
C96A20CE239E1A110011D5DC /* ViewController+Injection.m in Sources */ = {isa = PBXBuildFile; fileRef = C96A20CD239E1A110011D5DC /* ViewController+Injection.m */; };
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
Expand All @@ -32,6 +34,10 @@
C96A20BB239CF5A40011D5DC /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
C96A20C6239D16D60011D5DC /* ProtocolInjection.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ProtocolInjection.h; sourceTree = "<group>"; };
C96A20C7239D16D60011D5DC /* ProtocolInjection.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ProtocolInjection.m; sourceTree = "<group>"; };
C96A20C9239E161D0011D5DC /* Runnable.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Runnable.h; sourceTree = "<group>"; };
C96A20CA239E163B0011D5DC /* Runnable.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Runnable.m; sourceTree = "<group>"; };
C96A20CC239E1A110011D5DC /* ViewController+Injection.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ViewController+Injection.h"; sourceTree = "<group>"; };
C96A20CD239E1A110011D5DC /* ViewController+Injection.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "ViewController+Injection.m"; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -71,6 +77,10 @@
C96A20AD239CF5A10011D5DC /* SceneDelegate.m */,
C96A20AF239CF5A10011D5DC /* ViewController.h */,
C96A20B0239CF5A10011D5DC /* ViewController.m */,
C96A20CC239E1A110011D5DC /* ViewController+Injection.h */,
C96A20CD239E1A110011D5DC /* ViewController+Injection.m */,
C96A20C9239E161D0011D5DC /* Runnable.h */,
C96A20CA239E163B0011D5DC /* Runnable.m */,
C96A20B2239CF5A10011D5DC /* Main.storyboard */,
C96A20B5239CF5A40011D5DC /* Assets.xcassets */,
C96A20B7239CF5A40011D5DC /* LaunchScreen.storyboard */,
Expand Down Expand Up @@ -159,11 +169,13 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
C96A20CB239E163B0011D5DC /* Runnable.m in Sources */,
C96A20B1239CF5A10011D5DC /* ViewController.m in Sources */,
C96A20AB239CF5A10011D5DC /* AppDelegate.m in Sources */,
C96A20C8239D16D60011D5DC /* ProtocolInjection.m in Sources */,
C96A20BC239CF5A40011D5DC /* main.m in Sources */,
C96A20AE239CF5A10011D5DC /* SceneDelegate.m in Sources */,
C96A20CE239E1A110011D5DC /* ViewController+Injection.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,26 @@
//

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

#define injectionable \
+ (void)load { \
pi_classInjected(self); \
}

void protocolInjectionAdded(Protocol *protocol,Class containerClass);
#define injection optional;

void classInjected(Class injectionClass);
#define injectprotocol(NAME) \
interface NAME ## _ProtocolInjectionContainer : NSObject < NAME \
> {} \
@end \
@implementation NAME ## _ProtocolInjectionContainer \
+ (void)load { \
pi_protocolInjectionAdded(objc_getProtocol((# NAME )),self); \
}

void injection(void);
void pi_protocolInjectionAdded(Protocol *protocol,Class containerClass);

void pi_classInjected(Class injectionClass);

void pi_injection(void);
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,20 @@
//

#import "ProtocolInjection.h"
@import ObjectiveC.runtime;
@import ObjectiveC.message;
#import <CoreFoundation/CoreFoundation.h>

__attribute__((constructor)) static void ProtocolInject (void) {
pi_injection();
}

static CFMutableDictionaryRef restrict injectionProtocols = NULL;

static CFMutableSetRef restrict injectionClasses = NULL;

FOUNDATION_STATIC_INLINE void _injectMethod(Class class,Method method) {
if (class_getInstanceMethod(class, method_getName(method))) {
printf("Errr: Class has a custom imp for thie method %s",sel_getName(method_getName(method)));
printf("Errr: Class has a custom imp for thie method %s %s",sel_getName(method_getName(method)),class_getName(class));
return;
}
class_addMethod(class, method_getName(method), method_getImplementation(method), method_getTypeEncoding(method));
Expand All @@ -29,16 +32,16 @@ static void InjectionClassApplierFunction(const void *value,const void *context)
__unsafe_unretained Protocol **protocols = class_copyProtocolList(class, &count);
for (unsigned int i =0; i<count; i++) {
Protocol *protocol = protocols[i];
if (CFDictionaryContainsKey(injectionProtocols, protocol_getName(protocol))) {
Class containerClass = CFDictionaryGetValue(injectionProtocols, protocol_getName(protocol));
if (CFDictionaryContainsKey(injectionProtocols, (__bridge const void *)([NSString stringWithUTF8String:protocol_getName(protocol)]))) {
Class containerClass = CFDictionaryGetValue(injectionProtocols, (__bridge const void *)([NSString stringWithUTF8String:protocol_getName(protocol)]));
unsigned int count = 0;
Method *instanceMethods = class_copyMethodList(containerClass, &count);
for (unsigned int j=0; j<count; j++) {
_injectMethod(class, instanceMethods[j]);
}
Method *classMethods = class_copyMethodList(object_getClass(containerClass), &count);
for (unsigned int j=0; j<count; j++) {
_injectMethod(object_getClass(containerClass), classMethods[j]);
_injectMethod(object_getClass(class), classMethods[j]);
}
free(instanceMethods);
free(classMethods);
Expand All @@ -47,35 +50,38 @@ static void InjectionClassApplierFunction(const void *value,const void *context)
free(protocols);
}

void protocolInjectionAdded(Protocol *protocol,Class containerClass) {
void pi_protocolInjectionAdded(Protocol *protocol,Class containerClass) {
NSCParameterAssert(protocol);
NSCParameterAssert(containerClass);
if (injectionProtocols == NULL) {
injectionProtocols = CFDictionaryCreateMutable(CFAllocatorGetDefault(), 0, &kCFCopyStringDictionaryKeyCallBacks, NULL);
injectionProtocols = CFDictionaryCreateMutable(CFAllocatorGetDefault(), 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
}

if (CFDictionaryContainsKey(injectionProtocols, protocol_getName(protocol))) {
if (CFDictionaryContainsKey(injectionProtocols, (__bridge const void *)([NSString stringWithUTF8String:protocol_getName(protocol)]))) {
printf("Error: Could not inejct an already injected protocol");
return;
}

CFDictionaryAddValue(injectionProtocols,protocol_getName(protocol), (__bridge const void *)(containerClass));

CFDictionarySetValue(injectionProtocols, (__bridge const void *)([NSString stringWithUTF8String:protocol_getName(protocol)]), (__bridge const void *)(containerClass));
}

void classInjected(Class injectionClass) {
void pi_classInjected(Class injectionClass) {
NSCParameterAssert(injectionClass);
if (!injectionClasses) {
if (injectionClasses == NULL) {
injectionClasses = CFSetCreateMutable(CFAllocatorGetDefault(), 0, &kCFTypeSetCallBacks);
}
if (CFSetContainsValue(injectionClasses, (__bridge const void *)(injectionClass))) {
printf("Eooro: Could not inject an already injected class");
return;
}
CFSetAddValue(injectionClasses, (__bridge const void *)(injectionClass));
CFSetSetValue(injectionClasses, (__bridge const void *)(injectionClass));
}

void injection(void) {
void pi_injection(void) {
if (injectionClasses == NULL) {
printf("There is nothing to inject");
return;
}
CFSetApplyFunction(injectionClasses, (CFSetApplierFunction)&InjectionClassApplierFunction, NULL);
CFRelease(injectionClasses);
CFRelease(injectionProtocols);
Expand Down
23 changes: 23 additions & 0 deletions ProtocolInjection/ProtocolInjection/Runnable.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//
// Runnable.h
// ProtocolInjection
//
// Created by 李浩 on 2019/12/9.
// Copyright © 2019 GodL. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "ProtocolInjection.h"

NS_ASSUME_NONNULL_BEGIN

@protocol Runnable <NSObject>

@injection
+ (Class)runClass;

- (BOOL)canRun;

@end

NS_ASSUME_NONNULL_END
21 changes: 21 additions & 0 deletions ProtocolInjection/ProtocolInjection/Runnable.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//
// Runnable.m
// ProtocolInjection
//
// Created by 李浩 on 2019/12/9.
// Copyright © 2019 GodL. All rights reserved.
//

#import "Runnable.h"

@injectprotocol(Runnable)

+ (Class)runClass {
return self;
}

- (BOOL)canRun {
return YES;
}

@end
16 changes: 16 additions & 0 deletions ProtocolInjection/ProtocolInjection/ViewController+Injection.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// ViewController+Injection.h
// ProtocolInjection
//
// Created by 李浩 on 2019/12/9.
// Copyright © 2019 GodL. All rights reserved.
//
#import "ViewController.h"

NS_ASSUME_NONNULL_BEGIN

@interface ViewController (Injection)

@end

NS_ASSUME_NONNULL_END
16 changes: 16 additions & 0 deletions ProtocolInjection/ProtocolInjection/ViewController+Injection.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// ViewController+Injection.m
// ProtocolInjection
//
// Created by 李浩 on 2019/12/9.
// Copyright © 2019 GodL. All rights reserved.
//

#import "ViewController+Injection.h"
#import "ProtocolInjection.h"

@implementation ViewController (Injection)

injectionable

@end
5 changes: 3 additions & 2 deletions ProtocolInjection/ProtocolInjection/ViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,18 @@
//

#import "ViewController.h"
#import "Runnable.h"

@interface ViewController ()
@interface ViewController ()<Runnable>

@end

@implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"%d %@",self.canRun,[[self class] runClass]);
// Do any additional setup after loading the view.
}


@end

0 comments on commit 68d8842

Please sign in to comment.