An alternative to Core Data for people who like having direct SQL access.

Related tags

Database FCModel
Overview

FCModel 2

An alternative to Core Data for people who like having direct SQL access.

By Marco Arment. See the LICENSE file for license info (it's the MIT license).

FCModel is a generic model layer on top of SQLite. It's intended for people who want some of Core Data's convenience, but with more control over implementation, performance, database schemas, queries, indexes, and migrations, and the ability to use raw SQL queries and SQLite features directly.

Beta status

This is a beta. I use it in Overcast, a few others are using it and making contributions, and it's stable for us so far. But the API may still change in minor but backward-incompatible ways.

Requirements

  • Xcode 5 or later
  • Deployment on iOS 6 or above, or Mac OS X 10.8 or above (it requires NSMapTable)
  • ARC only
  • FMDB, Gus Mueller's excellent Objective-C SQLite wrapper (automatic if you use CocoaPods)
  • Linking your project with sqlite3 (automatic if you use CocoaPods)

Documentation

There isn't much. Check out the FCModel.h header and the example project.

Schema-to-object mapping

SQLite tables are associated with FCModel subclasses of the same name, and database columns map to @property declarations with the same name. So you could have a table like this:

CREATE TABLE Person (
    id           INTEGER PRIMARY KEY,
    name         TEXT NOT NULL DEFAULT '',
    createdTime  REAL NOT NULL
);

CREATE INDEX IF NOT EXISTS name ON Person (name);

A single-column primary key is required. It can be an integer or a string. If you don't specify a key value upon object creation, FCModel will generate a random 64-bit signed integer key that's unique within the table. You're responsible for creating your own table indexes.

This table's model would look like this:

#import "FCModel.h"

@interface Person : FCModel

@property (nonatomic) int64_t id;
@property (nonatomic, copy) NSString *name;
@property (nonatomic) NSDate *createdTime;

@end

Property types

Database-mapped object properties can be:

  • Primitives (int, double, BOOL, int64_t, etc.) or NSNumber, limited to SQLite's precision (64-bit signed for integers).
  • NSString, which is always stored and loaded as UTF-8
  • NSData for BLOB columns

Database values may be NSString or NSNumber for INTEGER/FLOAT/TEXT columns, or NSData for BLOB columns. For columns that permit NULL, these methods may receive or return nil.

You can name your column-property ivars whatever you like. FCModel associates columns with property names, not ivar names.

Models may have properties that have no corresponding database columns. But if any columns in a model's table don't have corresponding properties and aren't returned by the subclass' ignoredFieldNames method, FCModel logs a notice to the console at launch.

Schema creation and migrations

In your application:didFinishLaunchingWithOptions: method, before any models are accessed, call FCModel's openDatabaseAtPath:withSchemaBuilder:. This looks a bit crazy, but bear with me — it's conceptually very simple.

Your schema-builder block is passed int *schemaVersion, which is an in-out argument:

  • FCModel tells you the current schema on the way in (on an empty database, this starts at 0).
  • You execute any schema-creation or migration statements to get to the next schema version.
  • You update *schemaVersion to reflect the new version.

Here's an example from that Person class described above:

NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *dbPath = [documentsPath stringByAppendingPathComponent:@"testDB.sqlite3"];

[FCModel openDatabaseAtPath:dbPath withSchemaBuilder:^(FMDatabase *db, int *schemaVersion) {
    [db beginTransaction];

    // My custom failure handling. Yours may vary.
    void (^failedAt)(int statement) = ^(int statement){
        int lastErrorCode = db.lastErrorCode;
        NSString *lastErrorMessage = db.lastErrorMessage;
        [db rollback];
        NSAssert3(0, @"Migration statement %d failed, code %d: %@", statement, lastErrorCode, lastErrorMessage);
    };

    if (*schemaVersion < 1) {
        if (! [db executeUpdate:
            @"CREATE TABLE Person ("
            @"    id           INTEGER PRIMARY KEY,"
            @"    name         TEXT NOT NULL DEFAULT '',"
            @"    createdTime  REAL NOT NULL"
            @");"
        ]) failedAt(1);

        if (! [db executeUpdate:@"CREATE INDEX IF NOT EXISTS name ON Person (name);"]) failedAt(2);

        *schemaVersion = 1;
    }

    // If you wanted to change the schema in a later app version, you'd add something like this here:
    /*
    if (*schemaVersion < 2) {
        if (! [db executeUpdate:@"ALTER TABLE Person ADD COLUMN title TEXT NOT NULL DEFAULT ''"]) failedAt(3);
        *schemaVersion = 2;
    }

    // And so on...
    if (*schemaVersion < 3) {
        if (! [db executeUpdate:@"CREATE TABLE..."]) failedAt(4);
        *schemaVersion = 3;
    }

    */

    [db commit];
}];

Once you've shipped a version to customers, never change its construction in your code. That way, on an initial launch of a new version, your schema-builder will see that the customer's existing database is at e.g. schema version 2, and you can execute only what's required to bring it up to version 3.

Creating, fetching, and updating model instances

All changes to model instances should be done within a save: block, which will be executed synchronously on the main thread.

Creating new instances (INSERTs):

// If you want a random 64-bit signed integer primary key value for .id:
Person *bob = [Person new];
// If you want to specify your own .id value:
Person *bob = [Person instanceWithPrimaryKey:@123];

[bob save:^{
    bob.name = @"Bob";
    bob.createdTime = [NSDate date];
}];

SELECT and UPDATE queries should look familiar to FMDB fans: everything's parameterized with ? placeholders and varargs query functions, and it's passed right through to FMDB. Just as with FMDB, you need to box primitives when passing them as query params, e.g. @1 instead of 1.

// Find that specific Bob by ID
Person *bob = [Person instanceWithPrimaryKey:@123];
[bob save:^{
    bob.name = @"Robert";
}];

// Or find the first person named Bob
Person *firstBob = [Person firstInstanceWhere:@"name = ? ORDER BY id LIMIT 1", @"Bob"];

// Find all Bobs
NSArray *allBobs = [Person instancesWhere:@"name = ?", @"Bob"];

You can use two shortcuts in queries:

  • $T: The model's table name. (e.g. "Person")
  • $PK: The model's primary-key column name. (e.g. "id")

Suppose you wanted to rename all Bobs to Robert, or delete all people named Sue, without loading them all and doing a million queries.

// Suppose these are hanging out here, being retained somewhere (in the UI, maybe)
Person *bob = [Person instanceWithPrimaryKey:@123];
Person *sue = [Person firstInstanceWhere:@"name = 'Sue'"]; // you don't HAVE to parameterize everything
// ...

[Person executeUpdateQuery:@"UPDATE $T SET name = ? WHERE name = ?", @"Robert", @"Bob"];

NSLog(@"This Bob's name is now %@.", bob.name);
// prints: This Bob's name is now Robert.

[Person executeUpdateQuery:@"DELETE FROM $T WHERE name = 'Sue'"];

NSLog(@"Sue is %@.", sue.deleted ? @"deleted" : @"around");
// prints: Sue is deleted.

Object-to-object relationships

FCModel is not designed to handle this automatically. You're meant to write this from each model's implementation as appropriate. This gives you complete control over schema, index usage, automatic fetching queries (or not), and caching.

If you want automatic relationship mappings, consider using Core Data. It's the right tool for that job, and FCModel isn't.

Retention and Caching

Each FCModel instance is unique in memory by its table and primary-key value. If you load Person ID 1, then some other query loads Person ID 1, they'll be the same instance (unless the first one got deallocated in the meantime).

FCModels are safe to retain for a while, even by the UI. You can use KVO to observe changes. Just check instances' deleted property where relevant, and watch for change notifications.

FCModels are inherently cached by primary key:

NSArray *allBobs = [Person instancesWhere:@"name = ?", @"Bob"];
// executes query: SELECT * FROM Person WHERE name = 'Bob'

Person *bob = [Person instanceWithPrimaryKey:@123];
// cache hit, no query executed

...but only among what's retained in your app. If you want to cache an entire table, for instance, you'll want to do something like retain its allInstances array somewhere long-lived (such as the app delegate).

Concurrency

FCModels can be used from any thread, but all database reads and writes are serialized onto the main thread, so you're not likely to see any performance gains by concurrent access.

FCModel's notifications are always posted on the main thread.

Support

None, officially, but I'm happy to answer questions here on GitHub when time permits.

Contributions

...are welcome for consideration, with the following guideline:

More than anything else, I'd like to keep FCModel small, simple, and easy to fit in your mental L2 cache.

Comments
  • Proposal: remove AUTOINCREMENT support

    Proposal: remove AUTOINCREMENT support

    The concept of a model instance with a not-yet-set primary key is weird, and requires a lot of hacky special handling. Right now, to handle AUTOINCREMENT, models may have unset primary keys from new until a successful save. In your app's various functions, there's no guarantee that any model instance actually has a primary key at the time you're operating on it (unless you check every time, which is tedious and error-prone).

    SQLite's AUTOINCREMENT documentation shows that its automatic rowid pseudo-column is already fulfilling many of the same duties for reads, which is available in any query's ORDER BY clause in FCModel already (and I could make it a property without a ton of effort).

    I've also found that I've never actually used AUTOINCREMENT. It's not well-suited to a world with sync and concurrency. In every case so far, random 64-bit integers or GUID strings have been the better choice. It's better to remove a bad option than to let people shoot themselves in the foot with it.

    I'd like to remove AUTOINCREMENT support and replace it with optional randomly generated 64-bit signed-integer primary keys. (FCModel subclasses could do their own thing, like GUID strings, if they wanted different key-generation behavior.) This would clean up the FCModel code a bit and prevent some of those weird potential bugs in usage.

    Models would no longer be permitted to instantiate without any primary key value — you'd still use instanceWithPrimaryKey: or instanceWithPrimaryKey:createIfNonexistent: normally, but if you simply called new, a random key value would be assigned that's unique among all existing values in the table and all unsaved values currently in memory. Modifying any model's primary-key value after instantiation would raise an exception.

    What do you think?

    enhancement 
    opened by marcoarment 28
  • Is there a way to create a detached copy of an object?

    Is there a way to create a detached copy of an object?

    Using FCModel, is there a way to create a detached copy of an object? I would like to be able to do something like this:

    Person *joe = [Person new];
    joe.name = @"Joe";
    [joe save];
    
    DetachedPerson *detachedJoe = [joe detachedCopy];
    DetachedPerson *secondDetachedJoe = [joe detachedCopy];
    detachedJoe == secondDetachedJoe // true
    
    joe.age = 26;
    [joe save];
    
    DetachedPerson *thirdDetachedJoe = [joe detachedCopy];
    detachedJoe == thirdDetachedJoe // false
    

    Is it possible to do something like with FCModel? It -[FCModel copy] was supported I think I could use that instead, but I'm not sure.

    opened by jasonsilberman 12
  • What is the easiest way to execute a select with a join table?

    What is the easiest way to execute a select with a join table?

    I'm using FCModel to get some records based on a join table. The query looks similar to:

    SELECT Photos.* FROM Photos JOIN PhotosetPhotos ON PhotosetPhotos.photo_id = Photos.id WHERE PhotosetPhotos.photoset_id = ?
    

    I cannot find a way however to execute this using FCModel. How should things like these be handled?

    Regards,

    pieter

    opened by pieterclaerhout 12
  • Deadlock nightmare!

    Deadlock nightmare!

    Hi there! I'm using HEAD, and I'm experiencing a deadlock. Care to have a look?

    Stack trace for Thread 1

    #0  0x030737ca in __psynch_cvwait ()
    #1  0x03038d1d in _pthread_cond_wait ()
    #2  0x0303abd9 in pthread_cond_wait$UNIX2003 ()
    #3  0x0094821b in -[__NSOperationInternal _waitUntilFinished:] ()
    #4  0x0086f1c8 in -[NSOperation waitUntilFinished] ()
    #5  0x008775ea in -[NSOperationQueue addOperations:waitUntilFinished:] ()
    #6  0x000ef7f5 in -[FCModelDatabaseQueue execOnSelfSync:] at /Users/david/Development/geranium.iosapp/Pods/FCModel/FCModel/FCModelDatabaseQueue.m:56
    #7  0x000efb43 in -[FCModelDatabaseQueue inDatabase:] at /Users/david/Development/geranium.iosapp/Pods/FCModel/FCModel/FCModelDatabaseQueue.m:75
    #8  0x000dee9b in +[FCModel instanceFromDatabaseWithPrimaryKey:] at /Users/david/Development/geranium.iosapp/Pods/FCModel/FCModel/FCModel.m:189
    #9  0x000de639 in +[FCModel instanceWithPrimaryKey:databaseRowValues:createIfNonexistent:] at /Users/david/Development/geranium.iosapp/Pods/FCModel/FCModel/FCModel.m:140
    #10 0x000de226 in +[FCModel instanceWithPrimaryKey:] at /Users/david/Development/geranium.iosapp/Pods/FCModel/FCModel/FCModel.m:121
    

    Stack trace for Thread 3

    #0  0x03073802 in __psynch_mutexwait ()
    #1  0x03039945 in _pthread_mutex_lock ()
    #2  0x030397ac in pthread_mutex_lock ()
    #3  0x0087db0d in -[NSRecursiveLock lock] ()
    #4  0x008b9b28 in -[NSObject(NSKeyValueObserverRegistration) addObserver:forKeyPath:options:context:] ()
    #5  0x000e66ab in __55-[FCModel initWithFieldValues:existsInDatabaseAlready:]_block_invoke at /Users/david/Development/geranium.iosapp/Pods/FCModel/FCModel/FCModel.m:646
    #6  0x02a7da7a in __65-[__NSDictionaryM enumerateKeysAndObjectsWithOptions:usingBlock:]_block_invoke ()
    #7  0x02a7d97e in -[__NSDictionaryM enumerateKeysAndObjectsWithOptions:usingBlock:] ()
    #8  0x029e2125 in -[NSDictionary enumerateKeysAndObjectsUsingBlock:] ()
    #9  0x000e5d80 in -[FCModel initWithFieldValues:existsInDatabaseAlready:] at /Users/david/Development/geranium.iosapp/Pods/FCModel/FCModel/FCModel.m:609
    #10 0x000df19b in __46+[FCModel instanceFromDatabaseWithPrimaryKey:]_block_invoke at /Users/david/Development/geranium.iosapp/Pods/FCModel/FCModel/FCModel.m:192
    #11 0x000efc3c in __35-[FCModelDatabaseQueue inDatabase:]_block_invoke at /Users/david/Development/geranium.iosapp/Pods/FCModel/FCModel/FCModelDatabaseQueue.m:78
    #12 0x000ef062 in -[FCModelDatabaseQueueOperation main] at /Users/david/Development/geranium.iosapp/Pods/FCModel/FCModel/FCModelDatabaseQueue.m:17
    #13 0x00948c79 in -[__NSOperationInternal _start:] ()
    #14 0x008c59c8 in -[NSOperation start] ()
    #15 0x0094af44 in __NSOQSchedule_f ()
    #16 0x02d084d0 in _dispatch_client_callout ()
    #17 0x02cf6047 in _dispatch_queue_drain ()
    #18 0x02cf5e42 in _dispatch_queue_invoke ()
    #19 0x02cf6de2 in _dispatch_root_queue_drain ()
    #20 0x02cf7127 in _dispatch_worker_thread2 ()
    #21 0x03037dab in _pthread_wqthread ()
    
    opened by hartbit 10
  • [FCModel allInstances] returns an NSArray with same value

    [FCModel allInstances] returns an NSArray with same value

    [FCModel allInstances] returns an NSArray with same value

    When I perform [Toto allInstances], it returns an NSArray containing only the same first FCModel Object at each row. NSArray Count = 230 When I perform the query on OS X SQLite Client SELECT * FROM Toto , it returns 230 distinct rows.

    SQLite Toto table definition has two primary keys : GUID & Version

    here is Toto.h :

    #import "FCModel.h"
    
    @interface Toto : FCModel
    
    // properties from sql columns model
    @property (nonatomic, copy) NSString* GUID;
    @property (nonatomic) NSDate* WalkingDate;
    @property (nonatomic) NSData* json_data;
    @property (nonatomic) NSString* user_ID;
    @property (nonatomic) NSString* SystemInfo;
    @property (nonatomic) NSNumber* Version;
    @property (nonatomic) NSString* State;
    @property (nonatomic) float LastModificationDate;
    @property (nonatomic) BOOL isDirty;
    @property (nonatomic) NSString* ReasonForChange;
    
    @end
    

    Thanks for your help.

    opened by elneruda 8
  • Add multiple-database support

    Add multiple-database support

    The way it works right now, FCModel is implemented as a bunch of class methods, relying on private global variables. It's kind of convenient, but not as flexible as I'd like. This has caused me a few issues when I wanted to open more than one database at once (for example).

    Wouldn't it be more flexible to separate the library into FCModel, the subclass of all database table/classes, and a FCDatabase or FCManager, that handles the connection to one database?

    opened by hartbit 7
  • [NSDate doubleValue] - Unrecognized selector sent to instance

    [NSDate doubleValue] - Unrecognized selector sent to instance

    I'm currently investigating an exception that's difficult to reproduce, possibly related to concurrent usage of FCModel (version 4c00223e3f)

    The exception is [NSDate doubleValue] "Unrecognized selector sent to instance", and it happens in line 241 in FCModel.m:

        } else if (propertyClass == NSDate.class) {
            return [NSDate dateWithTimeIntervalSince1970:[databaseValue doubleValue]];
    

    So, apparently, the databaseValue is already an instance of NSDate, how can this happen?

    Possibly this has to do with unsaved changes from another thread, as I'm also getting the occasional SIGSEGV in [FCModel reload]:

    __18-[FCModel reload:]_block_invoke in FCModel.m on Line 649
    __35-[FCModelDatabaseQueue inDatabase:]_block_invoke in FCModelDatabaseQueue.m on Line 79
    -[FCModelDatabaseQueueOperation main] in FCModelDatabaseQueue.m on Line 17
    

    Any help would be greatly appreciated. (And thanks for this great library!)

    opened by papauschek 6
  • Properly cleaning up [avoiding EXC_BAD_ACCESS on FCModelDatabaseQueueOperation]

    Properly cleaning up [avoiding EXC_BAD_ACCESS on FCModelDatabaseQueueOperation]

    Our app has sensitive data so we have an inactivity timeout. When the timeout occurs they have to sign in again and we close the database. Upon signing in again, we open the database and :boom:!

    EXC_BAD_ACCESS on FCModelDatabaseQueueOperation.

    0x2c542d4: jmp 0x2c5426a ; object_cxxDestructFromClass(objc_object*, objc_class*) + 22

    What is the proper way of cleaning up/closing the db?

    Creating db:

    - (void)open:(NSString *)databasePath{
        [self.logger debug:@"Opening database: %@", databasePath];
    
        [FCModel openDatabaseAtPath:databasePath withSchemaBuilder:^(FMDatabase *db, int *schemaVersion) {
            self.database = db;
    
            self.database.logsErrors = YES;
            self.database.crashOnErrors = NO;
            self.database.traceExecution = NO;
    
            [self.database beginTransaction];
    
            self.schemaVersion = *schemaVersion;
    
            [self runMigrations];
    
            *schemaVersion = self.schemaVersion;
    
            [self.database commit];
    
            [self.logger debug:@"Database ready: %@", databasePath];
        }];
    }
    
    ...
    
    - (void)close{
        if (self.database) {
            [self.database close];
        }
    }
    

    On timeout: [DBClass close];

    Thoughts? What's the best way to address this?

    opened by johncblandii 6
  • Dates remain flagged as changed after save

    Dates remain flagged as changed after save

    The issue is that the comparison in FCModel.m:750 falsely flags the unchanged NSDate as different:

    (lldb) p [(NSDate*)oldValue timeIntervalSince1970]
    (double) $0 = 1396611801.1373141
    (lldb) p [(NSDate*)newValue timeIntervalSince1970]
    (double) $1 = 1396611801.1373141
    (lldb) p [(NSDate*)newValue isEqual:(NSDate*)oldValue]
    (char) $2 = '\0'
    (lldb) p [(NSDate*)newValue isEqualToDate:(NSDate*)oldValue]
    (char) $3 = '\0'
    (lldb) p [(NSDate*)newValue timeIntervalSinceDate:(NSDate*)oldValue]
    (double) $4 = -0.000000059604644775390625
    

    I have added a unit test on a branch that shows this issue. I am currently working to identify a work around to what appears to be a rounding error somewhere.

    opened by felixLam 6
  • Add method to close current database

    Add method to close current database

    This is useful for the following cases:

    • An app might only use FCModel infrequently and wants to free up resources.
    • An app might want to allow the user specify (or change) where its data is stored.
    • Unit tests work best if each run starts with a 'clean slate'.

    This changeset also includes some initial unit tests for the library (which relies on the ability to create a fresh database for each test).

    opened by dhennessy 6
  • Using FCModel with iOS app extensions

    Using FCModel with iOS app extensions

    I am planning to update my app that uses FCModel to include Today widget that will also read data from the app's database (via app group's shared container). Should I take any measures to avoid problems when de-facto two apps are reading from the same SQLite database? (The Today widget will only read data, not write them).

    opened by ondrejmirtes 5
  • Add basic SwiftPM support for Objective-C code

    Add basic SwiftPM support for Objective-C code

    This fixes #158 for the most part. Only the Swift code adding the ObservableObject support I couldn't include because SwiftPM didn't want to accept mixed language packages. Maybe that can be fixed by splitting to two targets somehow, but as we don't need it for our project, I didn't invest the time to check. But this should be better than nothing.

    opened by Jeehut 0
  • Support for SwiftPM

    Support for SwiftPM

    Nowadays with Xcode 12.3 out already, people are starting to switch from CocoaPods and Carthage to the official Apple dependency manager SwiftPM which is built into Xcode. Adding support for it would therefore help many who are using this lib in modern projects.

    opened by Jeehut 0
  • FCModel.m: Rm useless imports

    FCModel.m: Rm useless imports

    • FCModel.h imports "FMDatabase.h" already (maybe we can use @class FMDatabase; in FCModel.h, and keep it in FCModel.m?).

    • FMDatabaseAdditions.h seems not needed in FCModel.m.

    opened by Kjuly 0
  • sqlite unique primary key generation bug

    sqlite unique primary key generation bug

    "continue" statement forces loop condition re-evaluation - while(conflict), this "conflict" value is initialized to false and does not change inside of loop body (loop will repeat itself only if condition is true, but condition is hardcoded false and will exit after first iteration) - loop will execute only once even if non unique primary key was generated, which will result in a sqlite crash (unique pk assertion failure)

    opened by Paberu85 0
  • FCModel.m unique key generation fail

    FCModel.m unique key generation fail

    For the while and do...while loops, continue statement causes the program control pass to the conditional test - 'conflict' which is initialized to NO and never changed elsewhere.

                        BOOL conflict = NO;
                        int attempts = 0;
                        do {
                            attempts++;
                            NSAssert1(attempts < 100, @"FCModel subclass %@ is not returning usable, unique values from primaryKeyValueForNewInstance", NSStringFromClass(self.class));
                            
                            id newKeyValue = [self.class primaryKeyValueForNewInstance];
                            if ([self.class instanceFromDatabaseWithPrimaryKey:newKeyValue]) continue; // already exists in database
                            [self setValue:newKeyValue forKey:key];
                        } while (conflict);
    
    opened by Paberu85 1
