WinkKit 1.0.1

WinkKit 1.0.1

测试已测试
语言语言 SwiftSwift
许可证 MIT
发布最后发布2018年7月
SPM支持 SPM

Rico Crescenzio 维护。



 
依赖
Alamofire~> 4.5
AlamofireImage~> 3.2
Argo>= 0
Runes>= 0
Curry>= 0
DateTools>= 0
 

WinkKit 1.0.1

  • 作者
  • Rico Crescenzio

WinkKit

CocoaPods Version License Platforms Swift Version

一个 iOS 框架,包含一系列遵循 MVP 模式的类,并以 Swift 编写,用于解决一些常见问题,用于 Wink 应用。遵循此指南了解如何结构化 Wink iOS 项目。

目录

  1. 开始使用
  2. 了解结构
  3. 使用增强视图
  4. 使用 ViewControllers 和 Presenters
  5. 使用 Table Views 和 Collection Views
  6. 实用工具和更多

开始使用

先决条件

您需要安装 Xcode 9、Swift 4 和 CocoaPods

将项目/文件模板添加到Xcode中(可选但推荐)

WinkKit已设计用于帮助使用MVP模式创建应用程序(您将在稍后更好地理解这一点);遵循此模式,需要为每个视图创建几个文件。WinkKit包含一组Xcode模板,以加快项目和文件创建的速度;下载Wink Project Helper macOS应用程序以安装所有模板。

在模板安装后,在Xcode中,在文件 > 新建 > 文件(或CMD+N)下,您可以创建符合MVP视图控制器、表格视图单元格和集合视图单元格,如下所示。

您甚至可以创建整个项目,请看下一点。

安装

使用模板创建项目

如果您是从头开始,并且成功安装了Wink Kit模板,您可以直接从Xcode中创建新项目,在文件 > 新建 > 项目

此模板为您创建了Wink应用程序的基本结构(稍后将解释),已配置好包含WinkKit框架的Podfile.gitignore和其他模板文件/代码。

现在在根项目文件夹中运行pod install,然后从工作区文件重新打开项目。这样就完成了。🎉

手动

只需将CocoaPods依赖项粘贴到您的Podfile中。由于cocoapods的错误,请确保也粘贴了post_install函数。

# Podfile
use_frameworks!

target 'YOUR_TARGET_NAME' do

    # https://github.com/WINKgroup/WinkKit
    pod 'WinkKit'
    
end

# This post install is needed because of a Cocoapods bug; it is needed to render WinkKit properties in InterfaceBuilder correctly.
post_install do |installer|
    installer.pods_project.targets.each do |target|
        target.build_configurations.each do |config|
            if target.name === 'AlamofireImage'
                config.build_settings['SWIFT_VERSION'] = '3.3' # set swift 3.3 on AlamofireImage
            end
            config.build_settings['CONFIGURATION_BUILD_DIR'] = '$PODS_CONFIGURATION_BUILD_DIR'
        end
    end
end

注意:AlamofireImage只能在Swift 3.3中编译。

API 文档

在此检查类引用 这里

理解结构

在讨论框架的类之前,我们将先看看架构结构。

这是一个 MVP 模式;查看这个 iOS 架构概述 来理解 MVC、MVP、MVVM、VIPER 之间的差异。

Wink iOS 项目 应该 按以下方式进行结构化,特别是如果项目将有很大的增长

Arch diagram

映射此架构的整个 Xcode proj 结构大致如下


表示层

