开源项目源码分析(Kickstarter-iOS )(一)

1.Kickstarter开源项目简介

我们自己去啃这些开源源码是有一点难度的,这里介绍一本很好的书籍: Raywenderlich 的一本书 《Advanced iOS App Architecture》在介绍 MVVM 架构的时候,说到 Kickstarter 很彻底地遵循了 MVVM 架构。

  • 首先第一感觉是代码非常令人爽心悦目,因为代码非常整洁。再仔细一看,发现里面有很多值得学习的地方,项目使用swift5.0编写,真正的使用MVVM架构模式,架构清晰,非常值得学习。

  • 下面看几张项目架构图片:
    KickStart项目架构

  • 用到的框架:
    Kickstarter用到的框架

  • 用到的第三方工具:

    • CircleCI:是一个持续集成的持续部署的工具,可以让开发者们更容易、更快地构建、测试和部署应用程序。
    • SwiftLint:一个检查 Swift 代码风格的工具,这可以说是 Swift 开发必备的工具。使用方法大家可以查看文档。
    • fastlane: 是一个开源平台,旨在简化 Android 和 iOS 的部署。他可以让我们自动化开发和发布的工作流程。
  • MVVM模式

Kickstarter MVVM架构

2. Kickstarter项目结构

2.1 Makefile 文件

  • 在把项目 clone 下来之后,我们一般首先会想着怎么把它运行起来。在项目的 readme 中的 Getting Started 我们可以看到,运行 make bootstrap安装工具和依赖,运行 make test-all 构建项目并进行测试。而这两个命令就是在 Makefile 中定义的。

ios git clone地址:https://github.com/kickstarter/ios-oss
android git clone地址:https://github.com/kickstarter/android-oss

  • 打开 Makefile 文件,我们可以从中看到:1)文件的开头定义了各种变量;2)剩下的是项目中用到的命令。我们以 make bootstrap 为例:
bootstrap: hooks dependencies
    brew update || brew update
    brew unlink swiftlint || true
    brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/686375d8bc672a439ca9fcf27794a394239b3ee6/Formula/swiftlint.rb
    brew switch swiftlint 0.29.2
    brew link --overwrite swiftlint
  • 执行 make bootstrap ,就会依次执行 bootstrap 下面包含的所有命令。
  • 使用 Makefile 的好处是,我们可以把项目相关的一些命令操作都放到这个文件,即便是刚刚接手项目的同事也一目了然。

2.2 Git submodule

  • 下载源码用xcode打开后你肯定会好奇,这么NB的工程居然没有用cocoapod,那么项目没有使用第三方框架么?
  • 答案是否定的。把项目 clone 下来之后,我们确实会发现文件夹里面没有我们常用的 Podfilexcworkspace 文件。然而,Kickstarter 不是用 Cocoapods 来管理第三方库的,而是使用 git submodule
  • 其实除了上面提到的两个管理第三方框架的工具之后,还可以用 Carthage 来管理第三方库。找到一篇文章:对比Carthage和Cocoapods和Git submodule,描述了这三种工具的优缺点。
  • 至于选择哪一种,就看我们更看重的是什么了。我一般都是使用的cocoapods.

2.3 脚本工具

  • 在根目录下的 bin 目录,我们可以看到两个用 Swift 编写的脚本:ColorScriptStringsScript

2.3.1 ColorScript脚本

  • 开发者把项目中用到的颜色,保存在Colors.json文件,然后通过 ColorScript 转换成 Colors.swift文件。开发者在使用的时候只需要通过 UIColor.ksr_dark_grey_400就能得到相应的颜色了。后续如果 UI 设计师想要微调颜色,直接修改颜色, json 中的 key 的值不变,我们只需要重新生成 Colors.swift就都搞定了,而不需要更改代码。
{
   
  "apricot_600": "FFCBA9",
  "cobalt_500": "4C6CF8",
  "dark_grey_400": "9B9E9E",
  "dark_grey_500": "656868",
  "facebookBlue": "3B5998",
    ...
}
  • 这种统一管理颜色的方法,我觉得其实就是把颜色管理的工作交给 UI 设计师了。设计师写好 json 文件,交给开发者,开发者用脚本生成 Colors.swift,就一切都搞定了(如果颜色名字有变动或有新添加的颜色,还是需要开发者手动更改和添加)。如果不通过这种方法去做,而是开发者自己手动去写,那么可能会经常去手动修改 Colors.swift,这样就麻烦一些。

2.3.2 StringsScript脚本

  • 做过国际化的开发者应该知道,如果不通过其他处理的话,我们需要通过 NSLocalizedString("Hello_World", comment: "") 去获取对应的本地化字符串,这种写法非常麻烦,而且很容易出错。
  • 在 Kickstarter-iOS 中,开发者用 StringsScriptLocalizable.strings转换生成 Strings.swift 文件,然后我们在使用的时候,就可以像这样去获取想要的字符串 Strings. Hello_World()。这个脚本把 key 变成了方法名,让我们避免了在使用的时候出现错误,而且使用起来非常方便。
  • 如果有做本地化的项目,采用这种方法可以给开发者带来很大的便利。

