Search code examples
iosswiftcore-dataentity

Programmatically create entity/table using CoreData and insert values into that entity in Swift 3 for iOS


I have been trying to find a way to programmatically create the database entity/table at runtime in Swift 3 for iOS platform. Please explain the process in detail. I have followed other links but nothing worked for me and I was unable to understand the process properly so please explain the whole process with working code instead of providing other existing links.

There is one more table which has been added from XCode and I can perform the database related operations (insert row, delete, update) on that table but I am unable to find a way to perform following operations on the table which will be created programmatically at run time. There are following operations that need to be performed.

Add Entity - From interface, user can add entity name, number of columns, column names then on tapping a button the entity should be created into the database using CoreData. User can add any number of tables from the interface.

Insert Values - Then user will have interface to insert values into the entity. The name of the entity will be known and the values for a row in the entity will be entered by user. On tapping a button the row should be inserted into the entity/database-table.

Fetch Values - User will have an option to fetch all the saved values form the entity. To use them anytime when needed.

Update value - User will be able to update any value present in the table which was created programmatically.

Delete Entity - There will be an option to delete the database entity as well. On tapping a button, the name of the entity will be passed to the function and that entity/database-table will be deleted from the database.

I have tried the following code -:

    let model = NSManagedObjectModel()
    let entityName = "TestEntity"
    let entity = NSEntityDescription()
    entity.name = entityName
    entity.managedObjectClassName = entityName

    // Creating a attribute
    let remoteURLAttribute = NSAttributeDescription()
    remoteURLAttribute.name = "columnOne"
    remoteURLAttribute.attributeType = .stringAttributeType
    remoteURLAttribute.isOptional = true
    remoteURLAttribute.isIndexed = true

    var properties = Array<NSAttributeDescription>()
    properties.append(remoteURLAttribute)
    // Adding the attribute to the entity
    entity.properties = properties

    // Adding the entity into the model
    model.entities = [entity]

    do {
        try CoreDataManager.managedObjectContext.save()
    } catch {
        print(error)
    }

    // Inserting the data into the entity
    let testEntity = NSManagedObject(entity: entity, insertInto: CoreDataManager.managedObjectContext)
    testEntity.setValue("WHY SO SERIOUS?", forKey: "columnOne")

    do {
        try CoreDataManager.managedObjectContext.save()
    } catch {
        print(error)
    }

    // Fetching the data from the entity
    let request = NSFetchRequest<NSFetchRequestResult>()
    request.entity = entity
    request.propertiesToFetch = ["columnOne"]
    request.returnsDistinctResults = false
    do {
        let results = try CoreDataManager.managedObjectContext.fetch(request)
        print(results)
    } catch {

    }

I am getting the following value in the results -:

▿ 1 element - 0 : (entity: TestEntity; id: 0x600000422f80 ; data: { columnOne = "WHY SO SERIOUS?"; })

But I don't have any way to get the values from this entity anywhere else and insert the values into the entity from other places as well by using entity name which is TestEntity in this case.


Solution

  • Some of the steps you describe are simply not possible with Core Data. Or at least, not without making things extremely complex and difficult for you. Asking for complete working code is not reasonable because you have an extremely unusual and complex set of requirements for Core Data.

    It's true that the NSManagedModel and all of the entities are mutable and can be changed in code. Except, all of these changes must be made before you use that model to load any data. You cannot make changes after you call loadPersistentStores(_:) (if you're using NSPersistentContainer) or addPersistentStore(ofType:configurationName:at:options:) (if you're not using NSPersistentContainer). Doing so is a run-time error that will crash your app.

    Because of this, the idea of providing a user interface to dynamically create and delete Core Data entities is not really an option. You can create and delete instances of entities but not the entity descriptions.

    If you're willing to do a lot of hard work, you might be able to get something close. The closest you could get with Core Data would be to create an entirely new managed object model any time you need a change. Then copy all of your data to a new persistent store file using this model (including whatever custom code you need to handle non-lightweight migration). Then delete the old model and persistent store file and all references to all objects that you previously fetched with them.

    This will be very difficult to get right and may have unforeseen difficulties that I haven't thought of. I would strongly urge not attempting to do this with Core Data, because it was not designed to be used in this way.