模块化开发iOSApp

一个iOS菜菜的白话文记录

不停的写博客不是为了炫耀什么,仅仅只是为了个人的一些学习总结,没有过多的什么意思,因为很多东西都能够在网络上找到。如Blog标题我只是一个iOS入门级菜鸟。只有当你的基础足够的扎实时候,才能像YYKit作者那样对iOS平台技术有如此深厚的理解。

模块化开发iOSApp一

FEB 26TH, 2016 11:45 AM

一直想学习下模块化开发一个App

  • 让一个App分成n个单独的模块
  • 每一个插件模块由一个小组单独开发,最大限度解耦
    • 每一个小组只负责该插件模块的开发、代码合并
    • 不用再担心整个App工程的代码合并,也就不再需要对.Xcodeproj解决代码冲突
    • 更重要的是不会因为所有的业务揉在一起,导致对全局业务不熟悉的人修改代码时,还需要额外的看懂其他不相关的业务代码
  • 解耦到极致后,既可以实现每一个模块的热更新
    • 主App只是一个承载众多个插件模块的容器载体
    • 提供一些基础功能
    • 调用其他插件模块完成其对于业务
    • 插件A与插件B之间的沟通

模块化基础、从抽象隔离开始

  • 假设在MainViewController要push到一个显示新闻列表的NewsListViewController
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#import "MainViewController.h"

//导入具体控制器类
#import "NewsListViewController.h"

@implementation MainViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    //此时需要显示新闻列表的界面
    NewsListViewController *vc = [[NewsListViewController alloc] init];
    [self.navigationController pushViewController:vc animated:YES];
}

@end
  • 改进上述MainViewController直接依赖NewsListViewController的方法

    • 使用抽象接口隔离

      • 同一层依赖接口
      • 各层之间也依赖接口
      • 使用容器管理接口与实现类的映射关系,可配置化
    • 使用一个标识符来代替具体的ViewController类
      • BaseViewController pushWithControllerId: 一个NSIntger枚举值
      • 模拟URL Scheme跳转App的思路

抽象接口 + 容器注入

  • 抽象接口定义:显示新闻列表
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//
//  NewsListProtocol.h
//  Demo
//
//  Created by xiongzenghui on 16/2/26.
//  Copyright © 2016年 xiongzenghui. All rights reserved.
//

#import <Foundation/Foundation.h>

@protocol NewsListProtocol <NSObject>

- (void)showNewsList;

@end
  • 接口实现类,具体怎么样显示新闻列表
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//
//  NewsListViewController.h
//  Demo
//
//  Created by xiongzenghui on 16/2/26.
//  Copyright © 2016年 xiongzenghui. All rights reserved.
//

#import <UIKit/UIKit.h>

//导入接口
#import "NewsListProtocol.h"

//实现接口,具备显示NewLsit的能力
@interface NewsListViewController : UIViewController <NewsListProtocol>

@end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//
//  NewsListViewController.m
//  Demo
//
//  Created by xiongzenghui on 16/2/26.
//  Copyright © 2016年 xiongzenghui. All rights reserved.
//

#import "NewsListViewController.h"

@implementation NewsListViewController

- (void)showNewsList {
    //1. 请求服务器
    //...

    //2. 异步刷新UI显示
    //[self.tableView reload];
}

@end
  • MainViewController依赖一个容器获取接口实现类对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
//
//  MainViewController.m
//  Demo
//
//  Created by xiongzenghui on 16/2/26.
//  Copyright © 2016年 xiongzenghui. All rights reserved.
//

#import "MainViewController.h"

//导入具体控制器类
//#import "NewsListViewController.h"

//导入抽象接口
#import "NewsListProtocol.h"

//导入容器
#import "Objectiontor.h"

@implementation MainViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    //此时需要显示新闻列表的界面

    //依赖具体类
//    NewsListViewController *vc = [[NewsListViewController alloc] init];
//    [self.navigationController pushViewController:vc animated:YES];

    //涕泪抽象
    id<NewsListProtocol> vc = [Objectiontor objectWithProtocol:@protocol(NewsListProtocol)];
    [self.navigationController pushViewController:(UIViewController *)vc animated:YES];
}

@end
  • 中间容器,只是随便写的例子
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//
//  Objectiontor.h
//  Demo
//
//  Created by xiongzenghui on 16/2/26.
//  Copyright © 2016年 xiongzenghui. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface Objectiontor : NSObject

+ (id)objectWithProtocol:(Protocol *)protocol;

@end
1
实现部分没写,可参考`Objection`

这样的话就能够做到:

  • 那天想切换新闻显示列表的控制器,直接修改容器中接口配置的实现类
  • 需要单独抽出MainViewController到其他工程,因为没有任何的具体类依赖

