Git Product home page Git Product logo

fcmodel's People

Contributors

abachman avatar allenwei avatar benoitsan avatar crossforward avatar daleljefferson avatar dhennessy avatar felixlam avatar fji8ejfijai83r avatar hydhknn avatar ilyannn avatar kaspth avatar kjuly avatar l4u avatar lickel avatar lukedurrant avatar marcboquet avatar marcoarment avatar ondrejmirtes avatar ramonvic avatar randomsequence avatar slaunchaman avatar wzph avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

fcmodel's Issues

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?

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).

closeDatabase causes crash when g_instancesReadLock hasn't been initalized

I have unit tests that are crashing after the test runs when it calls [FCModel closeDatabase]. The crash happens on the following line:

    dispatch_semaphore_wait(g_instancesReadLock, DISPATCH_TIME_FOREVER);

The crash occurs because the g_instancesReadLock variable is nil. If in my test I do something that triggers the uniqueMapInit class method which in turn initializes this variable then the closeDatabase call works fine. Is there a better place to initialize this variable so closeDatabase always works?

Crash when calling +dataWasUpdatedExternally

Here's a quick rundown of the crash:

  1. +dataWasUpdatedExternally is called after a custom importing operation
  2. If at least one of the classes has no loaded instances, postChangeNotification:changedFields:instance: is called with the instance parameter set to nil.
  3. In postChangeNotification:changedFields:instance:, a nil value on instance results in a lock initialized with NULL.
  4. dispatch_semaphore_wait is called with lock at NULL.
  5. Crash!

I would have done a pull request, but I'm not sure how this should be fixed. Should we avoid calling -postChangeNotification:changedFields:instance: when no instances are loaded?

License in source files

The initial comment in each source file says that it's copyrighted. Shouldn't they be updated to instead reflect the MIT license?

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 ()

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

[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 4c00223)

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!)

Maybe -begin/endNotificationBatch should be per thread?

I am not having any actual problems with this right now, but think of this scenario:

There is a sync engine, that syncs the local database with a webservice. After downloading a set of changes, it merges them into the local database. It wraps this in a notification batch to only notify the UI once after the sync completed.

Now, while the sync engine is going through a big set of changes, the user makes a change in the ui, which would normally cause a notification to fire that tells other parts of the ui to update. But since the sync engine is busy, this notification is delayed until it finishes syncing.

This potential problem could be addressed by making -beginNotificationBatch and -endNotificationBatchAndNotify: affect the thread they are called on only.

I think this change would make a lot of sense, but I am not quite sure wether there are any drawbacks. Just throwing it out there.

PS: I think it would also be nice to have another block-based method something like this:

[FCModel performBlockWithBatchedNotifications:^{
    // do some changes
} andNotify:YES];

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?

NSDate properties get default value @(0)

I have this column in a table:

creationDate INTEGER NOT NULL

The corresponding class has a property:

@property (nonatomic) NSDate *creationDate;

Now the problem is: The code in +openDatabaseAtPath:WithDatabaseInitializer:schemaBuilder: decides that the default value for any INTEGER column is @(0), which is obviously not good for a NSDate property.

I think this should default to [NSDate dateWithTimeIntervalSince1970:0].

A simple fix would be to use -unserializedRepresentationOfDatabaseValue:forPropertyNamed: for default values.

Difficulty recreating records with -instanceWithPrimaryKey:

I have an app that has an entity with an app-supplied primary key. A possible sequence goes like this:

MyModel *m1 = [MyModel instanceWithPrimaryKey:@"xyzzy"];
// ...
[m1 save];
// ...
[m1 delete];
// ... time passes
MyModel *m2 = [MyModel instanceWithPrimaryKey:@"xyzzy"];
// ...
[m2 save];

The [m2 save] will frequently fail because the m1 instance ends up being in the cache and returned from [MyModel instanceWithPrimaryKey:@"xyzzy"]. The save then fails because the instance is marked as deleted. Calling dataWasUpdatedExternally after the delete doesn't help because the m1 instance recaches itself.

I think the solution is twofold:

  1. -instanceWithPrimaryKey: should return a new instance if the previously cached instance was marked as deleted.
  2. -recache: should not add the model to the cache if it is deleted.