这是包含所有 iOS 框架专用类的层,例如 UIKit 框架。我们可以说,这个层不能在没有 iPhone/iPad 的情况下存在,因为 UIKit 只能在那里运行。

  • AppDelegate:这是众所周知的 AppDelegate 类,没有什么特别的;
  • 用例:一个包含所有用例的组。重要的是要理解,一个 用例 是用户在应用屏幕上执行的一个或多个动作,例如登录。
    • 登录:一个用例的示例。它将包含所有相关的 ViewControllers、Presenter(如果用例包含多个),DataSources 等。
      • 登录展示者:一个简单的展示者;登录展示者保留登录视图控制器的状态;展示者是一个包含逻辑的类,视图控制器不包含逻辑。 展示者不包含 UIKit 类! 这是为了使展示者易于测试。
      • 登录视图控制器:在经典 MVC 模式下,(iOS 世界的“大量视图控制器”😫所有逻辑都在这里,与视图处理混合在一起;在这个框架中,ViewController 拥有一个Presenter,并委派其逻辑。例如,ViewController没有func performLogin(email: String, password: String)这样的方法;取而代之的是,Presenter有。ViewController只会接收用户输入,并通知Presenter发生了什么事情。Presenter会执行工作,并告诉ViewController视图应该改变。
  • 核心:一个包含在项目中可重用基类的组。定义这些类是一个好习惯,可以避免代码重复,从而提高维护难度。
  • 资源:所有资源都放在这里,包括.xcassets、自定义字体等……

数据

这是处理所有数据层级的层,例如http调用、到达后端的上传/下载缓存。在这个层中不使用任何UIKit类!

  • 缓存:一个包含SessionManager和其他所有本地保存数据的类的组。
  • 网络:包含HttpClient的组,必须用Alamofire实现。WinkKit本身在框架中提供了AlamofireAlamofire Image,因此您不需要在Podfile中添加任何东西。
    • 响应序列化:包含Alamofire的DataResponse扩展:它提供对返回对象而不是json的http调用的公共响应;json解析在这个扩展中完成(详情请参阅源文件)。注意,这个扩展使用Argo进行json解析。
    • 资源:一个将https调用响应映射到枚举。
    • 错误:将http错误(客户端和服务器)映射到类/结构。
    • 路由器:路由器负责了解api的端点,并为Services创建用于执行http调用的urlRequest
    • 服务:服务执行http调用,使用路由器创建的请求。

表示

使用增强的视图

WinkKit提供了具有更多@IBDesignable的通用视图类。

  • WKView
  • WKImageView
  • WKButton
  • WKLabel
  • WKTextView

每个类都继承自 UIKit,例如 WKView 继承自 UIView。要在 InterfaceBuilder 中使用这些类,从对象库中拖拽对象,并让它继承期望的 WinkKit 视图。例如,要使用 WKButton,从对象库中拖拽一个按钮,然后在“身份检查器”中设置自定义类。

确保将 WinkKit 保持为模块。

然后你可以从“属性检查器”中自定义按钮。

使用 ViewControllers 和 Presenters

在 WinkKit 应用中,每个视图控制器都应该继承自 WKViewController<P>(或 WKTableViewController<P>WKCollectionViewContrller<P>,它们都有相同的行为)。

WKViewController 希望有一个 WKGenericViewControllerPresenter 的子类(这是一个扩展基本呈现器协议 WKPresenter 的协议),因为视图控制器生命周期绑定到这种呈现器。主页的一个典型实现是:

// HomeViewController.swift

class HomeViewController: WKViewController<HomePresenter> {
	// do only UI stuff here
}

// Since the view controller is handled by HomePresenter, it must be conform to LoginView.
extension HomeViewController: LoginView {
	// implements all HomeView methods/properties
}


// HomePresenter.swift

// Define what the view can do
protocol LoginView: PresentableView {

}

class HomePresenter: WKGenericViewControllerPresenter {

    typealias View = LoginView // need to tell the protocol which is the view handled
    
    weak var view: LoginView? // keep view weak to avoid retain-cycle since view controller holds a reference to this presenter
    
    required init() {} // framework wants empty init
    
    // do all logic here, such as use a Service to fetch data and tell the view to update
}

请注意,您不需要调用任何方法来绑定视图控制器和呈现器,所有这些操作都是框架自动完成的! 🎉🎉🎉

HomePresenter 和 HomeViewController 是两个不同的文件。您可以使用文件模板快速创建这种结构😉.

使用 Table Views 和 Collection Views

WinkKit 提供了 WKTableViewWKCollectionViewWKTableViewCellWKCollectionViewCell。让我们来谈谈 WKTableViewWKTableViewCell(集合视图有相同的逻辑)。

注意:为了有一个更好的结构,所有单元格都必须有一个 xib:请不要在Storyboard中直接创建单元格。

WKTableView 提供了两种方法来快速注册和排练一个 WKTableViewCell,只需这样做:

tableView.register(cell: ItemTableViewCell.self) // register the cell with a xib that has same name of the class

tableView.dequeueReusableCell(ofType: ItemTableViewCell.self, for: indexPath) // dequeue a cell, already casted

单元格就像视图控制器一样:它们有一个呈现器(在这种情况下是简单的 WKPresenter),并且必须符合呈现器处理的视图。因此,创建单元格就像创建视图控制器一样

// ItemTableViewCell.swift

class ItemTableViewCell: WKTableViewCell<ItemPresenter> {
	// do only UI stuff here
}

extension ItemTableViewCell: ItemView {
  	// implements all ItemView methods/properties  
}

// ItemPresenter.swift

/// The protocol that the cell handled by presenter must conforms to.
protocol ItemView: PresentableView {
    
}

/// The presenter that will handle all logic of the view.
class ItemPresenter: WKPresenter {
    
    typealias View = ItemView
    
    // The view associated to this presenter. Keep weak to avoid retain-cycle
    weak var view: ItemView?
	
	// the item that will be showed in this cell
	private var item: Item!
	 
    init(with item: Item) {
    	self.item = item
    }
    
    // do all logic here
}

您可以使用模板快速创建所有这些类/协议😁.

与视图控制器不同,单元格在数据源中排练后必须进行配置,如下所示

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
	let cell = tableView.dequeueReusableCell(ofType: ItemTableViewCell.self, for: indexPath)
  	let presenter = ItemPresenter() // create a presenter
  	cell.configure(with: presenter) // configure the cell with the presenter
  	return cell
}

