Coder Social home page Coder Social logo

ryanleely / tinypart Goto Github PK

View Code? Open in Web Editor NEW
132.0 7.0 14.0 921 KB

TinyPart is an iOS modularization framework implemented by Ojective-C. It also supports URL-routing and inter-module communication. TinyPart是一个由Objective-C编写的面向协议的iOS模块化框架,同时它还支持URL路由和模块间通信机制。

Home Page: https://github.com/RyanLeeLY/TinyPart

License: MIT License

Objective-C 98.50% Ruby 1.50%
objective-c ios objc modular module router url service tinypart registered-services

tinypart's Introduction

TinyPart

Build Status Platform Version License MIT Gmail Twitter

TinyPart is an iOS modularization framework implemented by Ojective-C. It also supports URL-routing and inter-module communication. (中文文档)

Installation

cocoapods

pod 'TinyPart'

Features

  • Protocol-oriented Modules and services in Tinypart are protocol-oriented. The advantage is that maintenance interface will be much more easier, and any interface changes are visible at compile time. However, large projects may face a large number of protocols that need to be maintained. This is a disadvantage that cannot be ignored.

  • Dynamic The registration of modules and services in TinyPart is done at runtime. You can adjust the registration and startup time of the module according to specific needs. The asynchronous startup will help optimize the first-screen-loading of the APP.

  • Routing-service We know that protocol-oriented services are convenient for maintaining interface. However, when modules call other's services, they need to know each other's protocols. In the end, all protocols may need to be exposed to all modules. For example, there are 10 modules and 1 service protocol per module. In the above case, each module needs to know the protocol of another 9 modules. This means that each protocol is imported 9 times, and all protocols will be imported 9*10=90 times in total, this is a nightmare for modularization who want code isolation. Routing-service is a good balance between the inter-module calls and dependencies, and by the way also solve the cross-APP jump problem.

  • URL-routing On the basis of routing-service, simply adding another one or two lines of code can implement the URL-routing through APPScheme.

  • Multi-level Directive Communication In general, there are two ways of inter-module communication for decoupling: URL and notifications NSNotification. URL solves the problem of inter-module services calling, but they may become very complicated if you want to implement an observer-pattern by URL. At this time, people may prefer to select notifications, but since the notifications are global, this will cause any one of the notifications can be used by any module in the APP. As time went by, these notifications will be difficult to maintain.
    The so-called multi-level directive communication, is based on the NSNotification to limit the propagation direction of the notifications. The notification being dispatched from underlying modules to upper modules that called Broadcast. The notification being dispatched from upper modules to underlying or same-level modules that called Report. This has two advantages: on the one hand, more beneficial to the maintenance of the notification, on the other hand can help us to divide the module level. For example, if we find that a module needs to Report to so many modules, then this module should probably be divided into a lower-level modules.

Architecture

Architecture

Usage

Setup

  • AppDelegate inherits TPAppDelegate, and initialize the TPContext
#import "TinyPart.h"

@interface AppDelegate : TPAppDelegate
@property (strong, nonatomic) UIWindow *window;
@end

@implementation AppDelegate
@synthesize window;

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [TPMediator sharedInstance].deleagate = self;

    [TPContext sharedContext].launchOptions = launchOptions;
    [TPContext sharedContext].application = application;
    [TinyPart sharedInstance].context = [TPContext sharedContext];
    
    return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
@end

Module

  • Defination And Registration
#import "TinyPart.h"

@interface TestModule1 : NSObject <TPModuleProtocol>
@end

@implementation TestModule1
TP_MODULE_AUTO_REGISTER // Module will be registered in "+load" method

TP_MODULE_ASYNC         // Aysnc load

TP_MODULE_PRIORITY(1)   // Priority of the module. The higher will be launched in higher priority.

TP_MODULE_LEVEL(TPModuleLevelBasic)     // Level of the module

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    return YES;
}

- (void)moduleDidLoad:(TPContext *)context {
    switch (context.env) {
        case TPRunningEnviromentTypeDebug: {
            NSLog(@"%@", @"TestModule1 moduleDidLoad: debug");
            break;
        }
        case TPRunningEnviromentTypeRelease: {
            NSLog(@"%@", @"TestModule1 moduleDidLoad: release");
            break;
        }
    }
}
@end

Service

  • Defination And Registration Service can be singleton or multiple partterns。
#import "TPServiceProtocol.h"

@protocol TestModuleService1 <TPServiceProtocol>
- (void)function1;
@end

@interface TestModuleService1Imp : NSObject <TestModuleService1>
@end

