contentful-persistence.swift

Version Carthage compatible License Platform Build Status Coverage Status

一个简化将数据从 Contentful 持久化到本地 CoreData 数据库的集成方案;构建于官方 Contentful Swift 库之上。该库专门使用 Content Delivery API 的 /sync 端点,将 Contentful 空间中的所有内容同步到设备。

什么是 Contentful?

Contentful 为数字团队提供内容基础设施,以便在网站、应用程序和设备中提供内容。与 CMS 不同,Contentful 旨在与现代软件栈集成。它为结构化内容提供了一个中央枢纽、强大的管理和交付 API,以及一个可定制的 Web 应用程序,使开发人员和内容创建者能够更快地交付数字产品。

开始使用

前提条件

在开始之前,强烈建议您熟悉 Apple 的 CoreData 框架,因为开发过程中遇到的许多问题可能特定于 CoreData。阅读 CoreData 编程指南并查看其他(非 Contentful)示例。

用法

SynchronizationManager 管理您的 CoreData 数据库的状态,并使其与来自您的 Contentful 空间的数据保持同步。

// Tell the library which of your `NSManagedObject` subclasses that conform to `EntryPersistable` should be used when mapping API responses to CoreData entities.
let entryTypes = [Author.self, Category.self, Post.self]

// Initialize the data store and it's schema.
let store = CoreDataStore(context: self.managedObjectContext)
let persistenceModel = PersistenceModel(spaceType: SyncInfo.self, assetType: Asset.self, entryTypes: entryTypes)

// Initialize the Contentful.Client with a persistenceIntegration which will receive messages about changes when calling `sync methods`
self.client = Client(spaceId: "<YOUR_SPACE_ID>", accessToken: "<YOUR_ACCESS_TOKEN>")

// Create the manager.
self.syncManager = SynchronizationManager(
    client: self.client,
    localizationScheme: LocalizationScheme.all, // Save data for all locales your space supports.
    persistenceStore: self.store,
    persistenceModel: persistenceModel
)

// Sync with the API.
self.syncManager.sync { _ in
  do {
    // Fetch all `Posts` from CoreData
    let post: Post? = try self.store.fetchAll(type: Post.self, predicate: NSPredicate(value: true))
  } catch {
    // Handle error thrown by CoreData fetches.
  }
}

SpaceType 和 AssetType

PersistenceModel 需要同时指定 spaceTypeassetType。这些分别对应于 Core Data 实体,用于存储 SyncInfoAsset 对象。

为了正常运行,这些对象必须

示例实现

class SyncInfo: NSManagedObject, SyncSpacePersistable {
    @NSManaged var syncToken: String?
    @NSManaged var dbVersion: NSNumber?
}

class Asset: NSManagedObject, AssetPersistable {
    @NSManaged var id: String
    @NSManaged var localeCode: String?
    @NSManaged var title: String?
    @NSManaged var assetDescription: String?
    @NSManaged var urlString: String?
    @NSManaged var createdAt: Date?
    @NSManaged var updatedAt: Date?

    @NSManaged var size: NSNumber?
    @NSManaged var width: NSNumber?
    @NSManaged var height: NSNumber?
    @NSManaged var fileType: String?
    @NSManaged var fileName: String?
}

然后在 xcdatamodeld 文件中:

定义您的 CoreData 模型

要将您的模型类与 contentful-persistence.swift 集成,您必须遵循 Contentful Assets 的 AssetPersistable 协议或 Contentful 条目类型的 EntryPersistable 协议。

接下来,您需要在项目的 xcdatamodel 文件中创建相应的模型。EntryPersistableAssetPersistable 类型都需要一个非可选 id 属性,以及可选的 localeCodecreatedAtupdatedAt 属性。

注意: Core Data 实体中的可选性与 Swift 可选性不同。对于 Core Data 实体,可选性意味着在保存到数据库操作期间,属性可能不存在。要配置属性的可选性,请打开 Xcode "Utilities" 右侧边栏中的“数据模型检查器”,然后切换“可选”复选框。

Contentful 字段到您的数据模型实体的映射将自动派生,但您也可以通过在您的类上实现 static func fieldMapping() -> [FieldName: String]? 来定制它。

下面是一个模型类的示例。

import Foundation
import CoreData
import ContentfulPersistence
import Contentful