If you think this approach is correct, I'll try it out and put together a pull request.

instancesMatchingSQLQuery or similar

I've found myself wanting to use ORDER in a few places and right now it's a little tricky, I'm happy to submit pull requests for any features but first I thought I'd bounce them off you.

If I want to get all the playlist items ordered by their position I have to do either:

+(NSArray *) instancesOrderedBy:(NSString *) order {
    NSString *fullQuery = [NSString stringWithFormat:@"SELECT * FROM PlaylistEntry ORDER BY %@", order];
    __block NSArray *results = nil;

    [[self databaseQueue] inDatabase:^(FMDatabase *db) {
        FMResultSet *resultSet = [db executeQuery:fullQuery];
        results = [self instancesFromResultSet:resultSet];
        [resultSet close];
    }];
    return results;
}

Or if I'm feeling like hacking something gross I could do

NSArray *items = [PlaylistEntry instancesWhere:@"1=1 ORDER BY position ASC"];

Would you take a patch to add instancesMatchingSQLQuery: or instancesOrderedBy: or both?

Not safe to persist NSURL using absoluteString() for file URLs

When persisting an NSURL to the database it is not safe to simply convert it to an absolute string and store it. If the NSURL is storing a file URL then the resulting string will not work to reconstruct a valid file URL. Instead, it should persist to disk as a bookmark in a BLOB. Since the field type would differ based on whether the NSURL is a file URL or not I am unsure how to fix this.

Crash on closeDatabase due to g_instancesReadLock hasn't been initialised

If you open a database and close it before any operation is done to it. It'll crash due to g_instancesReadLock hasn't been initialised yet, as there hasn't been any chance to call uniqueMapInit yet.

NSString *dbPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:@"testDB.sqlite3"];
[FCModel openDatabaseAtPath:dbPath withSchemaBuilder:^(FMDatabase *db, int *schemaVersion) {
}];
[FCModel closeDatabase];

NSInvalidArgumentException - setNilValueForKey

Hi,
If the database value column = NULL, an error occurs "Terminating app due to uncaught exception 'NSInvalidArgumentException', setNilValueForKey : could not set nil as the value".

- (void)decodeFieldValue:(id)value intoPropertyName:(NSString *)propertyName
{
    if (value == [NSNull null]) value = nil;
    if (class_getProperty(self.class, propertyName.UTF8String)) {
        [self setValue:[self unserializedRepresentationOfDatabaseValue:value forPropertyNamed:propertyName] forKeyPath:propertyName];
    }
}

This happens when the value = [NSNull null].

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.

Adding default sorting option

Is there a way you could do something like this?

[Person defaultOrder:@"ORDER BY pos"];

Then on queries such as allInstances it would automatically sort the array by that?

Maybe it could work by just appending that string?

Thanks!

P.S. I am totally loving this so far & am planning to use this in an upcoming app!

Replacement for -didChangeValueForFieldName:fromValue:toValue:

With the new KVO-less approach, I guess you don't plan to include a replacement for -didChangeValueForFieldName:fromValue:toValue:? If you don't, feel free to close this right away, I just wanted to ask wether I need to roll my own KVO now.

(I found it to be rather useful though. It would be nice to have something similar.)

Are queries on the main thread?

Queries happen from the main thread but are they executed on the main thread? I've looked through the code and saw the queues work but I'm not seasoned enough to grasp all of the queue bits in obj-c. :)

wrong imports

#import "FMDatabase.h"
#import "FMDatabaseQueue.h"

should become

#import <FMDB/FMDatabase.h>
#import <FMDB/FMDatabaseQueue.h>

as it's not part of the project when using cocoapods. Else you'll get 'FMDatabase.h' file not found

Allow classes to specify default values for fields

I think it would be nice to have a declarative way to give default values for not null columns.

As far as I can see, the best way right now is to override -didInit, and set default values if .existsInDatabase == NO.

Imho, it would be nicer if classes could implement a method like +defaultValueForFieldName: that takes precedence over the fieldInfos defaultValue (basically another else-if here).