Releases(0.9.0)
Owner
null
🔥 🔥 🔥Support for ORM operation,Customize the PQL syntax for quick queries,Support dynamic query,Secure thread protection mechanism,Support native operation,Support for XML configuration operations,Support compression, backup, porting MySQL, SQL Server operation,Support transaction operations.

?? ?? ??Support for ORM operation,Customize the PQL syntax for quick queries,Support dynamic query,Secure thread protection mechanism,Support native operation,Support for XML configuration operations,Support compression, backup, porting MySQL, SQL Server operation,Support transaction operations.

null 60 Dec 12, 2022
Sharing SQL queries between Server and Mobile databases

Sharing SQL queries between Server and Mobile databases Overview As we all know, code is expensive to maintain, and the more complex the code, the mor

Aaron LaBeau 4 May 24, 2022
Health Care gives tips to people about his/her life to be better.

Health Care Health Care gives tips to people about his/her life to be better. How does it do this? This application examines and evaluates the health

Mehmet ateş 2 Sep 22, 2022
Realm is a mobile database: a replacement for Core Data & SQLite

Realm is a mobile database that runs directly inside phones, tablets or wearables. This repository holds the source code for the iOS, macOS, tvOS & wa

Realm 15.7k Jan 1, 2023
CoreDataCloudKitShare - Learn how to use Core Data CloudKit

