RepositoryKit 4.1.1

RepositoryKit 4.1.1

测试已测试
语言语言 SwiftSwift
许可证 MIT
发布最后发布2017年11月
SwiftSwift 版本3.0
SPM支持 SPM

Luciano Polit维护。



  • 作者
  • Luciano Polit

RepositoryKit

Version
Build
Coverage
Documentation

索引

介绍

RepositoryKit是一个减轻您代码组织方式的框架。

它基于存储库模式,其主要目的是将检索存储模块(如网络或本地存储)数据的逻辑从您的代码中分离出来。它通常位于控制器中,迫使它执行比它应该做的更多的事情(并使其变得更大)。然而,现在,它们有了正确的干净的地方。

它由三个组件组成

  • 实体:我们需要表示的东西,通常被称为对象。
  • 存储库:知道如何在与实体和数据存储之间操作的。
  • 数据存储:存储数据的地方,提供与它通信的方式,如网络会话或Core Data栈。

此外,它使用承诺,这是一种管理异步代码的好方法。

示例

要运行示例项目有两种方法

  • 在终端中执行pod try RepositoryKit
  • 克隆仓库并打开示例。

需求

  • iOS 9.0+
  • Swift 3.0+

安装

CocoaPods

要使用CocoaPods安装RepositoryKit,只需将以下行添加到您的Podfile

pod "RepositoryKit", "~> 4.1"

Carthage

要使用Carthage安装RepositoryKit,只需将以下行添加到您的Cartfile

github "LucianoPolit/RepositoryKit" ~> 4.1

使用

情况:需要与REST API交互来管理对话,简单的情况,'Message'作为唯一实体。对于这些消息,我们需要执行四种不同的操作,存储库将负责执行这些操作。这些操作是:创建、读取、更新、删除,通常称为CRUD。

从实体开始

首先,由于存储库需要与我们的API进行交互,它需要能够识别实体,因为它需要在同一实体上执行不同的操作。因此,我们必须遵守 'Identifiable',只需添加一个 'id' 属性。

struct Message: Identifiable {
    
    // Entity identification.
    var id: String
    // Properties.
    var text: String
    
}

然后,由于存储库需要使用公共数据表示与我们的API进行通信,实体必须遵守两个新的协议:'DictionaryInitializable' 和 'DictionaryRepresentable'。

extension Message: DictionaryInitializable {
    
    // Initialize with a dictionary.
    init?(dictionary: [String: Any]) {
        
        // Here we will have the dictionary that should initialize the entity.
        // We have to be careful that every information we need is inside the dictionary.
        // If not, return nil, and we will have an error in the promise of the repository operation.
        guard let id = dictionary["_id"] as? String, let text = dictionary["text"] as? String else { return nil }
        
        // In case that we have the data needed, set it.
        self.id = id
        self.text = text
        
    }
    
}

extension Message: DictionaryRepresentable {
    
    // Dictionary representation.
    var dictionary: [String: Any] {
        return [
            "_id": id,
            "text": text
        ]
    }
    
}

就这样!我们的实体准备好了,可以与我们的存储库和API交互了!

创建存储库

现在我们有了准备好的实体,我们需要做一些能够与API交互的事情,并且实体能够提供信息。

首先,我们的存储库需要知道我们的实体。符合 '存储库' 是容易的。

class MessageRepository: Repository {
    
    // It is the entity that the repository operates.
    typealias Entity = Message
    
}

然后,我们需要符合 '网络存储库'。所以,存储库需要

  • 存储库将表示的路径。
  • 某种与我们 API 交互的方式,进行 HTTP 请求。在这种情况下,KIT会为你提供一个默认的选择,名叫 'NetworkingSession',你可以使用你所创建的或者另一个框架的,只要它们符合 '网络' 标准。
class MessageRepository: NetworkingRepository {
    
    // It is the entity that the repository operates.
    typealias Entity = Message
    
    // It will make the requests.
    var store: Networking
    
    // The path that represents the repository.
    var path: String = "messages"
    
    // Initialize it with a networking store.
    init(store: Networking) {
        self.store = store
    }
    
}