That would even allow classes to set not null properties to nil temporarily, circumventing the default values.

If you would be willing to merge something like this, let me know and i'll whip up a pull request.

[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.

Proposal: remove overridable +tableName

Currently, subclasses may override this method to provide a custom table name instead of just using their class name:

+ (NSString *)tableName { return NSStringFromClass(self); }

I forgot that I even wrote that in, and I've always assumed in the rest of the code that the class name was always the table name. Humorously, custom table names don't actually work, and almost nobody noticed until now.

See #55.

Since FCModel scans the database schema after opening to get required property info, the only way to continue supporting custom table names is to use objc_getClassList to iterate through every class that exists to scan for FCModel subclasses at launch, which I think sucks.

Since they don't work anyway and the only fix would suck, I propose removing custom table names.

I know that some people have maintained forks here with custom table names or prefixes. I've chosen not to integrate them into FCModel for simplicity, easy debugging, and reasons like this — to me, this is a clear win for convention over configuration. You have a model class named OCPost? It's in a table named OCPost.

objc_msgSend() selector name: set_rowValuesInDatabase:

Are there some rules around retaining FCModel objects that aren't in the documentation? I see crashes like this one:
Exception Type: SIGSEGV
Exception Codes: SEGV_ACCERR at 0x2000000c
Crashed Thread: 0

Application Specific Information:
objc_msgSend() selector name: set_rowValuesInDatabase:

Thread 0 Crashed:
0   libobjc.A.dylib                      0x3b36f626 objc_msgSend + 6
1   podcasts                             0x00166cd7 -[FCModel reload:] (FCModel.m:710)
2   CoreFoundation                       0x30bdd1f1 __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 10
3   CoreFoundation                       0x30b5153f _CFXNotificationPost + 1716
4   Foundation                           0x3153ba3d -[NSNotificationCenter postNotificationName:object:userInfo:] + 74
5   podcasts                             0x00163671 __35+[FCModel dataWasUpdatedExternally]_block_invoke (FCModel.m:203)
6   libdispatch.dylib                    0x3b84d833 _dispatch_call_block_and_release + 8
7   libdispatch.dylib                    0x3b84d81f _dispatch_client_callout + 20
8   libdispatch.dylib                    0x3b85449f _dispatch_main_queue_callback_4CF$VARIANT$mp + 276
9   CoreFoundation                       0x30be58f1 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 6
10  CoreFoundation                       0x30be41c5 __CFRunLoopRun + 1298
11  CoreFoundation                       0x30b4ef0f CFRunLoopRunSpecific + 520
12  CoreFoundation                       0x30b4ecf3 CFRunLoopRunInMode + 104
13  GraphicsServices                     0x35a70663 GSEventRunModal + 136
14  UIKit                                0x3349a16d UIApplicationMain + 1134
15  podcasts                             0x00043ee7 main (main.m:14)
16  libdyld.dylib                        0x3b872ab7 start + 0

and it's cousin:
Exception Type: SIGSEGV
Exception Codes: SEGV_ACCERR at 0x7000000c
Crashed Thread: 0

Application Specific Information:
objc_msgSend() selector name: _rowValuesInDatabase

Thread 0 Crashed:
0   libobjc.A.dylib                      0x3a958626 objc_msgSend + 6
1   podcasts                             0x0013c849 __25-[FCModel unsavedChanges]_block_invoke (FCModel.m:790)
2   CoreFoundation                       0x30012093 __65-[__NSDictionaryM enumerateKeysAndObjectsWithOptions:usingBlock:]_block_invoke + 96
3   CoreFoundation                       0x30011fb7 -[__NSDictionaryM enumerateKeysAndObjectsWithOptions:usingBlock:] + 160
4   podcasts                             0x0013c767 -[FCModel unsavedChanges] (FCModel.m:787)
5   podcasts                             0x0013bdc5 -[FCModel reload:] (FCModel.m:714)
6   CoreFoundation                       0x300981f1 __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 10
7   CoreFoundation                       0x3000c53f _CFXNotificationPost + 1716
8   Foundation                           0x309f6a3d -[NSNotificationCenter postNotificationName:object:userInfo:] + 74
9   podcasts                             0x00138671 __35+[FCModel dataWasUpdatedExternally]_block_invoke (FCModel.m:203)
10  libdispatch.dylib                    0x3ae36833 _dispatch_call_block_and_release + 8
11  libdispatch.dylib                    0x3ae3681f _dispatch_client_callout + 20
12  libdispatch.dylib                    0x3ae3d49f _dispatch_main_queue_callback_4CF$VARIANT$mp + 276
13  CoreFoundation                       0x300a08f1 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 6
14  CoreFoundation                       0x3009f1c5 __CFRunLoopRun + 1298
15  CoreFoundation                       0x30009f0f CFRunLoopRunSpecific + 520
16  CoreFoundation                       0x30009cf3 CFRunLoopRunInMode + 104
17  GraphicsServices                     0x34f62663 GSEventRunModal + 136
18  UIKit                                0x3295516d UIApplicationMain + 1134
19  podcasts                             0x00018ee7 main (main.m:14)
20  libdyld.dylib                        0x3ae5bab7 start + 0

Create new object and specify primary key WITHOUT db query?

See edits below. My console gets flooded with these errors:

2014-08-20 12:00:29.939 app[29675:4407] Unknown error calling sqlite3_step (19: column postId is not unique) eu
2014-08-20 12:00:29.940 app[29675:4407] DB Query: INSERT INTO "Link" ("last_utc","author","kind","url","created_utc","name","lastUpdated","customImgURL","recommendedIds","gilded","hasCustomImg","selfText","thumbnail","edited_utc","score","elapsed","categoryClass","likes","commentListId","title","numComments","sortedCommentListId","postId") VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)

