Статьи

Быстрые и базовые данные: сохранение данных с предварительным просмотром миниатюр

Я потратил некоторое время на добавление поддержки Core Data в мое приложение для диффузии на основе Swift и Metal . Базовые данные — это структура, которая позволяет мне сохранять различные конфигурации распространения реакции, чтобы пользователь мог сохранять и перезагружать различные шаблоны.

Существует несколько обёрток для Core Data, которые упрощают его реализацию, включая Alecrim и Sugar Record , но этот пост в блоге посвящен самой платформе. Мои первые порты захода были Jameson Quave «s отличные учебники и, конечно же , Рэй Wenderlich .

Когда я впервые создавал свое приложение, я не ставил флажок «Использовать базовые данные», поэтому моей первой задачей было создание нового проекта Swift с выбранной опцией и копирование всех внутренностей нового AppDelegate в мой и обеспечение ссылки в managedObjectModel и persistentStoreCoordinator были правильными.

Следующим шагом вручную является создание модели данных, отражающей данные, которые я хочу сохранить. Это делается с помощью FileNew  → File и выбрать модель данных под Core Data вариантов. Xcode теперь открывает редактор, в котором можно определить схему модели. Вот скриншот того, как выглядит мой ReactionDiffusionEntity :

Как только он будет создан, мне нужен класс Swift для его зеркалирования. Это делается из Редактора  → Создать NSManaged Subclass и генерирует следующий Swift:

class ReactionDiffusionEntity: NSManagedObject {
            @NSManaged var model: String
            @NSManaged var timestep: NSNumber
            @NSManaged var a0: NSNumber
            @NSManaged var a1: NSNumber
            @NSManaged var epsilon: NSNumber
            @NSManaged var delta: NSNumber
            @NSManaged var k1: NSNumber
            @NSManaged var k2: NSNumber
            @NSManaged var k3: NSNumber
            @NSManaged var f: NSNumber
            @NSManaged var k: NSNumber
            @NSManaged var du: NSNumber
            @NSManaged var dv: NSNumber
            @NSManaged var alpha: NSNumber
            @NSManaged var beta: NSNumber
            @NSManaged var gamma: NSNumber
            @NSManaged var imageData: NSData
            }

Теперь у меня есть соединение внутри
AppDelegate для доступа к платформе Core Data, модели данных и представлению модели Swift, я могу написать код для сохранения и загрузки моделей диффузии реакции. 

Я добавил два новых  экземпляра UIAlertAction в выпадающее меню гамбургеров в ReactionDiffusionEditor для сохранения и загрузки. Они вызывают saveModel ()  и loadModel ()  в моем главном контроллере представления

Чтобы сохранить, мне нужно создать экземпляр ReactionDiffusionEntity  в контексте Core Data, который копирует различные значения параметров из моего существующего объекта значения. Внутри init контроллера контроллера я создаю ссылку как на делегат приложения, так и на контекст:

 let appDelegate: AppDelegate
    let managedObjectContext: NSManagedObjectContext

    required init(coder aDecoder: NSCoder)
    {
        appDelegate = UIApplication.sharedApplication().delegate as AppDelegate

        managedObjectContext = appDelegate.managedObjectContext!
        [...]

… а затем при сохранении я создаю новую сущность на основе моей модели
ReactionDiffusionModel :

  func saveModel()
    {
        var newEntity = ReactionDiffusionEntity.createInManagedObjectContext(managedObjectContext, model: reactionDiffusionModel.model.rawValue, reactionDiffusionStruct: reactionDiffusionModel.reactionDiffusionStruct, image: self.imageView.image!)
        
       appDelegate.saveContext()

    }

managedObjectContext  и
saveContext ()  оба пришли бесплатно , когда я создал новый проект с «Использовать Core Data» проверяется.

Метод createInManagedObjectContext ()  не только вставляет новый объект в контекст, он также содержит строки, которые отображаются между моим объектом значения и сгенерированным NSManagedObject :

newItem.timestep = reactionDiffusionStruct.timestep
        newItem.a0 = reactionDiffusionStruct.a0
        newItem.a1 = reactionDiffusionStruct.a1
        newItem.epsilon = reactionDiffusionStruct.epsilon
        newItem.delta = reactionDiffusionStruct.delta
        [...]

Вы также можете заметить, что я передал изображение представления изображения контроллера представления в  createInManagedObjectContext () — используя небольшое написанное мной расширение для изменения размера изображений и UIImageJPEGRepresentation, я могу сохранить эскиз моделирования диффузии реакции в виде двоичных данных:

newItem.imageData = UIImageJPEGRepresentation(image.resizeToBoundingSquare(boundingSquareSideLength: 160.0), 0.75)

Для загрузки я использую executeFetchRequest ()  для заполнения массива ReactionDiffusionEntity :

     func loadModel()
    {
        let fetchRequest = NSFetchRequest(entityName: "ReactionDiffusionEntity")
        
        if let fetchResults = managedObjectContext.executeFetchRequest(fetchRequest, error: nil) as? [ReactionDiffusionEntity]
        {
            // retrieved fetchResults.count records....
        }

    }

 

Теперь, когда fetchResults  заполнен, я передаю его в свой BrowseAndLoadController,  который представлен в виде всплывающего диалога . Он содержит не более UICollectionView для отображения всех объектов внутри fetchResults. 

Элемент рендерер создает UIImage  версию хозяйствующего субъекта ImageData с  использованием наблюдателя на его reactionDiffusionEntity  собственности:

var reactionDiffusionEntity: ReactionDiffusionEntity?
    {
        didSet
        {
            if let _entity = reactionDiffusionEntity
            {
                label.text = _entity.model
            
                let thumbnail = UIImage(data: _entity.imageData as NSData)
            
                imageView.image = thumbnail
            }
        }

    }

Когда пользователь выбирает модель для загрузки, мне нужно сделать противоположное  createInManagedObjectContext ()  — создать объект значения из моей сущности. Я делаю это с помощью функции класса на ReactionDiffusionEntity, которая выглядит как зеркальное отображение  createInManagedObjectContext () :

class func createInstanceFromEntity(entity: ReactionDiffusionEntity) -> ReactionDiffusion!
    {
        var returnObject: ReactionDiffusion!
        
        var model: ReactionDiffusionModels = ReactionDiffusionModels(rawValue: entity.model)!
        
        switch model
        {
            case .BelousovZhabotinsky:
                returnObject = BelousovZhabotinsky()
            case .GrayScott:
                returnObject = GrayScott()
            case .FitzHughNagumo:
                returnObject = FitzhughNagumo()
        }
        
        // populate numeric params...
        returnObject.reactionDiffusionStruct.timestep = Float(entity.timestep)
        returnObject.reactionDiffusionStruct.a0 = Float(entity.a0)

        [...]

        returnObject.reactionDiffusionStruct.beta = Float(entity.beta)
        returnObject.reactionDiffusionStruct.gamma = Float(entity.gamma)
        
        return returnObject

    }

Это базовое сохранение и загрузка. Поскольку Xcode auto генерирует так много кода, Core Data — довольно простая вещь. Следующие шаги должны поддерживать удаление, редактирование и сохранение состояния между сеансами.

Весь исходный код этого проекта доступен в моем репозитории Git Hub здесь .