// The following @objc attribute is only necessary if your xcdatamodel Default configuration doesn't have your module
// name prepended to the Swift class. To enable removing the @objc attribute, change the Class for your entity to `ModuleName.Post`
@objc(Post)
class Post: NSManagedObject, EntryPersistable {

    // The identifier of the corresponding Content Type in Contentful.
    static let contentTypeId = "post"

    // Properties of the `sys` object of Contentful resources.
    @NSManaged var id: String
    @NSManaged var localeCode: String?
    @NSManaged var createdAt: Date?
    @NSManaged var updatedAt: Date?

    // Custom fields on the content type.
    @NSManaged var body: String?
    @NSManaged var comments: NSNumber?
    // NOTE: Unlike date fields in sys properties, this library can't store `Date` for custom fields.
    // Use `String` and map to date after fetching from CoreData
    @NSManaged var customDateField: String?
    @NSManaged var date: Date?
    @NSManaged var slug: String?
    @NSManaged var tags: Data?
    @NSManaged var title: String?
    @NSManaged var authors: NSOrderedSet?
    @NSManaged var category: NSOrderedSet?
    @NSManaged var theFeaturedImage: Asset?

    // Define the mapping from the fields on your Contentful.Entry to your model class.
    // In the below example, only the `title`, `date` and `author` fields and `featuredImage` link will be populated.
    // IMPORTANT: This should not include metadata from the `sys` object (e.g. id, createdAt, etc.)
    static func fieldMapping() -> [FieldName: String] {
        return [
            "title": "title",
            "featuredImage": "theFeaturedImage",
            "author": "authors"
            "date": "date"
        ]
    }
}

关系

假设我们在 Contentful 空间中有以下内容模型

Product
- name: String
- relatedProducts: [Product]

它表示具有名称和相关产品的产品。这将转换为我们的 Swift 模型,如下所示

class Product: NSManagedObject {
    // Contentful metadata
    @NSManaged var id: String
    @NSManaged var localeCode: String?
    @NSManaged var createdAt: Date?
    @NSManaged var updatedAt: Date?

    // Defined properties in Contentful
    @NSManaged public var name: String?
    @NSManaged public var relatedProducts: NSOrderedSet?
}

extension Product: EntryPersistable {
    public static var contentTypeId = "product"
    public static func fieldMapping() -> [FieldName: String] {
        return [
            "name": "name",
            "relatedProducts": "relatedProducts",
        ]
    }
}

相应的 CoreData 实体如下所示:

注意类型和设置为 ordered 的排列。

从数据库获取产品后,可以像这样访问相关产品

for product in products {
  if let relatedProductsSet = product.relatedProducts,
      let productsArray = relatedProductsSet.array as? [Product]
  {
      // productsArray is now [Product]
      for product in productsArray {
          // Access product properties here, e.g., product.name
          print("Related product:", product.id, product.name)
      }
  } else {
      print("No related products or unable to cast")
  }
}

安装

SPM 安装

您还可以使用 Xcode(Swift 3.0+)捆绑的 Swift Package Manager 将 Contentful Persistence 作为依赖项添加到您的项目中。为此,请选择您的项目,将选项卡更改为“Package Dependencies”,然后添加以下 URL


https://github.com/contentful/contentful-persistence.swift

您需要使用 "master" 分支。

CocoaPods 安装

CocoaPods 是 Objective-C 和 Swift 的依赖项管理器,它可以自动化和简化在您的项目中使用 ContentfulPersistence 等第三方库的过程。

platform :ios, '9.3'
use_frameworks!

target :MyApp do
  pod 'ContentfulPersistenceSwift', '~> 0.13.0'
end

Carthage 安装

您还可以使用 Carthage 进行集成,方法是将以下内容添加到您的 Cartfile

github "contentful/contentful.swift" ~> 0.13.0

文档

有关更多信息,请查看 开发人员文档或浏览 API 文档。后者也可以作为 Docset 加载到 Xcode 中。

贡献和开发

要开始贡献,请克隆项目,cd 到根目录并运行以下命令:make setup_env

make setup_env
carthage bootstrap --platform all

此命令将安装构建项目并执行测试所需的所有开发依赖项。要从命令行运行测试,请执行 make test。测试也应该都可以直接从 Xcode 应用程序运行。

许可证

版权所有 (c) 2018 Contentful GmbH。有关更多详细信息,请参见 LICENSE