I'm manually creating Links with alloc/init, then using EasyMapping to fill them with data from a JSON response.

NSMutableArray *models = [NSMutableArray arrayWithCapacity:JSONArray.count];
NSArray* ids = [JSONArray valueForKeyPath:@"data.id"];
NSDictionary* existingLinks = [Link keyedInstancesWithPrimaryKeyValues:ids];

for (NSDictionary *JSONDictionary in JSONArray){
    Link *model = nil;
    if ([existingLinks objectForKey:JSONDictionary[@"data"][@"id"]]) {
        model = [existingLinks objectForKey:JSONDictionary[@"data"][@"id"]];
    }
    else {
        model = [[Link alloc] init];
        model.postId = JSONDictionary[@"data"][@"id"];
    }

    [EKMapper fillObject:model fromExternalRepresentation:JSONDictionary[@"data"] withMapping:[self linktMapping]];

    [models addObject:model];
    [model save];
}

It does not appear that I can alloc/init and then specify the primary key. The PK I'm using comes from the server, and is guaranteed to be unique. It is not supposed to be generated on the client, so I cannot reliably override primaryKeyValueForNewInstance, which it looks like init calls.

So: how should I create new objects and specify a primary key without querying for them?

Edit: After more digging, the DB error comes from the fact that primaryKeyValueForNewInstance is somehow creating duplicate keys...

Edit 2: Switching to [Link instanceWithPrimaryKey:JSONDictionary[@"data"][@"id"]]; does not stop the flood of these error messages...

Unsaved results before any model access

Before I even access any models, I get this error as I create the database schema:

FCModelDatabaseQueue has an open FMResultSet after inDatabase:

Why would this happen before I use any models?

Thanks!

Autoincrement legacy treatment

From my understanding sqlite treats all primary integer key columns as "somewhat" AUTOINCREMENT:
http://www.sqlite.org/faq.html#q1

Is the legacy treatment in +primaryKeyValueForNewInstance really necessary? Would it be possible to introduce a macro to disable it?

While we have updated the model to remove the autoincrement, our alpha app tester have a good bit of valuable data in the old scheme (autoincrement is a pain to remove). Is there an issue I overlooked when running the new logic on old schemes (as a temporary measure)?

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 💥!

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?

SIGABRT on FCModel dealloc

This one seems to be fairly consistent in terms of crashing:
Exception Type: SIGABRT
Exception Codes: #0 at 0x3b9281f0
Crashed Thread: 0