现在,我们能够实现实体-存储库-API 之间的通信了。那么,我们能执行什么操作呢?有人知道吗…
所以,根据实际需要,我们需要能够执行CRUD操作

  • 创建
    • 请求:'url/path'。
    • 方法:POST。
    • 参数:实体字典。
    • 返回:一个带有额外属性的对象,至少有id。
  • 读取
    • 请求:'url/path' 或 'url/path/:id'。
    • 方法:GET。
    • 返回:一个对象或对象数组。
  • 更新
    • 请求:'url/path/:id'。
    • 方法:PUT。
    • 参数:实体字典。
    • 返回:如果需要,带有额外属性的对象。
  • 删除
    • 请求:'url/path/:id'。
    • 方法:DELETE。

如果我们使存储库符合'CRUDNetworkingRepository',它就能够执行这些操作。酷吗?多亏了Swift,这是由于默认协议实现成为可能的!

class MessageRepository: CRUDNetworkingRepository { ... }

如果CRUD的概念不足以满足你的需求,或者KIT包含的其他存储库,你可以扩展存储库并定义自己的方法,或者创建你自己的存储库类型。

现在,我们准备进行尝试了!

让我们试试

首先,我们使用Promise。如果你对这些没有了解,我邀请你先了解一点PromiseKit

在开始执行CRUD操作之前,我们需要初始化网络会话和存储库。

let networkingSession = NetworkingSession(url: "https://:3000")
let messageRepository = MessageRepository(store: networkingSession)

现在我们准备好了!让我们创建一条消息。

// It will create a message on your API.
messageRepository.create(["text": "Here goes a message!!!"])
    .then { message in
        print(message)
        // Observe that you should have at least the 'text' and 'id' properties initialized.
        // In my case, it printed 'Message(id: "581a8e2da80614c82661b98d", text: "Here goes a message!!!")'.
        // Here you can update the UI for example.
    }
    .catch { error in
        // In case that an error occurs, do whatever you have to do here.
        errorHandler(error)
    }

让我给你演示一个额外的例子。然后你可以尝试任何你想要的东西!

messageRepository.search("581a8e2da80614c82661b98d")
    .then(execute: messageRepository.delete)
    .then {
        print("The message has been deleted")
    }
    .catch { error in
        // In case that an error occurs, do whatever you have to do here.
        errorHandler(error)
    }

在这种情况下,它会尝试根据指定的id在API上搜索实体。然后,如果成功,它会尝试删除它,如果一切正常,它会打印实体已被删除。请记住,不要忘记处理可能的错误。

简单吗?更整洁吗?很酷!现在轮到你了,来试试吧!

更多存储库

使用案例只是一个起点,是最简单的。有更多的存储库类型,因此实体可能需要更多的要求。要查看更复杂的示例,下载示例文件,并看看它如何与多个存储库(在这种情况下,网络存储和本地存储结合,列出用户)一起工作。

以下是目前可用的存储库列表(对于每个存储库,检查需要进行实现的协议,对于实体和存储库两种情况)

  • CRUD 网络存储库:这是使用案例中指定的。
  • CRUD 网络存储库(字典):它与前面的一样,但是只能表示字典。
  • CRUD 网络与存储库:它管理的操作与其他CRUD存储库相同,但它将能够在网络存储库和存储库(都可以作为子项)中操作,保持它们同步的。
  • 可同步存储库
    • 目的:用于同步多个存储库。
    • API要求
      • 请求:'url/path/collection'。
      • 方法:POST。
      • 参数:包含所有未同步实体的对象数组。
      • 返回:含有额外属性的对象的排序列表,如果需要。
    • 用法:只需实现它,然后就可以调用`synchronize`方法。
  • 可修复的仓库(仅适用于网络情况)
    • 目的:避免在修改资源时发送不必要的数据。
    • API要求
      • 请求:'url/path/:id'。
      • 方法:PATCH。
      • 参数:一个代表旧版与新版之间差异的对象。
      • 返回:如果需要,带有额外属性的对象。
    • 用法:实现协议,并在发起请求且API上有所修改时,每次都注意更新'memoryDictionary'。

通信

  • 如果您需要帮助,请提出一个问题。
  • 如果您发现了一个错误,请提出一个问题。
  • 如果您有对功能的需求,请提出一个问题。
  • 如果您想要贡献力量,请提交一个pull request。

作者

Luciano Polit,[email protected]

许可证

RepositoryKit遵循MIT许可。有关更多信息,请参阅LICENSE文件。