BZObjectStore automatically stores your models to SQLite tables and provides useful options to your application.
16/10/2014 iOS 8 supported
- iOS
5.06.0 or later - OS X 10.8 or later
- ARC
- Easy to use
- Mapping Models to SQLite tables
- Relationship in NSObject, NSArray, NSDictionary, NSSet, NSOrderedSet support
- Automatic Schema Creating
- Thread Safety
- Lazy fetching,One time Update and other useful options
- Any super class not required in your model
- ActiveRecord support
- Parse.com support
BZObjectStore can be installed using CocoaPods.
pod 'BZObjectStore'
pod 'BZObjectStore/CoreLocation' // if needed
pod 'BZObjectStore/ActiveRecord' // if needed
pod 'BZObjectStore/Parse' // if needed
#import "BZObjectStore.h"
NSError *error = nil;
// open datbase
BZObjectStore *os = [BZObjectStore openWithPath:@"database.sqlite" error:&error];
// save a object
[os saveObject:YOUROBJECT error:&error];
// close database
[os close];
After processing, you can find 'database path=/XXXX/database.sqlite' in the console.
Open this file with your SQLite tool and check tables.
#import "BZObjectStore.h"
@interface SampleModel : NSObject
@property (nonatomic,strong) NSString *name;
@property (nonatomic,assign) NSInteger price;
@property (nonatomic,strong) SampleModel *sample;
@end
@implementation SampleModel
@end
SampleModel *sample1 = [[SampleModel alloc]init];
sample1.name = @"sample1";
sample1.price = 100;
SampleModel *sample2 = [[SampleModel alloc]init];
sample2.name = @"sample2";
sample2.price = 50;
sample2.sample = sample1;
#import "BZObjectStore.h"
NSError *error = nil;
// default path is NSLibraryDirectory
BZObjectStore *os = [BZObjectStore openWithPath:@"database.sqlite" error:&error];
// open in memory
BZObjectStore *os = [BZObjectStore openWithPath:nil error:&error];
// save a object
[os saveObject:sample1 error:&error];
// save objects in array
[os saveObjects:@[sample1,sample2] error:&error];
// fetch objects
NSArray *fetchObjects = [os fetchObjects:[SampleModel class] condition:nil error:&error];
// fetch latest data from database
SampleModel *latest = [os refreshObject:sample1 error:&error];
// fetch referencing objects
NSArray *referencingObjects = [os fetchReferencingObjectsTo:sample1 error:&error];
// delete a object
[os deleteObject:sample1 error:&error];
// delete objects
[os deleteObjects:[SampleModel class] condition:nil error:&error];
// delete objects in array
[os deleteObject:@[sample1,sample2] error:&error];
BZObjectStoreConditionModel *fetchCondition = [BZObjectStoreConditionModel condition];
fetchCondition.sqlite.where = @"name = 'sample1' and price > 50";
fetchCondition.sqlite.orderBy = @"name desc";
NSArray *objects = [os fetchObjects:[SampleModel class] condition:fetchCondition error:&error];
BZObjectStoreConditionModel *deleteCondition = [BZObjectStoreConditionModel condition];
deleteCondition.sqlite.where = @"name = 'sample1'";
[os deleteObjects:[SampleModel class] condition:deleteCondition error:&error];
// close database
[os close];
NSNumber *count = [os count:[SampleModel class] condition:nil error:&error];
NSNumber *max = [os max:@"price" class:[SampleModel class] condition:nil error:&error];
NSNumber *min = [os min:@"price" class:[SampleModel class] condition:nil error:&error];
NSNumber *sum = [os sum:@"price" class:[SampleModel class] condition:nil error:&error];
NSNumber *total = [os total:@"price" class:[SampleModel class] condition:nil error:&error];
NSNumber *avg = [os avg:@"price" class:[SampleModel class] condition:nil error:&error];
[os inTransaction:^(BZObjectStore *os, BOOL *rollback) {
NSError *error = nil;
[os saveObject:sample1 error:&error];
[os saveObject:sample2 error:&error];
// rollback if needed
*rollback = YES;
}];
// Improve response time (Not required but recommended)
[os registerClass:[SampleModel class] error:&error];
[os unRegisterClass:[SampleModel class] error:&error];
There are three classes:
BZObjectStoreConditionModel
- This class contains the following classes. You create a instance and set it to each method when you need.BZObjectStoreSQLiteConditionModel
- SQLite condition.BZObjectStoreReferenceConditionModel
- Reference object condition.
// create insntance
BZObjectStoreConditionModel *condition = [BZObjectStoreConditionModel condition];
// access to BZObjectStoreSQLiteConditionModel
condition.sqlite.XXXXX
// access to BZObjectStoreReferenceConditionModel
condition.reference.XXXXX
// where condition
condition.sqlite.where = @"name = ?";
// where parameters
condition.sqlite.parameters = @[@"sample1"];
// order By
condition.sqlite.orderBy = @"code desc";
// limit
condition.sqlite.limit = @20;
// offset
condition.sqlite.offset = @20;
// set object referencing from
condition.reference.from = sample1;
// no object referencing from
condition.reference.from = [NSNull null];
// set object referenced to
condition.reference.to = sample1;
// no object referenced to
condition.reference.from = [NSNull null];
define identical attributes
#import "BZObjectStoreModelInterface.h"
@interface OrderModel : NSObject
@property (nonatomic,strong) NSString<OSIdenticalAttribute> *no;
@property (nonatomic,assign) NSArray *items;
@end
ignore attributes
#import "BZObjectStoreModelInterface.h"
@interface OrderModel : NSObject
@property (nonatomic,strong) NSString<OSIdenticalAttribute> *no;
@property (nonatomic,assign) NSArray *items;
@property (nonatomic,assign) NSIndexPath<OSIgnoreAttribute> *indexPath;
@end
do not delete relationship objects when delete a object.
#import "BZObjectStoreModelInterface.h"
@interface OrderModel : NSObject
@property (nonatomic,strong) NSString<OSIdenticalAttribute> *no;
@property (nonatomic,strong) NSArray<OSWeakReferenceAttribute> *items;
@end
@interface ItemModel : NSObject
@property (nonatomic,strong) NSString<OSIdenticalAttribute> *code;
@property (nonatomic,assign) NSInteger price;
@end
fetch relationship objects only when refreshObject method, does not fetch when fetchObjects method.
#import "BZObjectStoreModelInterface.h"
@interface NodeModel : NSObject
@property (nonatomic,strong) NSArray<OSFetchOnRefreshingAttribute> *children;
@end
do not update attributes when value is nil.
#import "BZObjectStoreModelInterface.h"
@interface ProfileModel : NSObject
@property (nonatomic,strong) NSString *name;
@property (nonatomic,strong) UIImage<OSNotUpdateIfValueIsNullAttribute> *image;
@end
update attributes only one time.
#import "BZObjectStoreModelInterface.h"
@interface ProfileModel : NSObject
@property (nonatomic,strong) NSString *name;
@property (nonatomic,strong) NSDate<OSOnceUpdateAttribute> *registAt;
@property (nonatomic,strong) NSDate *updateAt;
@end
ignore super class attributes
#import "BZObjectStoreModelInterface.h"
@interface OrderModel : NSObject
@property (nonatomic,strong) NSString *remarks;
@end
@interface DailyOrderModel : OrderModel<OSIgnoreSuperClass>
@property (nonatomic,strong) NSString *no;
@property (nonatomic,assign) NSArray *details;
@end
use sqlite FTS3
#import "BZObjectStoreModelInterface.h"
@interface Address : NSObject<OSFullTextSearch3>
@property (nonatomic,assign) NSString *address;
@end
use sqlite FTS4
#import "BZObjectStoreModelInterface.h"
@interface Address : NSObject<OSFullTextSearch4>
@property (nonatomic,assign) NSString *address;
@end
prior insert performance
#import "BZObjectStoreModelInterface.h"
@interface LogModel : NSObject<OSInsertPerformance>
@property (nonatomic,assign) NSString *code;
@property (nonatomic,assign) NSString *description;
@end
prior update performance
#import "BZObjectStoreModelInterface.h"
@interface ProfileModel : NSObject<OSUpdatePerformance>
@property (nonatomic,assign) NSString *name;
@end
If primitve type, override attributeIsXXXX methods in your model instead of these options.
These methods are defined in OSModelInterface protocol.
This interface provides additional functions.
Import BZObjectStoreModelInterface.h file, implement OSModelInterface protocol in your model
and override methods you need.
+ (NSString*)OSTableName
{
return @"table_name_you_want";
}
+ (NSString*)OSColumnName:(NSString*)attributeName
{
if ([attributeName isEqualToString:@"column_name_you_want_to_change"]) {
return @"column_name_you_want";
}
return attributeName;
}
- (void)OSModelDidLoad
{
// your operation
}
- (void)OSModelDidSave
{
// your operation
}
- (void)OSModelDidDelete
{
// your operation
}
+ (BOOL)attributeIsOSIdenticalAttribute:(NSString*)attributeName
{
if ([attributeName isEqualToString:@"foo"]) {
return YES;
}
return NO;
}
+ (BOOL)attributeIsOSIgnoreAttribute:(NSString*)attributeName
{
if ([attributeName isEqualToString:@"foo"]) {
return YES;
}
return NO;
}
+ (BOOL)attributeIsOSWeakReferenceAttribute:(NSString*)attributeName
{
if ([attributeName isEqualToString:@"foo"]) {
return YES;
}
return NO;
}
+ (BOOL)attributeIsOSNotUpdateIfValueIsNullAttribute:(NSString*)attributeName
{
if ([attributeName isEqualToString:@"foo"]) {
return YES;
}
return NO;
}
+ (BOOL)attributeIsOSSerializableAttribute:(NSString*)attributeName
{
if ([attributeName isEqualToString:@"foo"]) {
return YES;
}
return NO;
}
+ (BOOL)attributeIsOSOnceUpdateAttribute:(NSString*)attributeName
{
if ([attributeName isEqualToString:@"foo"]) {
return YES;
}
return NO;
}
You can use background process methods.
Import BZObjectStoreBackground.h and call each method name + 'InBackground' methods.
#import "BZObjectStore.h"
[os saveObjectInBackground:savedObject completionBlock:^(NSError *error) {
if (!error) {
// succeed
} else {
// failed
}
}];
// refer BZObjectStoreBackground.h about other methods
Objective-C and C Data Types | SQLite Data Types | Mapping Column Names | Remarks |
---|---|---|---|
char* | INTEGER | attributeName | |
short | INTEGER | attributeName | |
int | INTEGER | attributeName | |
long | INTEGER | attributeName | |
long long | INTEGER | attributeName | |
double | REAL | attributeName | |
float | REAL | attributeName | |
unsigned char* | INTEGER | attributeName | |
unsigned short | INTEGER | attributeName | |
unsigned int | INTEGER | attributeName | |
unsigned long | INTEGER | attributeName | |
NSInteger | INTEGER | attributeName | |
CGFloat | REAL | attributeName | |
CGPoint | REAL | attributeName + '_x',+ '_y' | separated to 2 columns |
CGSize | REAL | attributeName + '_width',+ '_height' | separated to 2 columns |
CGRect | REAL | attributeName + '_x', + '_y', + '_width', + '_height' | separated to 4 columns |
NSRange | INTEGER | attributeName + '_length', + '_location' | separated to 2 columns |
NSDate | REAL | attributeName | saved as Unix time |
NSData | BLOB | attributeName | |
NSString | TEXT | attributeName | |
NSMutableString | TEXT | attributeName | |
NSNull | BLOB | attributeName | saved as null |
NSNumber | INTEGER | attributeName | saved as primitive value |
NSURL | TEXT | attributeName | saved as absolute URL string |
NSValue | BLOB | attributeName | saved as serialized |
UIColor | TEXT | attributeName | saved as RGBA string |
UIImage | BLOB | attributeName | saved as GIF binary data |
NSArray | INTEGER | attributeName | |
NSDictionary | INTEGER | attributeName | |
NSSet | INTEGER | attributeName | |
NSOrderedSet | INTEGER | attributeName | |
NSMutableArray | INTEGER | attributeName | |
NSMutableDictionary | INTEGER | attributeName | |
NSMutableSet | INTEGER | attributeName | |
NSMutableOrderedSet | INTEGER | attributeName | |
NSObject | INTEGER | attributeName | |
ID | NONE | attributeName,attributeName + '_attributeType' | separated to 2 columns |
CLLocationCoordinate2D | REAL | attributeName + '_latitude',+ '_longitude' | separated to 2 columns |
CLLocation | REAL | attributeName + '_altitude',+ '_latitude',+ '_longitude',+ '_course',+ '_horizontalAccuracy',+ '_speed',+ '_timestamp',+ '_verticalAccuracy' | separated to 8 columns |
Other C structures will be saved as NSValue. |
Objects in NSObject, NSArray, NSDictionary, NSSet, NSOrderedSet will be mapped to SQLite table automaticaly.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
BZObjectStore *os = [BZObjectStore openWithPath:@"database.sqlite" error:&error];
[BZActiveRecord setupWithObjectStore:os];
}
#import "NSObject-ActiveRecord.h"
@interface SampleModel : NSObject
@property (nonatomic,strong) NSString *name;
@property (nonatomic,assign) NSInteger price;
@property (nonatomic,strong) SampleModel *sample;
@end
@implementation SampleModel
@end
- (void)foo
{
NSError *error = nil;
SampleModel *sample = [SampleModel alloc]init];
[sample save:&error];
NSArray *samples = [SampleModel fetchs:nil error:&error];
[sample delete:&error];
}
- (void)foo
{
NSError *error = nil;
SampleModel *sample = [SampleModel alloc]init];
[sample OSSave:&error];
NSArray *samples = [SampleModel OSFetchs:nil error:&error];
[sample OSDelete:&error];
}
BZObjectStore supports the following Parse objects.
- PFObject implements PFSubclassing
- PFUser
- PFFile
- PFGeoPoint
Parse Data Types | SQLite Data Types | Mapping Column Names | Remarks |
---|---|---|---|
PFGeoPoint | REAL | attributeName + '_latitude',+ '_longitude' | separated to 2 columns |
PFFile | TEXT,BLOB | attributeName + '_name',+ '_data' | separated to 2 columns |
// migrate database
[os migrate error:&error];
When models are added attributes only, migration will be run automatically. so do not run 'migrate' method.
#import "BZObjectStore.h"
#import "FMDatabaseQueue.h"
#import "FMDatabase.h"
- (void)foo
{
BZObjectStore *os = [BZObjectStore openWithPath:@"database.sqlite" error:nil];
FMDatabaseQueue *dbQueue = os.dbQueue;
[dbQueue inDatabase:^(FMDatabase *db) {
FMResultSet *rs = [db getTableSchema:@"SampleModel"];
while (rs.next) {
NSString *columnName = [rs stringForColumnIndex:1];
}
[rs close];
}];
[os close];
}
#import "FMDatabase.h"
- (void)transactionDidBegin:(FMDatabase *)db
{
// called when call fetch,delete,save methods
}
- (void)transactionDidEnd:(FMDatabase *)db
{
// called when call fetch,delete,save methods
}
- Readonly property always will be ignored.
- Background process methods can not be used in inTransactionInBackground method.
Author: Takeshi Shimada
History: https://github.com/expensivegasprices/BZObjectStore/History.md
Inspired by AFNetworking, JSONModel and FMDB.