@implementation TestModuleService1Imp
TPSERVICE_AUTO_REGISTER(TestModuleService1) // Service will be registered in "+load" method

- (void)function1 {
    NSLog(@"%@", @"TestModuleService1 function1");
}
@end
  • Call Sevice
id<TestModuleService1> service1 = [[TPServiceManager sharedInstance] serviceWithName:@"TestModuleService1"];
    [service1 function1];

Router

  • Defination And Registration
#import "TPRouter.h"

@interface TestRouter : TPRouter
@end
#import "TinyPart.h"

@implementation TestRouter
TPROUTER_AUTO_REGISTER  // Router will be registered in "+load" method

// Authentication required in APP. You also need to implement TPMediatorDelegate's method.
TPRouter_AUTH_REQUIRE(@"action1", @"action2")

TPROUTER_METHOD_EXPORT(action1, {
    NSLog(@"TestRouter action1 params=%@", params);
    return nil;
});

TPROUTER_METHOD_EXPORT(action2, {
    NSLog(@"TestRouter action2 params=%@", params);
    return nil;
});
@end
  • Open Router
[[TPMediator sharedInstance] performAction:@"action1" router:@"Test" params:@{}];

URL Routing

  • Add A ConfigPlistFile TinyPart.bundle/TinyPart.plistiscontext.configPlistFileName 's default value.
TPContext *context = [TPContext sharedContext];
context.configPlistFileName = @"TinyPart.bundle/TinyPart.plist";
[TinyPart sharedInstance].context = context;
  • NewTinyPart.bundle/TinyPart.plist, and add a URL Scheme
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>APPURLSchemes</key>
	<array>
		<string>tinypart</string>
	</array>
</dict>
</plist>
  • Defination of URL-routing On the basic ofTestRouter, we only need to do is creating file TPMediator+Test and add the codes like below.
@implementation TPMediator (Test)
+ (void)load {
    // The host "com.tinypart.test" corresponding to TestRouter
    TPURLHostForRouter(@"com.tinypart.test", TestRouter) // tinypart://com.tinypart.test
    
	 // The path "/action1" corresponding to TestRouter's action1
    TPURLPathForActionForRouter(@"/action1", action1, TestRouter);  // tinypart://com.tinypart.test/action1
}
@end
  • Open URL
NSURL *url = [NSURL URLWithString:@"tinypart://com.tinypart.test/action1?id=1&name=tinypart"];
[[TPMediator sharedInstance] openURL:url];

Directive Communication

  • Send Here's a note of what was mentioned above: The notification being dispatched from underlying modules to upper modules that called Broadcast. The notification being dispatched from upper modules to underlying or same-level modules that called Report. There are three levels Basic、Middle、Topout defined in TinyPart。
TPNotificationCenter *center2 = [TestModule2 tp_notificationCenter];

[center2 reportNotification:^(TPNotificationMaker *make) {
    make.name(@"report_notification_from_TestModule2");
} targetModule:@"TestModule1"];
    
[center2 broadcastNotification:^(TPNotificationMaker *make) {
	make.name(@"broadcast_notification_from_TestModule2").userInfo(@{@"key":@"value"}).object(self);
}];
  • Receive
TPNotificationCenter *center1 = [TestModule1 tp_notificationCenter];
// Observer will be dealloc automatically
[center1 addObserver:self selector:@selector(testNotification:) name:@"report_notification_from_TestModule2" object:nil];

Reference

BeeHive

ReactNative

License

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

tinypart's People

Contributors

ryanleely avatar ryanliyao avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

tinypart's Issues

authorizationBeforeAction用法的疑惑

比如跳转到A场景之前需要满足某种条件,不满足条件就到跳转到B场景。
如果应用中出现多种上述场景,TPMediatorDelegate对应的实现是否会导致耦合,我想的是如登录场景,打开扫码前要判断授权权限的场景。还有就是URL是网页该如何打开一个网页。

- (BOOL)mediator:(TPMediator *)mediator routerAction:(TPMediatorRouterActionModel *)routerAction checkAuthRetryPerformActionHandler:(void (^)(void))retryHandler

callback如何处理呢

你好,作者,看了您写的框架,有几个问题咨询下您,望您有空回复下,谢谢!
1.请问下,对于需要回调callback的action,您是怎么处理的呢?
2.看了您写的框架,不是很清楚Router和service的关系?为什么需要字典保存service和serviceimpl的映射呢?还有写的demo里面,使用service时,import了service头文件,这如果是跨模块调用的话,不就耦合了吗? 可能理解的不对,还望指导下~

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.