还有之前使用类似URL Scheme来替代 NewsListViewController

就不细说了,可参考前面的文章.

总的来说,模块化设计的基础就是 面向抽象


模块化进阶一、使用单独的静态库工程提供子模块功能,然后再通过CocoaPods自动下载导入

  • 静态库提供的形式

    • 以 .a + .h 形式提供
    • 以 .framework 形式提供
      • 直接提供给别人一个单独的framework文件即可
      • 可以更好的打包资源文件
      • 还可以通过 CocoaPods 来实现像第三方框架那样集成
        • 参考 pod lib create
  • 一个完整的App最后是由n个单独屏蔽了内部实现的静态库合并起来的
    • 静态库A: 提供显示新闻列表
    • 静态库B: 提供商品列表
    • 静态库C: 提供支付
    • 静态库D: 等等…就是一个单独的业务功能模块
    • 再也会产生 .XcodeProj文件产生代码冲突了
    • 每一个静态库使用一个单独的podspec,作为一个pods源
  • 将所有的子功能模块做成私有的git库,然后使用CocoaPods导入

  • CocoaPods中podfile文件中的一些配置属性含义
1
2
3
4
5
platform: 可以指定平台的信息和deployment target的版本

target: 可以根据不同的target来引入不同的pod

pod: 引入依赖库
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
pod ‘SSZipArchive‘  -- 引入最新版本

pod ‘Objection‘, ‘0.9‘  -- 引入特定的版本

pod ‘Objection‘, ‘>0.9‘> -- 任何大于0.9的版本

pod ‘Objection‘, ‘>=0.9‘> -- 任何大于等于0.9的版本

pod ‘Objection‘, ‘<0.9‘> -- 任何小于0.9的版本

pod ‘Objection‘, ‘<=0.9‘> -- 任何小于等于0.9的版本

pod ‘Objection‘, ‘~>0.9‘> -- 任何介于0.9到1.0的最新版本,不包含1.0

pod ‘AFNetworking‘, :path => ‘~/Documents/AFNetworking‘  -- 使用本地路径引入

pod ‘AFNetworking‘, :git => ‘https://github.com/gowalla/AFNetworking.git‘, :tag => ‘0.7.0‘  -- 使用git库引入

pod ‘JSONKit‘, :podspec => ‘https://example.com/JSONKit.podspec‘  -- 使用外部的podspec来引入
  • 关于使用CocoaPods开发 static framework 的步骤可参看之前的文章.

模块化进阶二、使用单独的子App提供子模块功能

  • 主App依赖n个子App完成对应的子功能模块
  • 核心是根据 URL Scheme 来完成App的跳转
    • 可参考开源类库 JLRoutes 封装的复杂性URL Scheme跳转
    • 未按照则跳转AppStore下载安装
  • 多个子App的好处与坏处
    • 每一个单独的子App,可以单独的测试、发布
    • 坏处那就是App太多了…

列举下JLRoutes的简单用法

  • App启动时注册URL Scheme的回调处理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

  [JLRoutes addRoute:@"/foo" handler:^BOOL(NSDictionary *parameters) {
    // This block is called if the scheme is not ‘thing‘ or ‘stuff‘ (see below)
    return YES;
  }];

  [[JLRoutes routesForScheme:@"thing"] addRoute:@"/foo" handler:^BOOL(NSDictionary *parameters) {
    // This block is called for thing://foo
    return YES;
  }];

  [[JLRoutes routesForScheme:@"stuff"] addRoute:@"/foo" handler:^BOOL(NSDictionary *parameters) {
    // This block is called for stuff://foo
    return YES;
  }];

  return YES;
}
  • 当前App被打开时的回调函数,使用JLRoutes处理当前(iso9+)
1
2
3
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<NSString *, id> *)options {
  return [JLRoutes routeURL:url];
}
  • 当前App被打开时的回调函数,使用JLRoutes处理当前(iso9之前)
1
2
3
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
    return [JLRoutes routeURL:url];
}

更多的使用还是要项目用到的时候再去看了…

时间: 2024-10-02 18:29:16

模块化开发iOSApp的相关文章

2.精通前端系列技术之JavaScript模块化开发

在使用seajs模块化开发之前,直接在页面引用js会容易出现冲突及依赖相关的问题,具体问题如下 问题1:多人开发脚本的时候容易产生冲突(比如全局参数冲突,方法名冲突),可以使用命名空间降低冲突,不能完全避免冲突 // JavaScript Document /*var a = 10; function tab(){} function drag(){} function dialog(){}*/ var miaov = {}; //名字比较长 , 只能降低冲突,不能完全避免 miaov.a =