2.4 测试工具

  • 测试,是软件开发中非常重要的一个环节。甚至有些公司执行 TDD (测试驱动开发(Test-Driven Development)),可以见测试的重要性。
  • 在 Kickstarter-iOS 中,我们可以看到大量的 xxxTests.swift文件,包括了 Unit TestUI Test

2.5 独立的代码库

  • 用 Xcode 打开 Kickstarter-iOS 的项目,你会发现 KsApiLibraryLiveStream这三个文件夹不是存放在 Kickstarter-iOS文件夹里面的,而是跟它处于同一个目录。因为这三个文件夹存放的是独立于 Kickstarter-iOS 之外的 framework

Kickstarter-iOS 独立框架

  • 这么做的好处当然是代码可以复用。目前我看 iPad 上的 Kickstarter 应用是跟 iPhone 共用一个的,如果以后要为 iPad 单独做一个 app,这三个 frameworks 就可以直接拿过去用。

3. Kickstarter项目MVVM架构

3.1 MVVM架构思想简介

  • MVVM架构思想
    这里有一个讲解 MVVM & TDD 的视频。感兴趣的可以看一下。

  • 函数响应式编程思想
    代表主要有Rxswift, RAC, ReactiveSwift

  • ReactiveSwift 是一个响应式编程的库,与 RxSwift 类似,这两个库非常适用于 MVVM 架构。至于要选择哪一种,可以先去了解下他们的差别,然后再决定.这里有篇很好的文章讲解了他们的区别:How does ReactiveSwift relate to RxSwift?

  • Kickstarter-iOS 把 MVVM 模式贯彻地非常彻底。MVVM 的全称是 Model-View-ViewModel,所以我们可能会觉得要有 View 存在的地方,才可以用 ViewModel。但是 Kickstarter-iOS 在 AppDelegate 中也使用了 ViewModel,把很多在 AppDelegate 处理的逻辑剥离到 AppDelegateViewModelType 中。

3.2 MVVM架构实际运用

3.2.1 使用 ReactiveSwift

  • 我们平常很多项目一般都是使用Rxswift + MVVM架构模式这样搭配,然后会用到网络库Alamofire + Moya + Rxswift .数据库一般用FMDB.
  • 响应式编程非常适合 MVVM 架构。在 ViewModel 中,我们通常会使用 ReactiveSwift 或者 RxSwift 去定义一些属性,然后在 UIView 和 UIViewController中的 bindViewModel() 方法里面订阅那些属性的变化,然后更新 UI。
  • Kickstarter-iOS项目基本就是用 ReactiveSwift + MVVM这种。

3.2.2 UIView

  • 对于 UIView,Kickstarter 通过扩展重写 awakeFromNib(),在内部调用 bindViewModel()。代码如下:
extension UIView {
   
  open override func awakeFromNib() {
   
    super.awakeFromNib()
    self.bindViewModel()
  }
  @objc open func bindViewModel() {
   
  }
}
  • 因为 Kickstarter 在整个项目中都是通过 xib 来构建 UI 的,所以 UI 在初始化时,awakeFromNib()会被调用,从而 bindViewModel() 也被调用。那么在其他继承自 UIViewview 中,只需要重写 bindViewModel(),就能达到绑定 ViewModel 的目的。

3.2.3 UIViewController

  • UIViewController 中就会稍微复杂一点。Kickstarter 通过 runtime,默认在 viewDidLoad() 中调用 bindViewModel()。那么在其他继承自 UIViewControllerViewController 中,只需要重写 bindViewModel(),就能达到绑定 ViewModel 的目的。

  • UIViewController-Preparation.swift相关代码如下:

private func swizzle(_ vc: UIViewController.Type) {
   

  [
    (#selector(vc.viewDidLoad), #selector(vc.ksr_viewDidLoad)),
    (#selector(vc.viewWillAppear(_:)), #selector(vc.ksr_viewWillAppear(_:))),
    (#selector(vc.traitCollectionDidChange(_:)), #selector(vc.ksr_traitCollectionDidChange(_:))),
    ].forEach {
    original, swizzled in

      guard let originalMethod = class_getInstanceMethod(vc, original),
        let swizzledMethod = class_getInstanceMethod(vc, swizzled) else {
    return }

      let didAddViewDidLoadMethod = class_addMethod(vc,
                                                    original,
                                                    method_getImplementation(swizzledMethod),
                                                    method_getTypeEncoding(swizzledMethod))

      if didAddViewDidLoadMethod {
   
        class_replaceMethod(vc,
                            swizzled,
                            method_getImplementation(originalMethod),
                            method_getTypeEncoding(originalMethod))
      } else {
   
        method_exchangeImplementations(originalMethod, swizzledMethod)
      }
  }
}

private var hasSwizzled = false

extension UIViewController {
   
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值