集合视图和表视图数据源

作为最佳实践,最好是解耦数据源和视图控制器。避免将视图控制器做成数据源,这样可以更好地分离和复用各项功能。要从数据源传递给视图控制器,可以使用闭包或委托模式。一个简单的表格视图数据源的典型实现可能如下

class ItemDataSource: NSObject, UITableViewDataSource {
    
    private var items = [Any]()
    
    init(tableView: WKTableView) {
    	// register cell here so when you need this data source you don't have to repeat this line of code
    	tableView.register(cell: ItemTableViewCell.self)
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return items.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(ofType: ItemTableViewCell.self, for: indexPath)
        let presenter = ItemPresenter(with: items[indexPath.row])
        cell.configure(with: presenter)
        
        return cell
    }
    
}

然后在您的视图控制器中使用数据源作为实例变量。

提示: WinkKit 提供了一些现成的数据源类,具有一些常用方法,例如插入/删除/重新加载项目或处理无限滚动。请查看 WKTableViewDataSourceWKCollectionViewDataSourceWKTableViewInfiniteDataSourceDelegate

更多工具和相关内容

还有其他类和扩展可以用来实现某些行为

    • Logger: 包含日志记录方法以及避免在发布模式下打印调试信息的方法;
    • OrderedSet: 类似于 Set 但元素是有序的;
    • Queue: 一个简单的队列类
  • 扩展
    • UIAlertController: 包含快速显示警告的方法
    • Date: 包含从字符串和格式创建日期的方法,以及一些获取天、小时的方法
    • Collection: 包含一个下标,可以访问值即使索引是错误的(它返回一个可选值)
    • CALayer: 包含为层添加边框的方法
    • UIColor: 允许使用十六进制字符串创建颜色
    • UIWindow: 包含获取当前最顶层视图控制器的方法

作者

Rico Crescenzio - Linkedin

授权

本项目的授权协议为 MIT 协议 - 有关详细信息,请参阅 LICENSE 文件