Thread 0 Crashed:
0   libsystem_kernel.dylib               0x3b9281f0 __pthread_kill + 8
1   libsystem_pthread.dylib              0x3b992797 pthread_kill + 56
2   libsystem_c.dylib                    0x3b8d8fdd abort + 74
3   libsystem_malloc.dylib               0x3b950d67 free + 380
4   libobjc.A.dylib                      0x3b36c3ad object_dispose + 18
5   podcasts                             0x0016d639 -[FCModel dealloc] (FCModel.m:778)
6   libobjc.A.dylib                      0x3b374b6b objc_object::sidetable_release(bool) + 172
7   CoreFoundation                       0x30b4b93d CFRelease + 554
8   CoreFoundation                       0x30b666e3 -[__NSSetI dealloc] + 124
9   libobjc.A.dylib                      0x3b374b6b objc_object::sidetable_release(bool) + 172
10  libobjc.A.dylib                      0x3b3750d7 (anonymous namespace)::AutoreleasePoolPage::pop(void*) + 356
11  CoreFoundation                       0x30b4ec69 _CFAutoreleasePoolPop + 14
12  CoreFoundation                       0x30be41cb __CFRunLoopRun + 1304
13  CoreFoundation                       0x30b4ef0f CFRunLoopRunSpecific + 520
14  CoreFoundation                       0x30b4ecf3 CFRunLoopRunInMode + 104
15  GraphicsServices                     0x35a70663 GSEventRunModal + 136
16  UIKit                                0x3349a16d UIApplicationMain + 1134
17  podcasts                             0x00049ee7 main (main.m:14)
18  libdyld.dylib                        0x3b872ab7 start + 0

Any ideas what this could be? Seems like an FCModel object is in a set, the set gets released then it crashes. Latest version as at 2 July 2014.

registerUniqueInstance method?

I ran into a problem where I got two object instances of the same database row.

It's contradicting the README.md section "Retention and caching":

Each FCModel instance is exclusive 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).

This is what I did:

MyFCModel *newlyCreated = [MyFCModel new];
foo.myField = @"123";
[newlyCreated save];

NSArray *array = [MyFCModel instancesWhere:@"myField == ?", @"123"];
NSAssert(array.count == 1, @"More than 1 element");

MyFCModel *first = [array firstObject];

if (newlyCreated != first) {
    NSLog(@"%@ and %@ are different objects!", newlyCreated, first);
}

After some digging in FCModel.m I found the method registerUniqueInstance . It is neither used anywhere nor publicly exposed in FCModel.h . After exposing the method and calling it on my newly created object everything worked fine and I got only one instance.

Any thoughts on this? Is there something bogus? I'm not that deep into the FCModel source to finally say what's the best solution or if I'm misunderstanding something.

Allow use of FMDB's NSDate serialization

While I think storing NSDates as doubles is the best in most cases, FMDB has the option to store dates as strings, and in some cases I think it can be useful.
Also, it seems that if you do nothing it already converts dates to doubles, I don't know if you needed to do it on the FCModel side for some other reason.

Here's the relevant portion of FMDatabase: https://github.com/ccgus/fmdb/blob/395f7b7a9800fbe51f3a31ffb275481b5939999b/src/FMDatabase.m#L451-L456
It allows using your own NSDateFormatter using +[FMDatabase storeableDateFormat:] and -setDateFormat:

I have it more or less working on my fork (maybe it's not the best approach though), if you think it's something you'd like to add I can put some more time into polishing and testing it.

Using PRAGMA user_version

Is there any reason that the user_version PRAGMA was not used for storing the schema version instead of storing it inside the metadata table? If not, might it not be preferable?

id property is recognized as primitive type

I have a model class that has a property named value, of type id.

Depending on some external information, my implementations of -serializedDatabaseRepresentation... and -unserializedDatabaseRepresentation... will convert the database value into one of some possible types (NSDate, NSString, NSNumber, ...).

For this property, FCModel warns me about allowing NULL and says the property is a primitive type, while it very much isn't.

I don't know if this has any further implications or if it is just the warning.

(fwiw, the database colum is declared without any type)

Create +instancesOrderedBy

What does you think of adding an instancesOrderedBy method? Right now I am doing this with a where query.

[Person instancesWhere:@"id order by `createdTime` desc"];

It would be nice if I could do:

[Person instancesOrderedBy:@"`createdTime` desc"];

I don't want to override +allInstances because I sort my models differently depending on the case. What do you think?

Cached instances after update

Hello, I am having problem with cached instances of my models,
I create the initial instance with

[MyModel instanceWithPrimaryKey:ID]

After building the model, we perform some queries with

[MyModel inDatabaseSync:^(FMDatabase *db) {
    [db executeUpdate: QUERY]
}];  

updating some fields in the database, and call

[MyModel dataWasUpdatedExternally];

After these updates in another thread I call instanceWithPrimaryKey, and the model is returning with outdated data before the updates.
Is there any way around this?

Thanks

Insert/Update multiple objects

Which FCModel function to use to insert/update multiple objects at once (for eg. passing an array of FCModel objects to save function)?

Add ability to use a different table name than the class name

We're building our iOS and Android apps in tandem and were looking to keep our schemas aligned. With FCModel, we had to force our class prefix on the table name.

It would be a nice-to-have for expandQuery to use a specific table name of our choosing.

Example: JBPerson.h corresponds to table Person.

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.

"FCModel 2" non-unique-instances branch

Just pushed the first commit e0f9b3d of what might be called "FCModel 2" to the "non-unique-instances" branch. This is a big, likely-breaking change that applies a lot of lessons learned since the original design:

Instances are no longer tracked or kept unique in memory. All instances are "detached".

  • You can have two instances in memory of the same logical model (same table and primary key).
  • Changes made to a model object or table won't affect any other copies in memory.
  • If you want your interface to react to changes, you must reload any data in response to FCModel's change notifications.
  • dataWasUpdatedExternally, reloads, and conflict resolution are no longer necessary and have been removed.
  • allLoadedInstances is no longer possible and has been removed.
  • Transactions are now supported, although limited. (Rollbacks don't revert changed models in memory.)
  • Autoincrement, formerly deprecated, is now removed and will raise an exception.

All saves and deletes are expected to succeed. Saves shouldn't unexpectedly fail or be blocked.

  • Removed should/didInsert/Update/Delete, saveWasRefused, saveDidFail. To customize behavior, override save and call [super save] from the subclass.
  • FCModelSaveResult is removed. delete now returns void and save now returns a BOOL to indicate whether changes were made.
  • Saves and deletes that fail from database errors now raise exceptions. lastSQLiteError is removed.
  • All FCModel exceptions now have name FCModelException.
  • saveAll has been removed. Saves should happen intentionally, right after you change the data.
  • Custom serializations for NSURL, NSDate, etc. have been removed to avoid a lot of subtle bugs and inconsistencies between formats.

Notifications have been simplified to just a single FCModelChangeNotification for any change to a table.

  • FCModelInstanceSetKey has been replaced by FCModelInstanceKey and will always be one instance if known, or unset for many/unknown.
  • Notification-batching functions are now redundant and have been removed since transactions also batch notifications.

Take a look and see what you think so far. What other changes should we consider now that we're breaking things?

PLEASE don't ship any apps with this yet.

Support for transactions

Any chance you can add support for transactions?

Sometimes, it's very handy to have control over these when adding/updating items.

Regards,

Pieter

Saving deleted instances

Calling [FCModel saveAll] gives me an exception if I've got deleted instances still around, complaining about saving deleted instances. Currently I'm getting around this with an "if (deleted) return;" in saveByNotification.
Apologies if I missed something though, I only switched over from CoreData today.

[FMResultSet next] takes too long on app startup

I'm opening the connection to the database like the sample code shows and while running it through Instruments, I'm getting around ~3.7s for [FMResultSet next] under Time Profiler.

In my DB, I have 20 items, with negligible BLOB data and several attributes — nothing too fancy nor complicated.

Hi

My speculation is that I'm iterating through an NSArray that is the returned value of calling my model's -allInstances but it seems that operation should be performant.

I'm not sure if there is a spinlock occurring in [FMResultSet next] but I'm curious to hear if anyone has encountered this before.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.