Sharing Core Data Objects Between iCloud Users Implement the flow to share data

null 3 Feb 10, 2022
BowTies - The main purpose of this application is to show how you can perform simple operations using Core Data

BowTies The main purpose of this application is to show how you can perform simp

slemeshaev 1 Jan 31, 2022
Realm-powered Core Data persistent store

RealmIncrementalStore Realm-powered Core Data persistent store Wait, what? I like Realm. Realm's memory-mapped DB blows other databases out of the wat

Eureka 227 Jun 24, 2022
A stand-alone Swift wrapper around the mongo-c client library, enabling access to MongoDB servers.

This package is deprecated in favour of the official Mongo Swift Driver. We advise users to switch to that pack

PerfectlySoft Inc. 54 Jul 9, 2022
Simplified access to Apple's CloudKit

EVCloudKitDao Discuss EVCloudKitDao : What is this With Apple CloudKit, you can focus on your client-side app development and let iCloud eliminate the

Edwin Vermeer 632 Dec 29, 2022
A stand-alone Swift wrapper around the MySQL client library, enabling access to MySQL servers.

Perfect - MySQL Connector This project provides a Swift wrapper around the MySQL client library, enabling access to MySQL database servers. This packa

PerfectlySoft Inc. 118 Jan 1, 2023
A stand-alone Swift wrapper around the libpq client library, enabling access to PostgreSQL servers.

