# iOS-Demo 项目及注入方式
在接触iOS
一年多之后,明显感觉到, Objc
带有一种青黄不接的感觉。一方面市面上的大多数app基于Swift
构建,另一方面在国内,大型的 App 还在继续使用 Objc
构建, 团队中的 iOS 新人对于 iOS 开发的兴趣稍显欠缺,因此萌生了些一个 Demo App , 用来方便地构建 Demo,来做各种各样的演示。
- Project Repository : https://github.com/butub1/iOS-Demo (opens new window)
# 1. 需求
需求很简单:方便地构建 ViewController
- 要方便书写,避免重复劳动,避免如下情况:
#import "SceneDelegate.h" #import "DMBaseViewController.h" #import "BDMSyntaxController.h" #import "VerticalSlidingViewController.h" #import "DMHitTestViewController.h" #import "DMCollectionViewDragViewController.h" #import "DMLayoutViewController.h" #import "DMPassThroughViewController.h" #import "DMSampleViewController.h"
1
2
3
4
5
6
7
8
9 - 要有说明文字,要有 icon、author、hyperlink
- 要易于检索,搞个简单的搜索的VC, 方便跳转
- 要解耦,或者容易修改,上述的信息,在注入后,要能容易拿取到。
# 2. 设计
因为不想分散多处写注入代码, 最好是能像注解一样,只做一个操作,就注入。
@registerItem("Sample.Button.Basic")
@interface DMSampleViewController
@end
1
2
3
2
3
但是在 Objc 中,确实没有找到比较方便的实现,但是又非常想要这种效果。考虑过几种实现:
VC 继承的方式进行注入 --> Objc 不能多继承, 限制了 Demo 的能力
接口注入到全局 mountArray --> 添加操作需要运行时完成,否则需要静态注入。
/// in mount file
static NSArray<id<DMInjectProtocol>> *mountArray = @[
[DMSampleViewController class],
]
/// in DMSampleViewController.m
@interface DMSampleViewController()<DMInjectProtocol>
@end
1
2
3
4
5
6
7
2
3
4
5
6
7
因此不得不找些运行时注入的方式,或者编译预处理的操作,考虑过
- LazyRegister, 注入函数指针到 data 段,会在 section 引入的时候注入,运行时机可选。
- load 方法, 运行时机在 main 函数之前,但是需要写 C 方法。
- Category 运行时注入,生成特定函数,但是 Demo 多了之后,会生成很多小Category.
【Selected】
因为是 demo 项目,没有必要过度设计,所以选择了简单的方式实现,遇到问题再优化。
# 3. 实现
dm_registerDemo 宏 最终生成”一条分类“,一条 : ) 合乎文法 : )
@interface DMRegisterCenter( DMSampleViewController ) - (void)user_registerItemsFor_DMSampleViewController;@end; @implementation DMRegisterCenter( DMSampleViewController ) - (void)user_registerItemsFor_DMSampleViewController{ [self registerClass:@"DMSampleViewController" withBlock:^(DMRegisterItem *item) { { item.identifier = @"Sample.UIButton";} }]; }@end
1
我很喜欢这个 tricky 的实现
在 RegisterCenter 中会去遍历自己的实例方法,找到用户注入的方法(@user_ 开头)
- (void)loadAllItemsFromCategories
{
unsigned int count;
Method *methods = class_copyMethodList([self class], &count);
for (int i = 0; i < count; i++) {
SEL methodSelector = method_getName(methods[i]);
NSString *methodName = [NSString stringWithUTF8String:sel_getName(methodSelector)];
if ([methodName hasPrefix:@"user_"]) {
[self performSelector:methodSelector];
}
}
free(methods);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
# 4. 使用
这就很简单了, 引入宏,注册想要注册的ViewController
#import "DMSampleViewController.h"
// 1. import Macros
#import "DMMacros.h"
// 2. register an item corresponding to your view controller
dm_registerDemo(DMSampleViewController, {
item.identifier = @"Sample.UIButton"; // identifier required
})
// 3. enjoy coding with this view controller :)
@interface DMSampleViewController ()
@end
@implementation DMSampleViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor greenColor];
}
@end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
然后做一个简单的table list
, 获取所有以同样方式注册进来的VC,点击切换。