UC前端‘搭积木’的模块化开发——scrat.js

模块化开发 将模块所需的js\css\img\tmpl维护在一起,一个模块一个目录 js渲染模板 css只关心模块内样式 开发团队心声:"我们希望每次研发新产品不是从零开始,不同团队不同项目之间能有可复用的模块沉淀下来." 模块生态 每个工程有_工程模块_和_生态模块_. 生态模块:基于_component规范_开发,部署到Github上,可以通过命令行工具将Github上的模块安装到工程中使用.比如:jQuery, iscroll, zepto.js, vue.js 安装命令: sc

关于Egret模块化开发---vip系统

关于Egret模块化开发---vip系统 目录 关于Egret模块化开发---vip系统... 1 前言... 1 一,搭建界面... 1 二,建立数据模型... 3 1)数据模型的搭建: 3 2)数据的建立... 4 3)数据的增删改查... 7 三.做交互, 7 结束... 8 前言 做游戏就是做数据,数据模型的设计,是体验mvc一种基础的设计,用数据驱动界面变化.. 做为一个程序要学会模块化,配置化,脚本化的需求,提防策划的需求变更的可能 例如:做一个VIP系统步骤: 搭建界面 建立数据模

javascript模块化开发编程

随着网站的不断迭代更新,js代码越来越多,那么问题来了 代码比较乱 命名出现冲突 文件依赖比较繁杂 为了解决以上问题,模块化开发出现了 1.一个简单的demo,维护和扩展模块 模块的维护和扩展一定要遵守一个约定:开闭原则 对添加开放,对修改封闭 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>扩展和维护模块</

前端模块化开发的价值

本文发表在<程序员>杂志 2013 年 3 月刊,推荐购买. 前端模块化开发的价值 随着互联网的飞速发展,前端开发越来越复杂.本文将从实际项目中遇到的问题出发,讲述模块化能解决哪些问题,以及如何使用 Sea.js 进行前端的模块化开发. 恼人的命名冲突 我们从一个简单的习惯出发.我做项目时,常常会将一些通用的.底层的功能抽象出来,独立成一个个函数,比如 function each(arr) { // 实现代码 } function log(str) { // 实现代码 } 并像模像样地把这些函

轻轻谈一下seaJs——模块化开发的利器

"仅做一件事,做好一件事." 这个应该就是seaJs的精髓了. 我在自己的一些项目中使用过seaJs,对其算是了解一二,现在就班门弄斧,轻轻地谈一下. 首先上一段度娘的话: "seaJs是一个遵循CommonJs规范的JavaScript模块加载框架,可以实现JavaScript的模块化开发及加载机制.与jQuery等JavaScript框架不同,SeaJS不会扩展封装语言特性,而只是实现JavaScript的模块化及按模块加载.SeaJS的主要目的是令JavaScript开

Javascript模块化开发 – AMD规范

通行的Javascript模块规范共有两种:CommonJS和AMD. 2009年,美国程序员Ryan Dahl创造了node.js项目,将javascript语言用于服务器端编程.这标志"Javascript模块化编程"正式诞生.因为老实说,在浏览器环境下,没有模块也不是特别大的问题,毕竟网页程序的复杂性有限:但是在服务器端,一定要有模块,与操作系统和其他应用程序互动,否则根本没法编程. node.js的模块系统,就是参照CommonJS规范实现的.在CommonJS中,有一个全局性

软件开发中,什么是模块化开发?

软件产品可以被看作是由一系列具有特定功能的组件组成,作为一个完整的系统也可以被分解成一系列功能模块,这些模块之间的相互作用就形成了系统的所有功能. 所谓模块是指可组成系统的.具有某种确定独立功能的半自律性的子系统,可以通过标准的界面和其他同样的子系统按照一定的规则相互联系而构成的更加复杂的系统.每个模块的研发和改进都独立于其他模块的研发和改进,每个模块所特有的信息处理过程都被包含在模块的内部,如同一个"黑箱",但是有一个或数个通用的标准界面与系统或其他模块相互连接. 在软件的模块化开发

seajs的模块化开发--实践笔记

2017-04-02 SeaJS是一个遵循CMD规范的JavaScript模块加载框架,可以实现JavaScript的模块化开发及加载机制.有效的解决复杂项目中命名冲突.依赖.性能等问题. SeaJS中使用define函数定义一个模块.define可以接收三个参数:require, exports, module. require--模块加载函数,用于记载依赖模块. exports--接口点,将数据或方法定义在其上则将其暴露给外部调用. module--模块的元数据. SeaJS的基本用法有以下