Perfect - PostgreSQL Connector This project provides a Swift wrapper around the libpq client library, enabling access to PostgreSQL servers. This pack

PerfectlySoft Inc. 51 Nov 19, 2022
A stand-alone Swift wrapper around the FileMaker XML Web publishing interface, enabling access to FileMaker servers.

Perfect - FileMaker Server Connector This project provides access to FileMaker Server databases using the XML Web publishing interface. This package b

PerfectlySoft Inc. 33 Jul 13, 2022
CloudKit, Apple’s remote data storage service, provides a possibility to store app data using users’ iCloud accounts as a back-end storage service.

CloudKit, Apple’s remote data storage service, provides a possibility to store app data using users’ iCloud accounts as a back-end storage service. He

Yalantis 252 Nov 4, 2022
Innova CatchKennyGame - The Image Tap Fun Game with keep your scores using Core Database

Innova_CatchKennyGame The Image Tap Fun Game with keep your scores using Core Da

Alican Kurt 0 Dec 31, 2021
A clicker-like game based on the concept of a Knight abandoned in space

A Knight in Space A clicker-like game based on the concept of a Knight abandoned in space. Team Members Albin Shrestha, Zac Galer, Connor Kite, and Ma

Albin Shrestha 1 Feb 7, 2022
An e-commerce app with some function: searching, like product, demo paying and view product

Emarket_060921 An e-commerce app with some function: searching, like product, demo paying and view product. I have developed this app all by myself, b

null 0 Jan 17, 2022
HoneycombView is the iOS UIView for displaying like Honeycomb layout written by swift

HoneycombView iOS UIView for Honeycomb layout include with photoBrowser. Requirements iOS 8.0+ Swift 2.0+ ARC ##Installation ####CocoaPods HoneycombVi

keishi suzuki 200 May 16, 2022
🛶Shallows is a generic abstraction layer over lightweight data storage and persistence.

Shallows Shallows is a generic abstraction layer over lightweight data storage and persistence. It provides a Storage<Key, Value> type, instances of w

Oleg Dreyman 620 Dec 3, 2022
Disk is a powerful and simple file management library built with Apple's iOS Data Storage Guidelines in mind

Disk is a powerful and simple file management library built with Apple's iOS Data Storage Guidelines in mind

Saoud Rizwan 3k Jan 3, 2023