├── .DS_Store
├── .swift-version
├── BGFMDB.podspec
├── BGFMDB.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ ├── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
│ └── xcuserdata
│ │ ├── biao.xcuserdatad
│ │ └── UserInterfaceState.xcuserstate
│ │ └── huangzhibiao.xcuserdatad
│ │ └── UserInterfaceState.xcuserstate
└── xcuserdata
│ ├── biao.xcuserdatad
│ ├── xcdebugger
│ │ └── Breakpoints_v2.xcbkptlist
│ └── xcschemes
│ │ ├── BGFMDB.xcscheme
│ │ └── xcschememanagement.plist
│ └── huangzhibiao.xcuserdatad
│ ├── xcdebugger
│ └── Breakpoints_v2.xcbkptlist
│ └── xcschemes
│ ├── BGFMDB.xcscheme
│ └── xcschememanagement.plist
├── BGFMDB
├── .DS_Store
├── AppDelegate.h
├── AppDelegate.m
├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ ├── Contents.json
│ ├── MarkMan.imageset
│ │ ├── Contents.json
│ │ └── MarkMan.png
│ ├── ima1.imageset
│ │ ├── Contents.json
│ │ └── ima1.jpg
│ ├── ima2.imageset
│ │ ├── Contents.json
│ │ └── ima2.jpg
│ ├── ima3.imageset
│ │ ├── Contents.json
│ │ └── ima3.jpg
│ ├── ima4.imageset
│ │ ├── Contents.json
│ │ └── ima4.png
│ └── ima5.imageset
│ │ ├── Contents.json
│ │ └── ima5.jpg
├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
├── Info.plist
├── ViewController.h
├── ViewController.m
├── dictToModelController
│ ├── Animal.h
│ ├── Animal.m
│ ├── dictToModelController.h
│ ├── dictToModelController.m
│ └── dictToModelController.xib
├── file.txt
├── libs
│ ├── .DS_Store
│ ├── BG
│ │ ├── .DS_Store
│ │ ├── BGDB.h
│ │ ├── BGDB.m
│ │ ├── BGFMDB.h
│ │ ├── BGFMDBConfig.h
│ │ ├── BGTool.h
│ │ ├── BGTool.m
│ │ ├── NSCache+BGCache.h
│ │ ├── NSCache+BGCache.m
│ │ ├── NSObject+BGModel.h
│ │ └── NSObject+BGModel.m
│ └── FMDB
│ │ ├── .DS_Store
│ │ ├── FMDB.h
│ │ ├── FMDatabase.h
│ │ ├── FMDatabase.m
│ │ ├── FMDatabaseAdditions.h
│ │ ├── FMDatabaseAdditions.m
│ │ ├── FMDatabasePool.h
│ │ ├── FMDatabasePool.m
│ │ ├── FMDatabaseQueue.h
│ │ ├── FMDatabaseQueue.m
│ │ ├── FMResultSet.h
│ │ ├── FMResultSet.m
│ │ └── Info.plist
├── main.m
├── people.h
├── people.m
└── stockController
│ ├── stockController.h
│ ├── stockController.m
│ ├── stockController.xib
│ ├── stockModel.h
│ └── stockModel.m
├── BGFMDBTests
├── BGFMDBTests.m
└── Info.plist
├── BGFMDBUITests
├── BGFMDBUITests.m
└── Info.plist
└── README.md
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huangzhibiao/BGFMDB/7a9392636fea94bc3e4de5f5468b218c663f12a6/.DS_Store
--------------------------------------------------------------------------------
/.swift-version:
--------------------------------------------------------------------------------
1 | 2.3
2 |
--------------------------------------------------------------------------------
/BGFMDB.podspec:
--------------------------------------------------------------------------------
1 | #
2 | # Be sure to run `pod spec lint BGFMDB.podspec' to ensure this is a
3 | # valid spec and to remove all comments including this before submitting the spec.
4 | #
5 | # To learn more about Podspec attributes see http://docs.cocoapods.org/specification.html
6 | # To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/
7 | #
8 |
9 | Pod::Spec.new do |s|
10 |
11 | # ――― Spec Metadata ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
12 | #
13 | # These will help people to find your library, and whilst it
14 | # can feel like a chore to fill in it's definitely to your advantage. The
15 | # summary should be tweet-length, and the description more in depth.
16 | #
17 |
18 | s.name = "BGFMDB"
19 | s.version = "2.0.13"
20 | s.summary = "完美支持iOS大部分类型数据的存储,同时带有 字典转模型 功能模块."
21 |
22 | # This description is used to generate tags and improve search results.
23 | # * Think: What does it do? Why did you write it? What is the focus?
24 | # * Try to keep it short, snappy and to the point.
25 | # * Write the description between the DESC delimiters below.
26 | # * Finally, don't worry about the indent, CocoaPods strips it!
27 | s.description = <<-DESC
28 | 完美支持iOS大部分类型数据的存储,同时带有 字典转模型 功能模块.
29 | DESC
30 |
31 | s.homepage = "https://github.com/huangzhibiao/BGFMDB"
32 | # s.screenshots = "www.example.com/screenshots_1.gif", "www.example.com/screenshots_2.gif"
33 |
34 |
35 | # ――― Spec License ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
36 | #
37 | # Licensing your code is important. See http://choosealicense.com for more info.
38 | # CocoaPods will detect a license file if there is a named LICENSE*
39 | # Popular ones are 'MIT', 'BSD' and 'Apache License, Version 2.0'.
40 | #
41 |
42 | s.license = "MIT"
43 | # s.license = { :type => "MIT", :file => "FILE_LICENSE" }
44 |
45 |
46 | # ――― Author Metadata ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
47 | #
48 | # Specify the authors of the library, with email addresses. Email addresses
49 | # of the authors are extracted from the SCM log. E.g. $ git log. CocoaPods also
50 | # accepts just a name if you'd rather not provide an email address.
51 | #
52 | # Specify a social_media_url where others can refer to, for example a twitter
53 | # profile URL.
54 | #
55 |
56 | s.author = { "huangzhibiao" => "450426721@qq.com" }
57 | # Or just: s.author = "huangzhibiao"
58 | # s.authors = { "huangzhibiao" => "450426721@qq.com" }
59 | # s.social_media_url = "http://twitter.com/huangzhibiao"
60 |
61 | # ――― Platform Specifics ――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
62 | #
63 | # If this Pod runs only on iOS or OS X, then specify the platform and
64 | # the deployment target. You can optionally include the target after the platform.
65 | #
66 |
67 | # s.platform = :ios
68 | s.platform = :ios, "8.0"
69 |
70 | # When using multiple platforms
71 | # s.ios.deployment_target = "5.0"
72 | # s.osx.deployment_target = "10.7"
73 | # s.watchos.deployment_target = "2.0"
74 | # s.tvos.deployment_target = "9.0"
75 |
76 |
77 | # ――― Source Location ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
78 | #
79 | # Specify the location from where the source should be retrieved.
80 | # Supports git, hg, bzr, svn and HTTP.
81 | #
82 |
83 | s.source = { :git => 'https://github.com/huangzhibiao/BGFMDB.git', :tag => s.version, :submodules => true }
84 |
85 |
86 | # ――― Source Code ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
87 | #
88 | # CocoaPods is smart about how it includes source code. For source files
89 | # giving a folder will include any swift, h, m, mm, c & cpp files.
90 | # For header files it will include any header in the folder.
91 | # Not including the public_header_files will make all headers public.
92 | #
93 |
94 | s.public_header_files = 'BGFMDB/libs/BG/BGFMDB.h'
95 | s.source_files = 'BGFMDB/libs/BG/BGFMDB.h'
96 |
97 | s.subspec 'FMDB' do |ss|
98 | ss.source_files = 'BGFMDB/libs/FMDB/*.{h,m}'
99 | end
100 |
101 | s.subspec 'BG' do |ss|
102 | ss.source_files = 'BGFMDB/libs/BG/*.{h,m}'
103 | ss.dependency 'BGFMDB/FMDB'
104 | end
105 |
106 | #s.source_files = 'BGFMDB/libs/BG/*.{h,m}', 'BGFMDB/libs/FMDB/*.{h,m}'
107 | #s.exclude_files = "BGFMDB/BGFMDB/libs"
108 |
109 | #s.public_header_files = "BGFMDB/BGFMDB/libs/FMDB/FMDB.h"
110 |
111 |
112 | # ――― Resources ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
113 | #
114 | # A list of resources included with the Pod. These are copied into the
115 | # target bundle with a build phase script. Anything else will be cleaned.
116 | # You can preserve files from being cleaned, please don't preserve
117 | # non-essential files like tests, examples and documentation.
118 | #
119 |
120 | # s.resource = "icon.png"
121 | # s.resources = "Resources/*.png"
122 |
123 | # s.preserve_paths = "FilesToSave", "MoreFilesToSave"
124 |
125 |
126 | # ――― Project Linking ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
127 | #
128 | # Link your library with frameworks, or libraries. Libraries do not include
129 | # the lib prefix of their name.
130 | #
131 |
132 | # s.framework = "SomeFramework"
133 | # s.frameworks = "SomeFramework", "AnotherFramework"
134 |
135 | s.library = "sqlite3"
136 | # s.libraries = "iconv", "xml2"
137 |
138 |
139 | # ――― Project Settings ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
140 | #
141 | # If your library depends on compiler flags you can set them in the xcconfig hash
142 | # where they will only apply to your library. If you depend on other Podspecs
143 | # you can include multiple dependencies to ensure it works.
144 |
145 | s.requires_arc = true
146 |
147 | s.xcconfig = { "HEADER_SEARCH_PATHS" => "$(SDKROOT)/usr/lib/libsqlite3.dylib" }
148 | # s.dependency "JSONKit", "~> 1.4"
149 |
150 | end
151 |
152 |
--------------------------------------------------------------------------------
/BGFMDB.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/BGFMDB.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/BGFMDB.xcodeproj/project.xcworkspace/xcuserdata/biao.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huangzhibiao/BGFMDB/7a9392636fea94bc3e4de5f5468b218c663f12a6/BGFMDB.xcodeproj/project.xcworkspace/xcuserdata/biao.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/BGFMDB.xcodeproj/project.xcworkspace/xcuserdata/huangzhibiao.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huangzhibiao/BGFMDB/7a9392636fea94bc3e4de5f5468b218c663f12a6/BGFMDB.xcodeproj/project.xcworkspace/xcuserdata/huangzhibiao.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/BGFMDB.xcodeproj/xcuserdata/biao.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
8 |
14 |
15 |
16 |
18 |
30 |
31 |
32 |
34 |
46 |
47 |
48 |
50 |
62 |
63 |
64 |
66 |
78 |
79 |
80 |
82 |
94 |
95 |
96 |
98 |
110 |
111 |
125 |
126 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
--------------------------------------------------------------------------------
/BGFMDB.xcodeproj/xcuserdata/biao.xcuserdatad/xcschemes/BGFMDB.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
43 |
49 |
50 |
51 |
52 |
53 |
59 |
60 |
61 |
62 |
63 |
64 |
74 |
76 |
82 |
83 |
84 |
85 |
86 |
87 |
93 |
95 |
101 |
102 |
103 |
104 |
106 |
107 |
110 |
111 |
112 |
--------------------------------------------------------------------------------
/BGFMDB.xcodeproj/xcuserdata/biao.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | BGFMDB.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | D706630C1CD1EF67009E4B4D
16 |
17 | primary
18 |
19 |
20 | D70663251CD1EF67009E4B4D
21 |
22 | primary
23 |
24 |
25 | D70663301CD1EF67009E4B4D
26 |
27 | primary
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/BGFMDB.xcodeproj/xcuserdata/huangzhibiao.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
8 |
14 |
15 |
16 |
18 |
30 |
31 |
32 |
34 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/BGFMDB.xcodeproj/xcuserdata/huangzhibiao.xcuserdatad/xcschemes/BGFMDB.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
43 |
49 |
50 |
51 |
52 |
53 |
59 |
60 |
61 |
62 |
63 |
64 |
74 |
76 |
82 |
83 |
84 |
85 |
86 |
87 |
93 |
95 |
101 |
102 |
103 |
104 |
106 |
107 |
110 |
111 |
112 |
--------------------------------------------------------------------------------
/BGFMDB.xcodeproj/xcuserdata/huangzhibiao.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | BGFMDB.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | D706630C1CD1EF67009E4B4D
16 |
17 | primary
18 |
19 |
20 | D70663251CD1EF67009E4B4D
21 |
22 | primary
23 |
24 |
25 | D70663301CD1EF67009E4B4D
26 |
27 | primary
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/BGFMDB/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huangzhibiao/BGFMDB/7a9392636fea94bc3e4de5f5468b218c663f12a6/BGFMDB/.DS_Store
--------------------------------------------------------------------------------
/BGFMDB/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // BGFMDB
4 | //
5 | // Created by huangzhibiao on 16/4/28.
6 | // Copyright © 2016年 Biao. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface AppDelegate : UIResponder
12 |
13 | @property (strong, nonatomic) UIWindow *window;
14 |
15 |
16 | @end
17 |
18 |
--------------------------------------------------------------------------------
/BGFMDB/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // BGFMDB
4 | //
5 | // Created by huangzhibiao on 16/4/28.
6 | // Copyright © 2016年 Biao. All rights reserved.
7 | //
8 |
9 | #import "AppDelegate.h"
10 |
11 | @interface AppDelegate ()
12 |
13 | @end
14 |
15 | @implementation AppDelegate
16 |
17 |
18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
19 | // Override point for customization after application launch.
20 | return YES;
21 | }
22 |
23 | - (void)applicationWillResignActive:(UIApplication *)application {
24 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
25 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
26 | }
27 |
28 | - (void)applicationDidEnterBackground:(UIApplication *)application {
29 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
31 | }
32 |
33 | - (void)applicationWillEnterForeground:(UIApplication *)application {
34 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
35 | }
36 |
37 | - (void)applicationDidBecomeActive:(UIApplication *)application {
38 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
39 | }
40 |
41 | - (void)applicationWillTerminate:(UIApplication *)application {
42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
43 | }
44 |
45 | @end
46 |
--------------------------------------------------------------------------------
/BGFMDB/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | }
43 | ],
44 | "info" : {
45 | "version" : 1,
46 | "author" : "xcode"
47 | }
48 | }
--------------------------------------------------------------------------------
/BGFMDB/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/BGFMDB/Assets.xcassets/MarkMan.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "MarkMan.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/BGFMDB/Assets.xcassets/MarkMan.imageset/MarkMan.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huangzhibiao/BGFMDB/7a9392636fea94bc3e4de5f5468b218c663f12a6/BGFMDB/Assets.xcassets/MarkMan.imageset/MarkMan.png
--------------------------------------------------------------------------------
/BGFMDB/Assets.xcassets/ima1.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "ima1.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/BGFMDB/Assets.xcassets/ima1.imageset/ima1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huangzhibiao/BGFMDB/7a9392636fea94bc3e4de5f5468b218c663f12a6/BGFMDB/Assets.xcassets/ima1.imageset/ima1.jpg
--------------------------------------------------------------------------------
/BGFMDB/Assets.xcassets/ima2.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "ima2.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/BGFMDB/Assets.xcassets/ima2.imageset/ima2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huangzhibiao/BGFMDB/7a9392636fea94bc3e4de5f5468b218c663f12a6/BGFMDB/Assets.xcassets/ima2.imageset/ima2.jpg
--------------------------------------------------------------------------------
/BGFMDB/Assets.xcassets/ima3.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "ima3.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/BGFMDB/Assets.xcassets/ima3.imageset/ima3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huangzhibiao/BGFMDB/7a9392636fea94bc3e4de5f5468b218c663f12a6/BGFMDB/Assets.xcassets/ima3.imageset/ima3.jpg
--------------------------------------------------------------------------------
/BGFMDB/Assets.xcassets/ima4.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "ima4.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/BGFMDB/Assets.xcassets/ima4.imageset/ima4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huangzhibiao/BGFMDB/7a9392636fea94bc3e4de5f5468b218c663f12a6/BGFMDB/Assets.xcassets/ima4.imageset/ima4.png
--------------------------------------------------------------------------------
/BGFMDB/Assets.xcassets/ima5.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "ima5.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/BGFMDB/Assets.xcassets/ima5.imageset/ima5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huangzhibiao/BGFMDB/7a9392636fea94bc3e4de5f5468b218c663f12a6/BGFMDB/Assets.xcassets/ima5.imageset/ima5.jpg
--------------------------------------------------------------------------------
/BGFMDB/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/BGFMDB/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
30 |
38 |
46 |
54 |
62 |
70 |
81 |
92 |
93 |
94 |
95 |
96 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
--------------------------------------------------------------------------------
/BGFMDB/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UIRequiredDeviceCapabilities
30 |
31 | armv7
32 |
33 | UISupportedInterfaceOrientations
34 |
35 | UIInterfaceOrientationPortrait
36 | UIInterfaceOrientationLandscapeLeft
37 | UIInterfaceOrientationLandscapeRight
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/BGFMDB/ViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.h
3 | // BGFMDB
4 | //
5 | // Created by huangzhibiao on 16/4/28.
6 | // Copyright © 2016年 Biao. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ViewController : UIViewController
12 |
13 |
14 | @end
15 |
16 |
--------------------------------------------------------------------------------
/BGFMDB/ViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.m
3 | // BGFMDB
4 | //
5 | // Created by huangzhibiao on 16/4/28.
6 | // Copyright © 2016年 Biao. All rights reserved.
7 | //
8 |
9 | #import "ViewController.h"
10 | #import "stockController.h"
11 | #import "dictToModelController.h"
12 | #import "people.h"
13 |
14 | #define bg_tablename @"yy"
15 |
16 | @interface ViewController ()
17 |
18 | @property (weak, nonatomic) IBOutlet UIImageView *showImage;
19 | @property (weak, nonatomic) IBOutlet UILabel *showLab;
20 |
21 |
22 | - (IBAction)insertAction:(id)sender;
23 | - (IBAction)deleteAction:(id)sender;
24 | - (IBAction)updateAction:(id)sender;
25 | - (IBAction)registerChangeAction:(id)sender;
26 | - (IBAction)removeChangeAction:(id)sender;
27 |
28 | - (IBAction)stockAction:(id)sender;
29 | - (IBAction)dictToModelAction:(id)sender;
30 |
31 | - (IBAction)multithreadTestAction:(id)sender;
32 |
33 |
34 | @end
35 |
36 | @implementation ViewController
37 |
38 | - (void)viewDidLoad {
39 | [super viewDidLoad];
40 | /**
41 | 想测试更多功能,打开注释掉的代码即可.
42 | */
43 | bg_setDebug(YES);//打开调试模式,打印输出调试信息.
44 |
45 | /**
46 | 如果频繁操作数据库时,建议进行此设置(即在操作过程不关闭数据库).
47 | */
48 | //bg_setDisableCloseDB(YES);
49 |
50 | /**
51 | 手动关闭数据库(如果设置了bg_setDisableCloseDB(YES),则在切换bg_setSqliteName前,需要手动关闭数据库一下).
52 | */
53 | //bg_closeDB();
54 |
55 | /**
56 | 自定义数据库名称,否则默认为BGFMDB
57 | */
58 | //bg_setSqliteName(@"Tencent");
59 |
60 | //删除自定义数据库.
61 | //bg_deleteSqlite(@"Tencent");
62 |
63 | /**
64 | 直接存储数组.
65 | */
66 | //[self testSaveArray];
67 |
68 | /**
69 | 直接存储字典.
70 | */
71 | //[self testSaveDictionary];
72 | /**
73 | 直接存储自定义对象.
74 | */
75 | People* p = [self people];
76 | p.bg_tableName = bg_tablename;//自定义数据库表名称(库自带的字段).
77 | /**
78 | 存储.
79 | */
80 | [p bg_save];
81 |
82 | /**
83 | 同步存储或更新.
84 | 当"唯一约束"或"主键"存在时,此接口会更新旧数据,没有则存储新数据.
85 | */
86 | //[p bg_saveOrUpdate];
87 |
88 | /**
89 | 事务操作
90 | */
91 | // bg_inTransaction(^BOOL{
92 | // //此处进行--> 增删改 操作
93 | // return true;//返回true是提交事务,返回false是回滚事务.
94 | // });
95 |
96 | /**
97 | 同步 存储或更新 数组元素.
98 | 当"唯一约束"或"主键"存在时,此接口会更新旧数据,没有则存储新数据.
99 | 提示:“唯一约束”优先级高于"主键".
100 | */
101 | // p.bg_id = @(1);
102 | // People* p1 = [self people];
103 | // p1.bg_tableName = bg_tablename;//自定义数据库表名称(库自带的字段).
104 | // p1.bg_id = @(2);
105 | // p1.age = 66611;
106 | // p1.name = @"琪瑶11";
107 | // People* p2 = [self people];
108 | // p2.bg_tableName = bg_tablename;//自定义数据库表名称(库自带的字段).
109 | // p2.bg_id = @(3);
110 | // p2.age = 88822;
111 | // p2.name = @"标哥22";
112 | // [People bg_saveOrUpdateArray:@[p,p1,p2]];
113 |
114 | /**
115 | 单个对象更新,支持keyPath.
116 | 根据user下的student下的human下的body是否等于小芳 或 age是否等于31 来更新当前对象的数据进入数据库.
117 | */
118 | //NSString* where = [NSString stringWithFormat:@"where %@ and %@=%@",bg_keyPathValues(@[@"user.student.num",bg_equal,@"标哥"]),bg_sqlKey(@"age"),bg_sqlValue(@(99))];
119 | //p.name = @"天朝1";
120 | //[p bg_updateWhere:where];
121 |
122 | /**
123 | 使用SQL语句设置更新.
124 | 根据某个属性值去更改某个属性值,此处是当name等于@"天朝"时,设置age=100.
125 | */
126 | // NSString* where = [NSString stringWithFormat:@"set %@=%@ where %@=%@",bg_sqlKey(@"age"),bg_sqlValue(@(100)),bg_sqlKey(@"name"),bg_sqlValue(@"斯巴达")];
127 | // [People bg_update:bg_tablename where:where];
128 |
129 | // NSMutableArray* arrayM = [NSMutableArray array];
130 | // Human* human = [Human new];
131 | // human.sex = @"女";
132 | // human.body = @"小芳";
133 | // human.humanAge = 26;
134 | // human.age = 15;
135 | // human.num = 999;
136 | // human.counts = 10001;
137 | // human.food = @"大米";
138 | // [arrayM addObject:@"111"];
139 | // [arrayM addObject:@"222"];
140 | // [arrayM addObject:human];
141 | // NSString * update = [NSString stringWithFormat:@"set %@=%@ where %@=%@",bg_sqlKey(@"datasM"),bg_sqlValue(arrayM),bg_sqlKey(bg_primaryKey),bg_sqlValue(@(1))];
142 | // [People bg_update:bg_tablename where:update];
143 |
144 | /**
145 | 获取第一个元素.
146 | */
147 | // People* firstObj = [People bg_firstObjet:bg_tablename];
148 |
149 | /**
150 | 获取最后一个元素.
151 | */
152 | // People* lastObj = [People bg_lastObject:bg_tablename];
153 |
154 | /**
155 | 获取某一行的元素.
156 | */
157 | // People* someObj = [People bg_object:bg_tablename row:3];
158 |
159 | /**
160 | 覆盖存储,即清除之前的数据,只存储当前的数据.
161 | */
162 | // [p bg_cover];
163 |
164 | /**
165 | 按条件查询.
166 | */
167 | // NSString* where = [NSString stringWithFormat:@"where %@=%@",bg_sqlKey(@"name"),bg_sqlValue(@"斯巴达")];
168 | // NSArray* arr = [People bg_find:bg_tablename where:where];
169 |
170 | /**
171 | 按时间段查找数据.
172 | */
173 | // NSArray* arr = [People bg_find:bg_tablename type:bg_createTime dateTime:@"2017-11-30"];
174 |
175 | /**
176 | 按条件删除.
177 | */
178 | // NSString* where = [NSString stringWithFormat:@"where %@=%@",bg_sqlKey(@"name"),bg_sqlValue(@"斯巴达")];
179 | // [People bg_delete:bg_tablename where:where];
180 |
181 | /**
182 | 直接写SQL语句操作
183 | */
184 | //NSArray* arr = bg_executeSql(@"select * from yy", bg_tablename, [People class]);//查询时,后面两个参数必须要传入.
185 | // bg_executeSql(@"update yy set BG_name='标哥'", nil, nil);//更新或删除等操作时,后两个参数不必传入.
186 |
187 | /**
188 | 获取数据表当前版本号.
189 | */
190 | // NSInteger version = [People bg_version:bg_tablename];
191 | /**
192 | 刷新,当类"唯一约束"改变时,调用此接口刷新一下.
193 | version 版本号,从1开始,依次往后递增.
194 | 说明: 本次更新版本号必须 大于 上次的版本号,否则不会更新.
195 | */
196 | // [People bg_update:bg_tablename version:1];
197 |
198 | /**
199 | 使用keyPath查询嵌套类信息.
200 | */
201 | // NSString* where = [NSString stringWithFormat:@"where %@",bg_keyPathValues(@[@"user.name",bg_equal,@"陈浩"])];
202 | // NSArray* arrFind = [People bg_find:bg_tablename where:where];
203 |
204 | /**
205 | 当数据量巨大时采用分页范围查询.
206 | */
207 | NSInteger count = [People bg_count:bg_tablename where:nil];
208 | for(int i=1;i<=count;i+=50){
209 | NSArray* arr = [People bg_find:bg_tablename range:NSMakeRange(i,50) orderBy:nil desc:NO];
210 | for(People* pp in arr){
211 | //具体数据请断点查看
212 | //库新增两个自带字段createTime和updateTime方便开发者使用和做参考对比.
213 | NSLog(@"主键 = %@, 表名 = %@, 创建时间 = %@, 更新时间 = %@",pp.bg_id,pp.bg_tableName,pp.bg_createTime,pp.bg_updateTime);
214 | }
215 |
216 | //顺便取第一个对象数据测试
217 | if(i==1){
218 | People* lastP = arr.lastObject;
219 | _showImage.image = lastP.image;
220 | _showLab.attributedText = lastP.attriStr;
221 | }
222 | }
223 |
224 |
225 | }
226 |
227 | #pragma mark 直接存储数组
228 | -(void)testSaveArray{
229 | NSMutableArray* testA = [NSMutableArray array];
230 | [testA addObject:@"我是"];
231 | [testA addObject:@(10)];
232 | [testA addObject:@(9.999)];
233 | [testA addObject:@{@"key":@"value"}];
234 | Human* human = [Human new];
235 | human.sex = @"女";
236 | human.body = @"小芳";
237 | human.humanAge = 26;
238 | human.age = 15;
239 | human.num = 999;
240 | human.counts = 10001;
241 | human.food = @"大米";
242 | human.data = UIImageJPEGRepresentation([UIImage imageNamed:@"MarkMan"], 1);
243 | human.array = @[@"数组1",@"数组2",@"数组3",@(1),@(1.5)];
244 | human.dict = @{@"key1":@"value1",@"key2":@(2)};
245 | [testA addObject:human];
246 | /**
247 | 存储标识名为testA的数组.
248 | */
249 | [testA bg_saveArrayWithName:@"testA"];
250 |
251 | /**
252 | 往标识名为@"testA"的数组中添加元素.
253 | */
254 | //[NSArray bg_addObjectWithName:@"testA" object:@[@(1),@"哈哈"]];
255 |
256 | /**
257 | 更新标识名为testA的数组某个位置上的元素.
258 | */
259 | //[NSArray bg_updateObjectWithName:@"testA" Object:@"人妖" Index:0];
260 |
261 | /**
262 | 删除标识名为testA的数组某个位置上的元素.
263 | */
264 | //[NSArray bg_deleteObjectWithName:@"testA" Index:3];
265 |
266 | /**
267 | 查询标识名为testA的数组全部元素.
268 | */
269 | NSArray* testResult = [NSArray bg_arrayWithName:@"testA"];
270 |
271 | /**
272 | 获取标识名为testA的数组某个位置上的元素.
273 | */
274 | id arrObject = [NSArray bg_objectWithName:@"testA" Index:3];
275 |
276 | /**
277 | 清除标识名为testA的数组所有元素.
278 | */
279 | //[NSArray bg_clearArrayWithName:@"testA"];
280 |
281 | NSLog(@"结果 = %@",testResult);
282 | }
283 |
284 | #pragma mark 直接存储集合
285 | -(void)testSaveDictionary{
286 | Human* human = [Human new];
287 | human.sex = @"女";
288 | human.body = @"小芳";
289 | human.humanAge = 26;
290 | human.age = 15;
291 | human.num = 999;
292 | human.counts = 10001;
293 | human.food = @"大米";
294 | human.data = UIImageJPEGRepresentation([UIImage imageNamed:@"MarkMan"], 1);
295 | human.array = @[@"数组1",@"数组2",@"数组3",@(1),@(1.5)];
296 | human.dict = @{@"key1":@"value1",@"key2":@(2)};
297 | NSDictionary* dict = @{@"one":@(1),@"key":@"value",@"array":@[@(1.2),@"哈哈"],@"human":human};
298 | /**
299 | 存储字典.
300 | */
301 | [dict bg_saveDictionary];
302 | /**
303 | 添加字典元素.
304 | */
305 | //[NSDictionary bg_setValue:@"标哥" forKey:@"name"];
306 |
307 | /**
308 | 更新字典元素.
309 | */
310 | //[NSDictionary bg_updateValue:@"人妖" forKey:@"key"];
311 |
312 | /**
313 | 获取某个字典元素.
314 | */
315 | id num = [NSDictionary bg_valueForKey:@"one"];
316 |
317 | /**
318 | 移除字典某个元素.
319 | */
320 | //[NSDictionary bg_removeValueForKey:@"key"];
321 |
322 | /**
323 | 遍历字典元素.
324 | */
325 | [NSDictionary bg_enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, id _Nonnull value, BOOL *stop) {
326 | NSLog(@"key = %@ , value = %@",key,value);
327 | }];
328 |
329 | /**
330 | 清空字典.
331 | */
332 | //[NSDictionary bg_clearDictionary];
333 | }
334 |
335 | -(People*)people{
336 | //存储对象使用示例
337 | People* p = [People new];
338 | p.name = @"斯巴达7";
339 | p.num = @(220.88);
340 | p.age = 99;
341 | p.sex = @"男";
342 | p.eye = @"末世眼皮111";
343 | p.Url = [NSURL URLWithString:@"http://www.baidu.com"];
344 | p.addBool = YES;
345 | p.range = NSMakeRange(0,10);
346 | p.rect = CGRectMake(0,0,10,20);
347 | p.size = CGSizeMake(50,50);
348 | p.point = CGPointMake(2.55,3.14);
349 | p.color = [UIColor colorWithRed:245 green:245 blue:245 alpha:1.0];
350 | NSMutableAttributedString* attStrM = [[NSMutableAttributedString alloc] initWithString:@"BGFMDB"];
351 | [attStrM addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:NSMakeRange(0, 2)];
352 | p.attriStr = attStrM;
353 | p.image = [UIImage imageNamed:@"MarkMan"];
354 | NSData* data = UIImageJPEGRepresentation(p.image, 1);
355 | p.data2 = data;
356 |
357 | p.arrM = [NSMutableArray array];
358 | for(int i=1;i<=5;i++){
359 | [p.arrM addObject:UIImageJPEGRepresentation([UIImage imageNamed:[NSString stringWithFormat:@"ima%d",i]], 1)];
360 | }
361 |
362 | [p setValue:@(110) forKey:@"testAge"];
363 | p->testName = @"测试名字";
364 | p.sex_old = @"新名";
365 | User* user = [[User alloc] init];
366 | user.name = @"陈浩南";
367 | user.attri = @{@"用户名":@"黄芝标",@"密码":@(123456),@"数组":@[@"数组1",@"数组2"],@"集合":@{@"集合1":@"集合2"}};
368 | Student* student = [[Student alloc] init];
369 | student.num = @"标哥";
370 | student.names = @[@"小哥哥",@"小红",@(110),@[@"数组元素1",@"数组元素2"],@{@"集合key":@"集合value"}];
371 | student.count = 199;
372 | Human* human = [[Human alloc] init];
373 | human.sex = @"女";
374 | human.body = @"小芳";
375 | human.humanAge = 98;
376 | human.age = 18;
377 | student.human = human;
378 | user.student = student;
379 | p.students = @[@(1),@"呵呵",@[@"数组元素1",@"数组元素2"],@{@"集合key":@"集合value"},student,data,student];
380 | p.infoDic = @{@"name":@"标哥",@"年龄":@(1),@"数组":@[@"数组1",@"数组2"],@"集合":@{@"集合1":@"集合2"},@"user":user,@"data":data};
381 |
382 | NSHashTable* hashTable = [NSHashTable new];
383 | [hashTable addObject:@"h1"];
384 | [hashTable addObject:@"h2"];
385 | [hashTable addObject:student];
386 | NSMapTable* mapTable = [NSMapTable new];
387 | [mapTable setObject:@"m_value1" forKey:@"m_key1"];
388 | [mapTable setObject:@"m_value2" forKey:@"m_key2"];
389 | [mapTable setObject:user forKey:@"m_key3"];
390 | NSSet* set1 = [NSSet setWithObjects:@"1",@"2",student, nil];
391 | NSMutableSet* set2 = [NSMutableSet set];
392 | [set2 addObject:@{@"key1":@"value"}];
393 | [set2 addObject:@{@"key2":user}];
394 |
395 | People* userP = [People new];
396 | userP.name = @"互为属性测试";
397 | user.userP = userP;
398 |
399 | p.user = user;
400 | p.user1 = [User new];
401 | p.user1.name = @"小明_fuck2222";
402 | p.bfloat = 8.88;
403 | p.bdouble = 100.567;
404 | p.user.userAge = 13;
405 | p.user.userNumer = @(3.14);
406 | p.user.student.human.humanAge = 9999;
407 |
408 | p.hashTable = hashTable;
409 | p.mapTable = mapTable;
410 | p.nsset = set1;
411 | p.setM = set2;
412 | p.date = [NSDate date];
413 | return p;
414 | }
415 | /**
416 | 测试子类对象指向父类引用的情况.
417 | */
418 | -(void)testT{
419 | testT* test = [testT new];
420 | T2* t2 = [T2 new];
421 | t2.t2 = @"t2";
422 | t2.name = @"t2_name";
423 | /*------*/
424 | T3* t3 = [T3 new];
425 | t3.t3 = @"t3";
426 | t3.name = @"t3_name";
427 | t3.t2 = t2;
428 |
429 | test.t1 = t3;
430 | [test bg_save];
431 |
432 | NSArray* arr = [testT bg_findAll:nil];
433 |
434 | NSLog(@"-------");
435 | }
436 | /**
437 | 插入
438 | */
439 | - (IBAction)insertAction:(id)sender {
440 | People* p = [self people];
441 | p.bg_tableName = bg_tablename;//自定义的数据库表名称(库自带的字段).
442 | [p bg_save];
443 | }
444 | /**
445 | 删除
446 | */
447 | - (IBAction)deleteAction:(id)sender{
448 | NSString* where = [NSString stringWithFormat:@"where %@=%@",bg_sqlKey(bg_primaryKey),@(1)];
449 | [People bg_delete:bg_tablename where:where];
450 | }
451 | /**
452 | 更新
453 | */
454 | - (IBAction)updateAction:(id)sender {
455 | People* p = [self people];
456 | p.bg_tableName = bg_tablename;//自定义的数据库表名称(库自带的字段).
457 | NSString* where = [NSString stringWithFormat:@"where %@=%@",bg_sqlKey(bg_primaryKey),@(1)];
458 | [p bg_updateWhere:where];
459 | }
460 | /**
461 | 数据库变化监听
462 | */
463 | - (IBAction)registerChangeAction:(id)sender{
464 | [People bg_registerChangeForTableName:bg_tablename identify:@"change" block:^(bg_changeState result) {
465 | switch (result) {
466 | case bg_insert:
467 | NSLog(@"有数据插入");
468 | break;
469 | case bg_update:
470 | NSLog(@"有数据更新");
471 | break;
472 | case bg_delete:
473 | NSLog(@"有数据删删除");
474 | break;
475 | case bg_drop:
476 | NSLog(@"有表删除");
477 | break;
478 | default:
479 | break;
480 | }
481 | }];
482 | }
483 |
484 | /**
485 | 移除监听
486 | */
487 | - (IBAction)removeChangeAction:(id)sender{
488 | [People bg_removeChangeForTableName:bg_tablename identify:@"change"];
489 | }
490 | /**
491 | 模拟股票数据
492 | */
493 | - (IBAction)stockAction:(id)sender {
494 | stockController* con = [stockController new];
495 | [self presentViewController:con animated:YES completion:nil];
496 | }
497 | /**
498 | 字典转模型
499 | */
500 | - (IBAction)dictToModelAction:(id)sender{
501 | dictToModelController* con = [dictToModelController new];
502 | [self presentViewController:con animated:YES completion:nil];
503 | }
504 | /**
505 | 多线程安全测试
506 | */
507 | - (IBAction)multithreadTestAction:(id)sender {
508 | People* p = [self people];
509 | for(int i=0;i<5;i++){
510 |
511 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
512 | NSLog(@"存储...");
513 | [p bg_save];
514 | });
515 |
516 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
517 | NSLog(@"更新...");
518 | NSString* where = [NSString stringWithFormat:@"set %@=%@ where %@=%@",bg_sqlKey(@"name"),bg_sqlValue(@"标哥"),bg_sqlKey(@"name"),bg_sqlValue(@"斯巴达")];
519 | [People bg_update:bg_tablename where:where];
520 | });
521 |
522 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
523 | People* pp = [People bg_lastObject:nil];
524 | NSLog(@"bg_id = %@",pp.bg_id);
525 | });
526 |
527 | }
528 |
529 | }
530 | @end
531 |
--------------------------------------------------------------------------------
/BGFMDB/dictToModelController/Animal.h:
--------------------------------------------------------------------------------
1 | //
2 | // Animal.h
3 | // BGFMDB
4 | //
5 | // Created by huangzhibiao on 17/3/14.
6 | // Copyright © 2017年 Biao. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "BGFMDB.h"//引入所需头文件.
11 |
12 | @class Dog;
13 |
14 | @interface Animal : NSObject
15 | @property(nonatomic,strong)NSArray* foods;
16 | @property(nonatomic,strong)NSDictionary* body;
17 |
18 |
19 | @end
20 |
21 | @interface Dog : Animal
22 |
23 | @property(nonatomic,copy)NSString* name;
24 | @property(nonatomic,strong)NSNumber* age;
25 | @property(nonatomic,copy)NSString* specy;
26 |
27 | @end
28 |
29 | @interface Body:NSObject
30 |
31 | @property(nonatomic,copy)NSString* hand;
32 | @property(nonatomic,copy)NSString* leg;
33 | @property(nonatomic,strong)Dog* dog;
34 |
35 | @end
36 |
37 | @interface My : NSObject
38 |
39 | @property(nonatomic,copy)NSString* name;
40 | @property(nonatomic,copy)NSString* intro;
41 | @property(nonatomic,copy)NSString* sex;
42 | @property(nonatomic,strong)NSArray* dogs;
43 | @property(nonatomic,strong)NSArray* bodys;
44 | @property(nonatomic,strong)NSArray* foods;
45 | @property(nonatomic,strong)Body* body;
46 | @property(nonatomic,strong)Dog* dog;
47 | @end
48 |
--------------------------------------------------------------------------------
/BGFMDB/dictToModelController/Animal.m:
--------------------------------------------------------------------------------
1 | //
2 | // Animal.m
3 | // BGFMDB
4 | //
5 | // Created by huangzhibiao on 17/3/14.
6 | // Copyright © 2017年 Biao. All rights reserved.
7 | //
8 |
9 | #import "Animal.h"
10 |
11 | @implementation Animal
12 |
13 | @end
14 |
15 | @implementation Dog
16 |
17 |
18 | @end
19 |
20 | @implementation Body
21 |
22 |
23 | @end
24 |
25 | @implementation My
26 |
27 | /**
28 | 如果模型中有数组且存放的是自定义的类(NSString等系统自带的类型就不必要了),那就实现该函数,key是数组名称,value是自定的类Class,用法跟MJExtension一样.
29 | (‘字典转模型’ 或 ’模型转字典‘ 都需要实现该函数)
30 | */
31 | +(NSDictionary *)bg_objectClassInArray{
32 | return @{@"dogs":[Dog class],@"bodys":[Body class]};
33 | }
34 | /**
35 | 如果模型中有自定义类变量,则实现该函数对应进行集合到模型的转换.
36 | 注:字典转模型用.
37 | */
38 | +(NSDictionary *)bg_objectClassForCustom{
39 | return @{@"body":[Body class],@"body.dog":[Dog class]};
40 | }
41 | /**
42 | 将模型中对应的自定义类变量转换为字典.
43 | 模型转字典用.
44 | */
45 | +(NSDictionary *)bg_dictForCustomClass{
46 | return @{@"body":[Body class],@"dog":[Dog class]};
47 | }
48 | /**
49 | 替换变量的功能(及当字典的key和属性名不一样时,进行映射对应起来)
50 | 即将字典里key为descri的值 赋给 属性名为intro的变量,性别和sex同理.
51 | */
52 | +(NSDictionary *)bg_replacedKeyFromPropertyName{
53 | return @{@"descri":@"intro",@"性别":@"sex"};
54 | }
55 |
56 | @end
57 |
--------------------------------------------------------------------------------
/BGFMDB/dictToModelController/dictToModelController.h:
--------------------------------------------------------------------------------
1 | //
2 | // dictToModelController.h
3 | // BGFMDB
4 | //
5 | // Created by huangzhibiao on 17/3/14.
6 | // Copyright © 2017年 Biao. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface dictToModelController : UIViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/BGFMDB/dictToModelController/dictToModelController.m:
--------------------------------------------------------------------------------
1 | //
2 | // dictToModelController.m
3 | // BGFMDB
4 | //
5 | // Created by huangzhibiao on 17/3/14.
6 | // Copyright © 2017年 Biao. All rights reserved.
7 | //
8 |
9 | #import "dictToModelController.h"
10 | #import "Animal.h"
11 |
12 | @interface dictToModelController ()
13 | - (IBAction)beginTransformAction:(id)sender;
14 | - (IBAction)backAction:(id)sender;
15 |
16 |
17 | @end
18 |
19 | @implementation dictToModelController
20 |
21 | - (void)viewDidLoad {
22 | [super viewDidLoad];
23 | // Do any additional setup after loading the view from its nib.
24 | }
25 |
26 | - (IBAction)beginTransformAction:(id)sender{
27 | NSDictionary* dictDog = [self getDogDict];
28 | //一代码搞定字典转模型.
29 | Dog* dog = [Dog bg_objectWithKeyValues:dictDog];
30 | NSDictionary* dictMy = [self getMyDict];
31 | //一代码搞定字典转模型.
32 | My* my = [My bg_objectWithDictionary:dictMy];
33 |
34 | /**
35 | 批量转化.
36 | */
37 | NSArray* mys = [My bg_objectArrayWithKeyValuesArray:@[dictMy,dictMy,dictMy]];
38 |
39 | Body* body = [Body new];
40 | body.hand = @"手";
41 | body.leg = @"脚";
42 | //一句代码搞定模型转字典.
43 | NSDictionary* dictBodyAll = [my bg_keyValuesIgnoredKeys:nil];
44 |
45 | //忽略掉hand不转.
46 | NSDictionary* dictBody = [my bg_keyValuesIgnoredKeys:@[@"foods"]];
47 |
48 | [my bg_save];
49 |
50 | NSArray* myArr = [My bg_findAll:nil];
51 |
52 | NSLog(@"断点察看结果");
53 | }
54 |
55 | - (IBAction)backAction:(id)sender {
56 | [self dismissViewControllerAnimated:YES completion:nil];
57 | }
58 |
59 | -(NSDictionary*)getDogDict{
60 | NSMutableDictionary* dictM = [NSMutableDictionary dictionary];
61 | dictM[@"foods"] = @[@"肉",@"骨头",@"屎",@"狗粮",@"米饭",@{@"蔬菜":@"狗菜"}];
62 | dictM[@"body"] = @{@"leg":@"两条腿",@"hand":@"两只手",@"head":@(1)};
63 | dictM[@"name"] = @"逗逼";
64 | dictM[@"age"] = @(2);
65 | dictM[@"specy"] = @"哈士奇";
66 | return dictM;
67 | }
68 | -(NSDictionary*)getBodyDict{
69 | NSMutableDictionary* dictM = [NSMutableDictionary dictionary];
70 | dictM[@"hand"] = @"手";
71 | dictM[@"leg"] = @"脚";
72 | dictM[@"dog"] = [self getDogDict];
73 | return dictM;
74 | }
75 | -(NSDictionary*)getMyDict{
76 | NSMutableDictionary* dictM = [NSMutableDictionary dictionary];
77 | dictM[@"name"] = @"小明";
78 | dictM[@"descri"] = @"标哥最帅了...";
79 | dictM[@"性别"] = @"男";
80 | dictM[@"dogs"] = @[[self getDogDict],[self getDogDict],[self getDogDict]];
81 | dictM[@"bodys"] = @[[self getBodyDict],[self getBodyDict]];
82 | dictM[@"foods"] = @[@"米饭",@"水果",@"蔬菜"];
83 | dictM[@"body"] = [self getBodyDict];
84 | return dictM;
85 | }
86 | @end
87 |
--------------------------------------------------------------------------------
/BGFMDB/dictToModelController/dictToModelController.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
31 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/BGFMDB/file.txt:
--------------------------------------------------------------------------------
1 | 2017-02-22 14:33:49.037120 BGFMDB[448:43650] key = testAge , type = i
2 | 2017-02-22 14:33:49.037220 BGFMDB[448:43650] key = testName , type = @"NSString"
3 | 2017-02-22 14:33:49.037261 BGFMDB[448:43650] key = addBool , type = B
4 | 2017-02-22 14:33:49.037336 BGFMDB[448:43650] key = bshort , type = s
5 | 2017-02-22 14:33:49.037379 BGFMDB[448:43650] key = age , type = i
6 | 2017-02-22 14:33:49.037410 BGFMDB[448:43650] key = bint , type = i
7 | 2017-02-22 14:33:49.037440 BGFMDB[448:43650] key = bsigned , type = i
8 | 2017-02-22 14:33:49.037486 BGFMDB[448:43650] key = bunsigned , type = I
9 | 2017-02-22 14:33:49.037684 BGFMDB[448:43650] key = bfloat , type = f
10 | 2017-02-22 14:33:49.037740 BGFMDB[448:43650] key = name , type = @"NSString"
11 | 2017-02-22 14:33:49.037943 BGFMDB[448:43650] key = num , type = @"NSNumber"
12 | 2017-02-22 14:33:49.037986 BGFMDB[448:43650] key = eye , type = @"NSString"
13 | 2017-02-22 14:33:49.038018 BGFMDB[448:43650] key = sex_old , type = @"NSString"
14 | 2017-02-22 14:33:49.038124 BGFMDB[448:43650] key = students , type = @"NSArray"
15 | 2017-02-22 14:33:49.038160 BGFMDB[448:43650] key = info , type = @"NSDictionary"
16 | 2017-02-22 14:33:49.038191 BGFMDB[448:43650] key = user , type = @"User"
17 | 2017-02-22 14:33:49.038221 BGFMDB[448:43650] key = user1 , type = @"User"
18 | 2017-02-22 14:33:49.038330 BGFMDB[448:43650] key = blonglong , type = q
19 | 2017-02-22 14:33:49.038370 BGFMDB[448:43650] key = bdouble , type = d
20 | 2017-02-22 14:33:49.038401 BGFMDB[448:43650] key = bCGFloat , type = d
21 | 2017-02-22 14:33:49.038433 BGFMDB[448:43650] key = bNSInteger , type = q
22 | 2017-02-22 14:33:49.038511 BGFMDB[448:43650] key = blong , type = q
23 | 2017-02-22 14:33:49.038695 BGFMDB[448:43650] key = rect , type = ^{CGRect={CGPoint=dd}{CGSize=dd}}
24 | 2017-02-22 14:33:49.038778 BGFMDB[448:43650] key = point , type = ^{CGPoint=dd}
25 | 2017-02-22 14:33:49.038880 BGFMDB[448:43650] key = size , type = ^{CGSize=dd}
26 | 2017-02-22 14:33:49.038922 BGFMDB[448:43650] key = range , type = ^{_NSRange=QQ}
27 | 2017-02-22 14:33:49.038954 BGFMDB[448:43650] key = arrM , type = @"NSMutableArray"
28 | 2017-02-22 14:33:49.038988 BGFMDB[448:43650] key = dictM , type = @"NSMutableDictionary"
29 | 2017-02-22 14:33:49.039097 BGFMDB[448:43650] key = nsset , type = @"NSSet"
30 | 2017-02-22 14:33:49.039131 BGFMDB[448:43650] key = setM , type = @"NSMutableSet"
31 | 2017-02-22 14:33:49.039163 BGFMDB[448:43650] key = mapTable , type = @"NSMapTable"
32 | 2017-02-22 14:33:49.039246 BGFMDB[448:43650] key = hashTable , type = @"NSHashTable"
33 | 2017-02-22 14:33:49.039323 BGFMDB[448:43650] key = date , type = @"NSDate"
34 | 2017-02-22 14:33:49.039359 BGFMDB[448:43650] key = data , type = @"NSData"
35 | 2017-02-22 14:33:49.039396 BGFMDB[448:43650] key = dataM , type = @"NSMutableData"
36 | 2017-02-22 14:33:49.039428 BGFMDB[448:43650] key = image , type = @"UIImage"
37 | 2017-02-22 14:33:49.039460 BGFMDB[448:43650] key = color , type = @"UIColor"
38 | 2017-02-22 14:33:49.039491 BGFMDB[448:43650] key = url , type = @"NSURL"
39 |
40 |
41 | [2] (null) @"foods" : @"[\n {\n \"BGValue\" : \"肉\"\n },\n {\n \"BGValue\" : \"骨头\"\n },\n {\n \"BGValue\" : \"屎\"\n },\n {\n \"BGValue\" : \"狗粮\"\n },\n {\n \"BGValue\" : \"米饭\"\n },\n {\n \"BGDictionary\" : \"{\\n \\\"蔬菜\\\" : \\\"狗菜\\\"\\n}\"\n },\n {\n \"BGModel*Dog\" : \"{\\n \\\"name\\\" : \\\"花花\\\",\\n \\\"age\\\" : \\\"0.5\\\",\\n \\\"specy\\\" : \\\"泰迪\\\"\\n}\"\n },\n {\n \"BGModel*Dog\" : \"{\\n \\\"name\\\" : \\\"花花\\\",\\n \\\"age\\\" : \\\"0.5\\\",\\n \\\"specy\\\" : \\\"泰迪\\\"\\n}\"\n }\n]"
42 |
43 | sqlValue __NSCFString * @"{\n \"name\" : \"花花\",\n \"age\" : \"0.5\",\n \"specy\" : \"泰迪\"\n}" 0x0000000170102d90
44 |
--------------------------------------------------------------------------------
/BGFMDB/libs/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huangzhibiao/BGFMDB/7a9392636fea94bc3e4de5f5468b218c663f12a6/BGFMDB/libs/.DS_Store
--------------------------------------------------------------------------------
/BGFMDB/libs/BG/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huangzhibiao/BGFMDB/7a9392636fea94bc3e4de5f5468b218c663f12a6/BGFMDB/libs/BG/.DS_Store
--------------------------------------------------------------------------------
/BGFMDB/libs/BG/BGDB.h:
--------------------------------------------------------------------------------
1 | //
2 | // BGDB.h
3 | // BGFMDB
4 | //
5 | // Created by biao on 2017/10/18.
6 | // Copyright © 2017年 Biao. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "BGFMDBConfig.h"
11 | #import "FMDB.h"
12 |
13 | @interface BGDB : NSObject
14 | //信号量.
15 | @property(nonatomic, strong)dispatch_semaphore_t _Nullable semaphore;
16 | /**
17 | 调试标志
18 | */
19 | @property(nonatomic,assign)BOOL debug;
20 | /**
21 | 自定义数据库名称
22 | */
23 | @property(nonatomic,copy)NSString* _Nonnull sqliteName;
24 | /**
25 | 设置操作过程中不可关闭数据库(即closeDB函数无效).
26 | */
27 | @property(nonatomic,assign)BOOL disableCloseDB;
28 | /**
29 | 获取单例函数.
30 | */
31 | +(_Nonnull instancetype)shareManager;
32 | /**
33 | 关闭数据库.
34 | */
35 | -(void)closeDB;
36 | /**
37 | 删除数据库文件.
38 | */
39 | +(BOOL)deleteSqlite:(NSString*_Nonnull)sqliteName;
40 | /**
41 | 事务操作.
42 | */
43 | -(void)inTransaction:(BOOL (^_Nonnull)())block;
44 | /**
45 | 添加操作到线程池
46 | */
47 | -(void)addToThreadPool:(void (^_Nonnull)())block;
48 | /**
49 | 注册数据变化监听.
50 | @claName 注册监听的类名.
51 | @name 注册名称,此字符串唯一,不可重复,移除监听的时候使用此字符串移除.
52 | @return YES: 注册监听成功; NO: 注册监听失败.
53 | */
54 | -(BOOL)registerChangeWithName:(NSString* const _Nonnull)name block:(bg_changeBlock)block;
55 | /**
56 | 移除数据变化监听.
57 | @name 注册监听的时候使用的名称.
58 | @return YES: 移除监听成功; NO: 移除监听失败.
59 | */
60 | -(BOOL)removeChangeWithName:(NSString* const _Nonnull)name;
61 |
62 | #pragma mark --> 以下是直接存储一个对象的API
63 |
64 | /**
65 | 存储一个对象.
66 | @object 将要存储的对象.
67 | @ignoreKeys 忽略掉模型中的哪些key(即模型变量)不要存储,nil时全部存储.
68 | @complete 回调的block.
69 | */
70 | -(void)saveObject:(id _Nonnull)object ignoredKeys:(NSArray* const _Nullable)ignoredKeys complete:(bg_complete_B)complete;
71 | /**
72 | 批量存储.
73 | */
74 | -(void)saveObjects:(NSArray* _Nonnull)array ignoredKeys:(NSArray* const _Nullable)ignoredKeys complete:(bg_complete_B)complete;
75 | /**
76 | 批量更新.
77 | over
78 | */
79 | -(void)updateObjects:(NSArray* _Nonnull)array ignoredKeys:(NSArray* const _Nullable)ignoredKeys complete:(bg_complete_B)complete;
80 | /**
81 | 批量插入或更新.
82 | */
83 | -(void)bg_saveOrUpateArray:(NSArray* _Nonnull)array ignoredKeys:(NSArray* const _Nullable)ignoredKeys complete:(bg_complete_B)complete;
84 | /**
85 | 根据条件查询对象.
86 | @tablename 要操作的表名称.
87 | @cla 代表对应的类.
88 | @where 条件参数.
89 | @complete 回调的block.
90 | */
91 | -(void)queryObjectWithTableName:(NSString* _Nonnull)tablename class:(__unsafe_unretained _Nonnull Class)cla where:(NSString* _Nullable)where complete:(bg_complete_A)complete;
92 |
93 | /**
94 | 根据条件改变对象数据.
95 | @object 要更新的对象.
96 | @where 数组的形式 @[@"key",@"=",@"value",@"key",@">=",@"value"],为nil时设置全部.
97 | @complete 回调的block
98 | */
99 | -(void)updateWithObject:(id _Nonnull)object where:(NSArray* _Nullable)where ignoreKeys:(NSArray* const _Nullable)ignoreKeys complete:(bg_complete_B)complete;
100 | /**
101 | 根据keyPath改变对象数据.
102 | @keyPathValues数组,形式@[@"user.student.name",Equal,@"小芳",@"user.student.conten",Contains,@"书"]
103 | 即更新user.student.name=@"小芳" 和 user.student.content中包含@“书”这个字符串的对象.
104 | */
105 | -(void)updateWithObject:(id _Nonnull)object forKeyPathAndValues:(NSArray* _Nonnull)keyPathValues ignoreKeys:(NSArray* const _Nullable)ignoreKeys complete:(bg_complete_B)complete;
106 | /**
107 | 直接传入条件sql语句更新对象.
108 | */
109 | -(void)updateObject:(id _Nonnull)object ignoreKeys:(NSArray* const _Nullable)ignoreKeys conditions:(NSString* _Nonnull)conditions complete:(bg_complete_B)complete;
110 | /**
111 | 根据类删除此类所有数据.
112 | @complete 回调的block
113 | */
114 | -(void)clearWithObject:(id _Nonnull)object complete:(bg_complete_B)complete;
115 | /**
116 | 根据类,删除这个类的表.
117 | @complete 回调的block
118 | */
119 | -(void)dropWithTableName:(NSString* _Nonnull)tablename complete:(bg_complete_B)complete;
120 | /**
121 | 将某表的数据拷贝给另一个表
122 | @srcTable 源表.
123 | @destTable 目标表.
124 | @keyDict 拷贝的对应key集合,形式@{@"srcKey1":@"destKey1",@"srcKey2":@"destKey2"},即将源类srcCla中的变量值拷贝给目标类destCla中的变量destKey1,srcKey2和destKey2同理对应,以此推类.
125 | @append YES: 不会覆盖destCla的原数据,在其末尾继续添加;NO: 覆盖掉原数据,即将原数据删掉,然后将新数据拷贝过来.
126 | */
127 | -(void)copyTable:(NSString* _Nonnull)srcTable to:(NSString* _Nonnull)destTable keyDict:(NSDictionary* const _Nonnull)keydict append:(BOOL)append complete:(bg_complete_I)complete;
128 |
129 | /**----------------------------------华丽分割线---------------------------------------------*/
130 | #pragma mark --> 以下是非直接存储一个对象的API
131 |
132 | /**
133 | 数据库中是否存在表.
134 | @name 表名称.
135 | @complete 回调的block
136 | */
137 | - (void)isExistWithTableName:( NSString* _Nonnull)name complete:(bg_complete_B)complete;
138 | - (BOOL)bg_isExistWithTableName:( NSString* _Nonnull)name;
139 | /**
140 | 创建表(如果存在则不创建)
141 | @name 表名称.
142 | @keys 数据存放要求@[字段名称1,字段名称2].
143 | @uniqueKeys '唯一约束'集合.
144 | @complete 回调的block
145 | */
146 | -(void)createTableWithTableName:(NSString* _Nonnull)name keys:(NSArray* _Nonnull)keys unionPrimaryKeys:(NSArray* _Nullable)unionPrimaryKeys uniqueKeys:(NSArray* _Nullable)uniqueKeys complete:(bg_complete_B)complete;
147 | /**
148 | 插入数据.
149 | @name 表名称.
150 | @dict 插入的数据,只关心key和value 即@{key:value,key:value}.
151 | @complete 回调的block
152 | */
153 | -(void)insertIntoTableName:(NSString* _Nonnull)name Dict:(NSDictionary* _Nonnull)dict complete:(bg_complete_B)complete;
154 | /**
155 | 直接传入条件sql语句查询.
156 | @name 表名称.
157 | @conditions 条件语句.例如:@"where BG_name = '标哥' or BG_name = '小马哥' and BG_age = 26 order by BG_age desc limit 6" 即查询BG_name等于标哥或小马哥和BG_age等于26的数据通过BG_age降序输出,只查询前面6条.
158 | 更多条件语法,请查询sql的基本使用语句.
159 | */
160 | -(void)queryWithTableName:(NSString* _Nonnull)name conditions:(NSString* _Nullable)conditions complete:(bg_complete_A)complete;
161 | /**
162 | 根据条件查询字段.
163 | @name 表名称.
164 | @keys 存放的是要查询的哪些key,为nil时代表查询全部.
165 | @where 形式 @[@"key",@"=",@"value",@"key",@">=",@"value"],条件key属性只能是系统自带的属性,暂不支持自定义类.
166 | @complete 回调的block,返回的数组元素是字典 @[@{key:value},@{key:value}] .
167 | */
168 | -(void)queryWithTableName:(NSString* _Nonnull)name keys:(NSArray* _Nullable)keys where:(NSArray* _Nullable)where complete:(bg_complete_A)complete;
169 | /**
170 | 全部查询.
171 | @name 表名称.
172 | @where 条件参数 例如排序 @"order by BG_bg_id desc" 等.
173 | @complete 回调的block,返回的数组元素是字典 @[@{key:value},@{key:value}] .
174 | */
175 | -(void)queryWithTableName:(NSString* _Nonnull)name where:(NSString* _Nullable)where complete:(bg_complete_A)complete;
176 | /**
177 | 直接传入条件sql语句更新.
178 | */
179 | -(void)updateWithObject:(id _Nonnull)object valueDict:(NSDictionary* _Nullable)valueDict conditions:(NSString* _Nonnull)conditions complete:(bg_complete_B)complete;
180 | /**
181 | 根据表名和条件删除表内容.
182 | @name 表名称.
183 | @where 条件数组,形式 @[@"key",@"=",@"value",@"key",@">=",@"value"],where要非空.
184 | @complete 回调的block.
185 | */
186 | -(void)deleteWithTableName:(NSString* _Nonnull)name where:(NSArray* _Nonnull)where complete:(bg_complete_B)complete;
187 | /**
188 | 直接传入条件sql语句删除.
189 | */
190 | -(void)deleteWithTableName:(NSString* _Nonnull)name conditions:(NSString* _Nullable)conditions complete:(bg_complete_B)complete;
191 | /**
192 | 根据keypath删除表内容.
193 | @name 表名称.
194 | @keyPathValues数组,形式@[@"user.student.name",Equal,@"小芳",@"user.student.conten",Contains,@"书"]
195 | 即删除user.student.name=@"小芳" 和 user.student.content中包含@“书”这个字符串的对象.
196 | */
197 | -(void)deleteWithTableName:(NSString* _Nonnull)name forKeyPathAndValues:(NSArray* _Nonnull)keyPathValues complete:(bg_complete_B)complete;
198 | /**
199 | 根据表名删除表格全部内容.
200 | @name 表名称.
201 | @complete 回调的block.
202 | */
203 | -(void)clearTable:(NSString* _Nonnull)name complete:(bg_complete_B)complete;
204 | /**
205 | 删除表.
206 | @name 表名称.
207 | @complete 回调的block.
208 | */
209 | -(void)dropTable:(NSString* _Nonnull)name complete:(bg_complete_B)complete;
210 | /**
211 | 删除表(线程安全).
212 | */
213 | -(void)dropSafeTable:(NSString* _Nonnull)name complete:(bg_complete_B)complete;
214 | /**
215 | 动态添加表字段.
216 | @name 表名称.
217 | @key 将要增加的字段.
218 | @complete 回调的block.
219 | */
220 | -(void)addTable:(NSString* _Nonnull)name key:(NSString* _Nonnull)key complete:(bg_complete_B)complete;
221 | /**
222 | 查询该表中有多少条数据
223 | @name 表名称.
224 | @where 条件数组,形式 @[@"key",@"=",@"value",@"key",@">=",@"value"],为nil时返回全部数据的条数.
225 | */
226 | -(NSInteger)countForTable:(NSString* _Nonnull)name where:(NSArray* _Nullable)where;
227 | /**
228 | 直接传入条件sql语句查询数据条数.
229 | */
230 | -(NSInteger)countForTable:(NSString* _Nonnull)name conditions:(NSString* _Nullable)conditions;
231 | /**
232 | keyPath查询数据条数.
233 | */
234 | -(NSInteger)countForTable:(NSString* _Nonnull)name forKeyPathAndValues:(NSArray* _Nonnull)keyPathValues;
235 | /**
236 | 直接调用sqliteb的原生函数计算sun,min,max,avg等.
237 | */
238 | -(double)sqliteMethodForTable:(NSString* _Nonnull)name type:(bg_sqliteMethodType)methodType key:(NSString* _Nonnull)key where:(NSString* _Nullable)where;
239 | /**
240 | 刷新数据库,即将旧数据库的数据复制到新建的数据库,这是为了去掉没用的字段.
241 | @name 表名称.
242 | @keys 新表的数组字段.
243 | */
244 | -(void)refreshTable:(NSString* _Nonnull)name class:(__unsafe_unretained _Nonnull Class)cla keys:(NSArray* const _Nonnull)keys complete:(bg_complete_I)complete;
245 | -(void)refreshTable:(NSString* _Nonnull)name class:(__unsafe_unretained _Nonnull Class)cla keys:(NSArray* const _Nonnull)keys keyDict:(NSDictionary* const _Nonnull)keyDict complete:(bg_complete_I)complete;
246 | /**
247 | 直接执行sql语句.
248 | @tablename 要操作的表名.
249 | @cla 要操作的类.
250 | */
251 | -(id _Nullable)bg_executeSql:(NSString* const _Nonnull)sql tablename:(NSString* _Nonnull)tablename class:(__unsafe_unretained _Nonnull Class)cla;
252 | #pragma mark 存储数组.
253 | /**
254 | 直接存储数组.
255 | */
256 | -(void)saveArray:(NSArray* _Nonnull)array name:(NSString* _Nonnull)name complete:(bg_complete_B)complete;
257 | /**
258 | 读取数组.
259 | */
260 | -(void)queryArrayWithName:(NSString* _Nonnull)name complete:(bg_complete_A)complete;
261 | /**
262 | 读取数组某个元素.
263 | */
264 | -(id _Nullable)queryArrayWithName:(NSString* _Nonnull)name index:(NSInteger)index;
265 | /**
266 | 更新数组某个元素.
267 | */
268 | -(BOOL)updateObjectWithName:(NSString* _Nonnull)name object:(id _Nonnull)object index:(NSInteger)index;
269 | /**
270 | 删除数组某个元素.
271 | */
272 | -(BOOL)deleteObjectWithName:(NSString* _Nonnull)name index:(NSInteger)index;
273 |
274 |
275 | #pragma mark 存储字典.
276 | /**
277 | 直接存储字典.
278 | */
279 | -(void)saveDictionary:(NSDictionary* _Nonnull)dictionary complete:(bg_complete_B)complete;
280 | /**
281 | 添加字典元素.
282 | */
283 | -(BOOL)bg_setValue:(id _Nonnull)value forKey:(NSString* const _Nonnull)key;
284 | /**
285 | 更新字典元素.
286 | */
287 | -(BOOL)bg_updateValue:(id _Nonnull)value forKey:(NSString* const _Nonnull)key;
288 | /**
289 | 遍历字典元素.
290 | */
291 | -(void)bg_enumerateKeysAndObjectsUsingBlock:(void (^ _Nonnull)(NSString* _Nonnull key, id _Nonnull value,BOOL *stop))block;
292 | /**
293 | 获取字典元素.
294 | */
295 | -(id _Nullable)bg_valueForKey:(NSString* const _Nonnull)key;
296 | /**
297 | 删除字典元素.
298 | */
299 | -(BOOL)bg_deleteValueForKey:(NSString* const _Nonnull)key;
300 | @end
301 |
--------------------------------------------------------------------------------
/BGFMDB/libs/BG/BGFMDB.h:
--------------------------------------------------------------------------------
1 | //
2 | // BGFMDB.h
3 | // BGFMDB
4 | //
5 | // Created by biao on 2017/10/18.
6 | // Copyright © 2017年 Biao. All rights reserved.
7 | //
8 |
9 | #ifndef BGFMDB_h
10 | #define BGFMDB_h
11 |
12 | #import "NSObject+BGModel.h"
13 |
14 | #endif /* BGFMDB_h */
15 |
--------------------------------------------------------------------------------
/BGFMDB/libs/BG/BGFMDBConfig.h:
--------------------------------------------------------------------------------
1 | //
2 | // BGFMDBConfig.h
3 | // BGFMDB
4 | //
5 | // Created by biao on 2017/7/19.
6 | // Copyright © 2017年 Biao. All rights reserved.
7 | //
8 |
9 | #ifndef BGFMDBConfig_h
10 | #define BGFMDBConfig_h
11 |
12 | // 过期方法注释
13 | #define BGFMDBDeprecated(instead) NS_DEPRECATED(2_0, 2_0, 2_0, 2_0, instead)
14 |
15 | #define bg_primaryKey @"bg_id"
16 | #define bg_createTimeKey @"bg_createTime"
17 | #define bg_updateTimeKey @"bg_updateTime"
18 |
19 | //keyPath查询用的关系,bg_equal:等于的关系;bg_contains:包含的关系.
20 | #define bg_equal @"Relation_Equal"
21 | #define bg_contains @"Relation_Contains"
22 |
23 | #define bg_complete_B void(^_Nullable)(BOOL isSuccess)
24 | #define bg_complete_I void(^_Nullable)(bg_dealState result)
25 | #define bg_complete_A void(^_Nullable)(NSArray* _Nullable array)
26 | #define bg_changeBlock void(^_Nullable)(bg_changeState result)
27 |
28 | typedef NS_ENUM(NSInteger,bg_changeState){//数据改变状态
29 | bg_insert,//插入
30 | bg_update,//更新
31 | bg_delete,//删除
32 | bg_drop//删表
33 | };
34 |
35 | typedef NS_ENUM(NSInteger,bg_dealState){//处理状态
36 | bg_error = -1,//处理失败
37 | bg_incomplete = 0,//处理不完整
38 | bg_complete = 1//处理完整
39 | };
40 |
41 | typedef NS_ENUM(NSInteger,bg_sqliteMethodType){//sqlite数据库原生方法枚举
42 | bg_min,//求最小值
43 | bg_max,//求最大值
44 | bg_sum,//求总和值
45 | bg_avg//求平均值
46 | };
47 |
48 | typedef NS_ENUM(NSInteger,bg_dataTimeType){
49 | bg_createTime,//存储时间
50 | bg_updateTime,//更新时间
51 | };
52 |
53 | /**
54 | 封装处理传入数据库的key和value.
55 | */
56 | extern NSString* _Nonnull bg_sqlKey(NSString* _Nonnull key);
57 | /**
58 | 转换OC对象成数据库数据.
59 | */
60 | extern NSString* _Nonnull bg_sqlValue(id _Nonnull value);
61 | /**
62 | 根据keyPath和Value的数组, 封装成数据库语句,来操作库.
63 | */
64 | extern NSString* _Nonnull bg_keyPathValues(NSArray* _Nonnull keyPathValues);
65 | /**
66 | 直接执行sql语句;
67 | @tablename nil时以cla类名为表名.
68 | @cla 要操作的类,nil时返回的结果是字典.
69 | 提示:字段名要增加BG_前缀
70 | */
71 | extern id _Nullable bg_executeSql(NSString* _Nonnull sql,NSString* _Nullable tablename,__unsafe_unretained _Nullable Class cla);
72 | /**
73 | 自定义数据库名称.
74 | */
75 | extern void bg_setSqliteName(NSString*_Nonnull sqliteName);
76 | /**
77 | 删除数据库文件
78 | */
79 | extern BOOL bg_deleteSqlite(NSString*_Nonnull sqliteName);
80 | /**
81 | 设置操作过程中不可关闭数据库(即closeDB函数无效).
82 | 默认是NO.
83 | */
84 | extern void bg_setDisableCloseDB(BOOL disableCloseDB);
85 | /**
86 | 手动关闭数据库.
87 | */
88 | extern void bg_closeDB();
89 | /**
90 | 设置调试模式
91 | @debug YES:打印调试信息, NO:不打印调试信息.
92 | */
93 | extern void bg_setDebug(BOOL debug);
94 |
95 | /**
96 | 事务操作.
97 | @return 返回YES提交事务, 返回NO回滚事务.
98 | */
99 | extern void bg_inTransaction(BOOL (^ _Nonnull block)());
100 |
101 | /**
102 | 清除缓存
103 | */
104 | extern void bg_cleanCache();
105 |
106 | #endif /* BGFMDBConfig_h */
107 |
--------------------------------------------------------------------------------
/BGFMDB/libs/BG/BGTool.h:
--------------------------------------------------------------------------------
1 | //
2 | // BGTool.h
3 | // BGFMDB
4 | //
5 | // Created by huangzhibiao on 17/2/16.
6 | // Copyright © 2017年 Biao. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | /**
13 | 日志输出
14 | */
15 | #ifdef DEBUG
16 | #define bg_log(...) NSLog(__VA_ARGS__)
17 | #else
18 | #define bg_log(...)
19 | #endif
20 |
21 | #define bg_completeBlock(obj) !complete?:complete(obj);
22 |
23 | #define BG @"BG_"
24 | #define bg_tableNameKey @"bg_tableName"
25 | #define bg_rowid @"rowid"
26 |
27 | #define bg_uniqueKeysSelector NSSelectorFromString(@"bg_uniqueKeys")
28 | #define bg_ignoreKeysSelector NSSelectorFromString(@"bg_ignoreKeys")
29 | #define bg_unionPrimaryKeysSelector NSSelectorFromString(@"bg_unionPrimaryKeys")
30 |
31 | typedef NS_ENUM(NSInteger,bg_getModelInfoType){//过滤数据类型
32 | bg_ModelInfoInsert,//插入过滤
33 | bg_ModelInfoSingleUpdate,//单条更新过滤
34 | bg_ModelInfoArrayUpdate,//批量更新过滤
35 | bg_ModelInfoNone//无过滤
36 | };
37 |
38 | @interface BGTool : NSObject
39 | /**
40 | json字符转json格式数据 .
41 | */
42 | +(id _Nonnull)jsonWithString:(NSString* _Nonnull)jsonString;
43 | /**
44 | 字典转json字符 .
45 | */
46 | +(NSString* _Nonnull)dataToJson:(id _Nonnull)data;
47 | /**
48 | 根据类获取变量名列表
49 | @onlyKey YES:紧紧返回key,NO:在key后面添加type.
50 | */
51 | +(NSArray* _Nonnull)getClassIvarList:(__unsafe_unretained _Nonnull Class)cla Object:(_Nullable id)object onlyKey:(BOOL)onlyKey;
52 | /**
53 | 抽取封装条件数组处理函数.
54 | */
55 | +(NSArray* _Nonnull)where:(NSArray* _Nonnull)where;
56 | /**
57 | 封装like语句获取函数
58 | */
59 | +(NSString* _Nonnull)getLikeWithKeyPathAndValues:(NSArray* _Nonnull)keyPathValues where:(BOOL)where;
60 | /**
61 | 判断是不是主键.
62 | */
63 | +(BOOL)isUniqueKey:(NSString* _Nonnull)uniqueKey with:(NSString* _Nonnull)param;
64 | /**
65 | 判断并获取字段类型.
66 | */
67 | +(NSString* _Nonnull)keyAndType:(NSString* _Nonnull)param;
68 | /**
69 | 根据类属性类型返回数据库存储类型.
70 | */
71 | +(NSString* _Nonnull)getSqlType:(NSString* _Nonnull)type;
72 | //NSDate转字符串,格式: yyyy-MM-dd HH:mm:ss
73 | +(NSString* _Nonnull)stringWithDate:(NSDate* _Nonnull)date;
74 | /**
75 | 根据传入的对象获取表名.
76 | */
77 | +(NSString* _Nonnull)getTableNameWithObject:(id _Nonnull)object;
78 | /**
79 | 根据类属性值和属性类型返回数据库存储的值.
80 | @value 数值.
81 | @type 数组value的类型.
82 | @encode YES:编码 , NO:解码.
83 | */
84 | +(id _Nonnull)getSqlValue:(id _Nonnull)value type:(NSString* _Nonnull)type encode:(BOOL)encode;
85 | /**
86 | 转换从数据库中读取出来的数据.
87 | @tableName 表名(即类名).
88 | @array 传入要转换的数组数据.
89 | */
90 | +(NSArray* _Nonnull)tansformDataFromSqlDataWithTableName:(NSString* _Nonnull)tableName class:(__unsafe_unretained _Nonnull Class)cla array:(NSArray* _Nonnull)array;
91 | /**
92 | 转换从数据库中读取出来的数据.
93 | @claName 类名.
94 | @valueDict 传入要转换的字典数据.
95 | */
96 | +(id _Nonnull)objectFromJsonStringWithTableName:(NSString* _Nonnull)tablename class:(__unsafe_unretained _Nonnull Class)cla valueDict:(NSDictionary* _Nonnull)valueDict;
97 | /**
98 | 字典或json格式字符转模型用的处理函数.
99 | */
100 | +(id _Nonnull)bg_objectWithClass:(__unsafe_unretained _Nonnull Class)cla value:(id _Nonnull)value;
101 | /**
102 | 模型转字典.
103 | */
104 | +(NSMutableDictionary* _Nonnull)bg_keyValuesWithObject:(id _Nonnull)object ignoredKeys:(NSArray* _Nullable)ignoredKeys;
105 | /**
106 | 判断并执行类方法.
107 | */
108 | +(id _Nonnull)executeSelector:(SEL _Nonnull)selector forClass:(__unsafe_unretained _Nonnull Class)cla;
109 | /**
110 | 判断并执行对象方法.
111 | */
112 | +(id _Nonnull)executeSelector:(SEL _Nonnull)selector forObject:(id _Nonnull)object;
113 | /**
114 | 根据对象获取要更新或插入的字典.
115 | */
116 | +(NSDictionary* _Nonnull)getDictWithObject:(id _Nonnull)object ignoredKeys:(NSArray* const _Nullable)ignoredKeys filtModelInfoType:(bg_getModelInfoType)filtModelInfoType;
117 | /**
118 | 过滤建表的key.
119 | */
120 | +(NSArray* _Nonnull)bg_filtCreateKeys:(NSArray* _Nonnull)createkeys ignoredkeys:(NSArray* _Nonnull)ignoredkeys;
121 | /**
122 | 如果表格不存在就新建.
123 | */
124 | +(BOOL)ifNotExistWillCreateTableWithObject:(id _Nonnull)object ignoredKeys:(NSArray* const _Nullable)ignoredKeys;
125 | /**
126 | 整形判断
127 | */
128 | + (BOOL)isPureInt:(NSString* _Nonnull)string;
129 | /**
130 | 浮点形判断
131 | */
132 | + (BOOL)isPureFloat:(NSString* _Nonnull)string;
133 | /**
134 | NSUserDefaults封装使用函数.
135 | */
136 | +(BOOL)getBoolWithKey:(NSString* _Nonnull)key;
137 | +(void)setBoolWithKey:(NSString* _Nonnull)key value:(BOOL)value;
138 | +(NSString* _Nonnull)getStringWithKey:(NSString* _Nonnull)key;
139 | +(void)setStringWithKey:(NSString* _Nonnull)key value:(NSString* _Nonnull)value;
140 | +(NSInteger)getIntegerWithKey:(NSString* _Nonnull)key;
141 | +(void)setIntegerWithKey:(NSString* _Nonnull)key value:(NSInteger)value;
142 | @end
143 |
--------------------------------------------------------------------------------
/BGFMDB/libs/BG/NSCache+BGCache.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSCache+BGCache.h
3 | // BGFMDB
4 | //
5 | // Created by biao on 2017/10/17.
6 | // Copyright © 2017年 Biao. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface NSCache (BGCache)
12 |
13 | +(instancetype)bg_cache;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/BGFMDB/libs/BG/NSCache+BGCache.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSCache+BGCache.m
3 | // BGFMDB
4 | //
5 | // Created by biao on 2017/10/17.
6 | // Copyright © 2017年 Biao. All rights reserved.
7 | //
8 |
9 | #import "NSCache+BGCache.h"
10 |
11 | static NSCache* keyCaches;
12 | @implementation NSCache (BGCache)
13 |
14 | +(instancetype)bg_cache{
15 | static dispatch_once_t onceToken;
16 | dispatch_once(&onceToken, ^{
17 | keyCaches = [NSCache new];
18 | });
19 | return keyCaches;
20 | }
21 |
22 | @end
23 |
--------------------------------------------------------------------------------
/BGFMDB/libs/FMDB/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huangzhibiao/BGFMDB/7a9392636fea94bc3e4de5f5468b218c663f12a6/BGFMDB/libs/FMDB/.DS_Store
--------------------------------------------------------------------------------
/BGFMDB/libs/FMDB/FMDB.h:
--------------------------------------------------------------------------------
1 | #import
2 |
3 | FOUNDATION_EXPORT double FMDBVersionNumber;
4 | FOUNDATION_EXPORT const unsigned char FMDBVersionString[];
5 |
6 | #import "FMDatabase.h"
7 | #import "FMResultSet.h"
8 | #import "FMDatabaseAdditions.h"
9 | #import "FMDatabaseQueue.h"
10 | #import "FMDatabasePool.h"
11 |
--------------------------------------------------------------------------------
/BGFMDB/libs/FMDB/FMDatabaseAdditions.h:
--------------------------------------------------------------------------------
1 | //
2 | // FMDatabaseAdditions.h
3 | // fmdb
4 | //
5 | // Created by August Mueller on 10/30/05.
6 | // Copyright 2005 Flying Meat Inc.. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "FMDatabase.h"
11 |
12 | NS_ASSUME_NONNULL_BEGIN
13 |
14 | /** Category of additions for `` class.
15 |
16 | ### See also
17 |
18 | - ``
19 | */
20 |
21 | @interface FMDatabase (FMDatabaseAdditions)
22 |
23 | ///----------------------------------------
24 | /// @name Return results of SQL to variable
25 | ///----------------------------------------
26 |
27 | /** Return `int` value for query
28 |
29 | @param query The SQL query to be performed.
30 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query.
31 |
32 | @return `int` value.
33 |
34 | @note This is not available from Swift.
35 | */
36 |
37 | - (int)intForQuery:(NSString*)query, ...;
38 |
39 | /** Return `long` value for query
40 |
41 | @param query The SQL query to be performed.
42 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query.
43 |
44 | @return `long` value.
45 |
46 | @note This is not available from Swift.
47 | */
48 |
49 | - (long)longForQuery:(NSString*)query, ...;
50 |
51 | /** Return `BOOL` value for query
52 |
53 | @param query The SQL query to be performed.
54 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query.
55 |
56 | @return `BOOL` value.
57 |
58 | @note This is not available from Swift.
59 | */
60 |
61 | - (BOOL)boolForQuery:(NSString*)query, ...;
62 |
63 | /** Return `double` value for query
64 |
65 | @param query The SQL query to be performed.
66 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query.
67 |
68 | @return `double` value.
69 |
70 | @note This is not available from Swift.
71 | */
72 |
73 | - (double)doubleForQuery:(NSString*)query, ...;
74 |
75 | /** Return `NSString` value for query
76 |
77 | @param query The SQL query to be performed.
78 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query.
79 |
80 | @return `NSString` value.
81 |
82 | @note This is not available from Swift.
83 | */
84 |
85 | - (NSString * _Nullable)stringForQuery:(NSString*)query, ...;
86 |
87 | /** Return `NSData` value for query
88 |
89 | @param query The SQL query to be performed.
90 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query.
91 |
92 | @return `NSData` value.
93 |
94 | @note This is not available from Swift.
95 | */
96 |
97 | - (NSData * _Nullable)dataForQuery:(NSString*)query, ...;
98 |
99 | /** Return `NSDate` value for query
100 |
101 | @param query The SQL query to be performed.
102 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query.
103 |
104 | @return `NSDate` value.
105 |
106 | @note This is not available from Swift.
107 | */
108 |
109 | - (NSDate * _Nullable)dateForQuery:(NSString*)query, ...;
110 |
111 |
112 | // Notice that there's no dataNoCopyForQuery:.
113 | // That would be a bad idea, because we close out the result set, and then what
114 | // happens to the data that we just didn't copy? Who knows, not I.
115 |
116 |
117 | ///--------------------------------
118 | /// @name Schema related operations
119 | ///--------------------------------
120 |
121 | /** Does table exist in database?
122 |
123 | @param tableName The name of the table being looked for.
124 |
125 | @return `YES` if table found; `NO` if not found.
126 | */
127 |
128 | - (BOOL)tableExists:(NSString*)tableName;
129 |
130 | /** The schema of the database.
131 |
132 | This will be the schema for the entire database. For each entity, each row of the result set will include the following fields:
133 |
134 | - `type` - The type of entity (e.g. table, index, view, or trigger)
135 | - `name` - The name of the object
136 | - `tbl_name` - The name of the table to which the object references
137 | - `rootpage` - The page number of the root b-tree page for tables and indices
138 | - `sql` - The SQL that created the entity
139 |
140 | @return `FMResultSet` of schema; `nil` on error.
141 |
142 | @see [SQLite File Format](http://www.sqlite.org/fileformat.html)
143 | */
144 |
145 | - (FMResultSet *)getSchema;
146 |
147 | /** The schema of the database.
148 |
149 | This will be the schema for a particular table as report by SQLite `PRAGMA`, for example:
150 |
151 | PRAGMA table_info('employees')
152 |
153 | This will report:
154 |
155 | - `cid` - The column ID number
156 | - `name` - The name of the column
157 | - `type` - The data type specified for the column
158 | - `notnull` - whether the field is defined as NOT NULL (i.e. values required)
159 | - `dflt_value` - The default value for the column
160 | - `pk` - Whether the field is part of the primary key of the table
161 |
162 | @param tableName The name of the table for whom the schema will be returned.
163 |
164 | @return `FMResultSet` of schema; `nil` on error.
165 |
166 | @see [table_info](http://www.sqlite.org/pragma.html#pragma_table_info)
167 | */
168 |
169 | - (FMResultSet*)getTableSchema:(NSString*)tableName;
170 |
171 | /** Test to see if particular column exists for particular table in database
172 |
173 | @param columnName The name of the column.
174 |
175 | @param tableName The name of the table.
176 |
177 | @return `YES` if column exists in table in question; `NO` otherwise.
178 | */
179 |
180 | - (BOOL)columnExists:(NSString*)columnName inTableWithName:(NSString*)tableName;
181 |
182 | /** Test to see if particular column exists for particular table in database
183 |
184 | @param columnName The name of the column.
185 |
186 | @param tableName The name of the table.
187 |
188 | @return `YES` if column exists in table in question; `NO` otherwise.
189 |
190 | @see columnExists:inTableWithName:
191 |
192 | @warning Deprecated - use `` instead.
193 | */
194 |
195 | - (BOOL)columnExists:(NSString*)tableName columnName:(NSString*)columnName __deprecated_msg("Use columnExists:inTableWithName: instead");
196 |
197 |
198 | /** Validate SQL statement
199 |
200 | This validates SQL statement by performing `sqlite3_prepare_v2`, but not returning the results, but instead immediately calling `sqlite3_finalize`.
201 |
202 | @param sql The SQL statement being validated.
203 |
204 | @param error This is a pointer to a `NSError` object that will receive the autoreleased `NSError` object if there was any error. If this is `nil`, no `NSError` result will be returned.
205 |
206 | @return `YES` if validation succeeded without incident; `NO` otherwise.
207 |
208 | */
209 |
210 | - (BOOL)validateSQL:(NSString*)sql error:(NSError * _Nullable *)error;
211 |
212 |
213 | ///-----------------------------------
214 | /// @name Application identifier tasks
215 | ///-----------------------------------
216 |
217 | /** Retrieve application ID
218 |
219 | @return The `uint32_t` numeric value of the application ID.
220 |
221 | @see setApplicationID:
222 | */
223 |
224 | @property (nonatomic) uint32_t applicationID;
225 |
226 | #if TARGET_OS_MAC && !TARGET_OS_IPHONE
227 |
228 | /** Retrieve application ID string
229 |
230 | @see setApplicationIDString:
231 | */
232 |
233 | @property (nonatomic, retain) NSString *applicationIDString;
234 |
235 | #endif
236 |
237 | ///-----------------------------------
238 | /// @name user version identifier tasks
239 | ///-----------------------------------
240 |
241 | /** Retrieve user version
242 |
243 | @see setUserVersion:
244 | */
245 |
246 | @property (nonatomic) uint32_t userVersion;
247 |
248 | @end
249 |
250 | NS_ASSUME_NONNULL_END
251 |
--------------------------------------------------------------------------------
/BGFMDB/libs/FMDB/FMDatabaseAdditions.m:
--------------------------------------------------------------------------------
1 | //
2 | // FMDatabaseAdditions.m
3 | // fmdb
4 | //
5 | // Created by August Mueller on 10/30/05.
6 | // Copyright 2005 Flying Meat Inc.. All rights reserved.
7 | //
8 |
9 | #import "FMDatabase.h"
10 | #import "FMDatabaseAdditions.h"
11 | #import "TargetConditionals.h"
12 |
13 | #if FMDB_SQLITE_STANDALONE
14 | #import
15 | #else
16 | #import
17 | #endif
18 |
19 | @interface FMDatabase (PrivateStuff)
20 | - (FMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray * _Nullable)arrayArgs orDictionary:(NSDictionary * _Nullable)dictionaryArgs orVAList:(va_list)args;
21 | @end
22 |
23 | @implementation FMDatabase (FMDatabaseAdditions)
24 |
25 | #define RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(type, sel) \
26 | va_list args; \
27 | va_start(args, query); \
28 | FMResultSet *resultSet = [self executeQuery:query withArgumentsInArray:0x00 orDictionary:0x00 orVAList:args]; \
29 | va_end(args); \
30 | if (![resultSet next]) { return (type)0; } \
31 | type ret = [resultSet sel:0]; \
32 | [resultSet close]; \
33 | [resultSet setParentDB:nil]; \
34 | return ret;
35 |
36 |
37 | - (NSString *)stringForQuery:(NSString*)query, ... {
38 | RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(NSString *, stringForColumnIndex);
39 | }
40 |
41 | - (int)intForQuery:(NSString*)query, ... {
42 | RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(int, intForColumnIndex);
43 | }
44 |
45 | - (long)longForQuery:(NSString*)query, ... {
46 | RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(long, longForColumnIndex);
47 | }
48 |
49 | - (BOOL)boolForQuery:(NSString*)query, ... {
50 | RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(BOOL, boolForColumnIndex);
51 | }
52 |
53 | - (double)doubleForQuery:(NSString*)query, ... {
54 | RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(double, doubleForColumnIndex);
55 | }
56 |
57 | - (NSData*)dataForQuery:(NSString*)query, ... {
58 | RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(NSData *, dataForColumnIndex);
59 | }
60 |
61 | - (NSDate*)dateForQuery:(NSString*)query, ... {
62 | RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(NSDate *, dateForColumnIndex);
63 | }
64 |
65 |
66 | - (BOOL)tableExists:(NSString*)tableName {
67 |
68 | tableName = [tableName lowercaseString];
69 |
70 | FMResultSet *rs = [self executeQuery:@"select [sql] from sqlite_master where [type] = 'table' and lower(name) = ?", tableName];
71 |
72 | //if at least one next exists, table exists
73 | BOOL returnBool = [rs next];
74 |
75 | //close and free object
76 | [rs close];
77 |
78 | return returnBool;
79 | }
80 |
81 | /*
82 | get table with list of tables: result colums: type[STRING], name[STRING],tbl_name[STRING],rootpage[INTEGER],sql[STRING]
83 | check if table exist in database (patch from OZLB)
84 | */
85 | - (FMResultSet*)getSchema {
86 |
87 | //result colums: type[STRING], name[STRING],tbl_name[STRING],rootpage[INTEGER],sql[STRING]
88 | FMResultSet *rs = [self executeQuery:@"SELECT type, name, tbl_name, rootpage, sql FROM (SELECT * FROM sqlite_master UNION ALL SELECT * FROM sqlite_temp_master) WHERE type != 'meta' AND name NOT LIKE 'sqlite_%' ORDER BY tbl_name, type DESC, name"];
89 |
90 | return rs;
91 | }
92 |
93 | /*
94 | get table schema: result colums: cid[INTEGER], name,type [STRING], notnull[INTEGER], dflt_value[],pk[INTEGER]
95 | */
96 | - (FMResultSet*)getTableSchema:(NSString*)tableName {
97 |
98 | //result colums: cid[INTEGER], name,type [STRING], notnull[INTEGER], dflt_value[],pk[INTEGER]
99 | FMResultSet *rs = [self executeQuery:[NSString stringWithFormat: @"pragma table_info('%@')", tableName]];
100 |
101 | return rs;
102 | }
103 |
104 | - (BOOL)columnExists:(NSString*)columnName inTableWithName:(NSString*)tableName {
105 |
106 | BOOL returnBool = NO;
107 |
108 | tableName = [tableName lowercaseString];
109 | columnName = [columnName lowercaseString];
110 |
111 | FMResultSet *rs = [self getTableSchema:tableName];
112 |
113 | //check if column is present in table schema
114 | while ([rs next]) {
115 | if ([[[rs stringForColumn:@"name"] lowercaseString] isEqualToString:columnName]) {
116 | returnBool = YES;
117 | break;
118 | }
119 | }
120 |
121 | //If this is not done FMDatabase instance stays out of pool
122 | [rs close];
123 |
124 | return returnBool;
125 | }
126 |
127 |
128 |
129 | - (uint32_t)applicationID {
130 | #if SQLITE_VERSION_NUMBER >= 3007017
131 | uint32_t r = 0;
132 |
133 | FMResultSet *rs = [self executeQuery:@"pragma application_id"];
134 |
135 | if ([rs next]) {
136 | r = (uint32_t)[rs longLongIntForColumnIndex:0];
137 | }
138 |
139 | [rs close];
140 |
141 | return r;
142 | #else
143 | NSString *errorMessage = NSLocalizedString(@"Application ID functions require SQLite 3.7.17", nil);
144 | if (self.logsErrors) NSLog(@"%@", errorMessage);
145 | return 0;
146 | #endif
147 | }
148 |
149 | - (void)setApplicationID:(uint32_t)appID {
150 | #if SQLITE_VERSION_NUMBER >= 3007017
151 | NSString *query = [NSString stringWithFormat:@"pragma application_id=%d", appID];
152 | FMResultSet *rs = [self executeQuery:query];
153 | [rs next];
154 | [rs close];
155 | #else
156 | NSString *errorMessage = NSLocalizedString(@"Application ID functions require SQLite 3.7.17", nil);
157 | if (self.logsErrors) NSLog(@"%@", errorMessage);
158 | #endif
159 | }
160 |
161 |
162 | #if TARGET_OS_MAC && !TARGET_OS_IPHONE
163 |
164 | - (NSString*)applicationIDString {
165 | #if SQLITE_VERSION_NUMBER >= 3007017
166 | NSString *s = NSFileTypeForHFSTypeCode([self applicationID]);
167 |
168 | assert([s length] == 6);
169 |
170 | s = [s substringWithRange:NSMakeRange(1, 4)];
171 |
172 |
173 | return s;
174 | #else
175 | NSString *errorMessage = NSLocalizedString(@"Application ID functions require SQLite 3.7.17", nil);
176 | if (self.logsErrors) NSLog(@"%@", errorMessage);
177 | return nil;
178 | #endif
179 | }
180 |
181 | - (void)setApplicationIDString:(NSString*)s {
182 | #if SQLITE_VERSION_NUMBER >= 3007017
183 | if ([s length] != 4) {
184 | NSLog(@"setApplicationIDString: string passed is not exactly 4 chars long. (was %ld)", [s length]);
185 | }
186 |
187 | [self setApplicationID:NSHFSTypeCodeFromFileType([NSString stringWithFormat:@"'%@'", s])];
188 | #else
189 | NSString *errorMessage = NSLocalizedString(@"Application ID functions require SQLite 3.7.17", nil);
190 | if (self.logsErrors) NSLog(@"%@", errorMessage);
191 | #endif
192 | }
193 |
194 | #endif
195 |
196 | - (uint32_t)userVersion {
197 | uint32_t r = 0;
198 |
199 | FMResultSet *rs = [self executeQuery:@"pragma user_version"];
200 |
201 | if ([rs next]) {
202 | r = (uint32_t)[rs longLongIntForColumnIndex:0];
203 | }
204 |
205 | [rs close];
206 | return r;
207 | }
208 |
209 | - (void)setUserVersion:(uint32_t)version {
210 | NSString *query = [NSString stringWithFormat:@"pragma user_version = %d", version];
211 | FMResultSet *rs = [self executeQuery:query];
212 | [rs next];
213 | [rs close];
214 | }
215 |
216 | #pragma clang diagnostic push
217 | #pragma clang diagnostic ignored "-Wdeprecated-implementations"
218 |
219 | - (BOOL)columnExists:(NSString*)tableName columnName:(NSString*)columnName __attribute__ ((deprecated)) {
220 | return [self columnExists:columnName inTableWithName:tableName];
221 | }
222 |
223 | #pragma clang diagnostic pop
224 |
225 | - (BOOL)validateSQL:(NSString*)sql error:(NSError**)error {
226 | sqlite3_stmt *pStmt = NULL;
227 | BOOL validationSucceeded = YES;
228 |
229 | int rc = sqlite3_prepare_v2([self sqliteHandle], [sql UTF8String], -1, &pStmt, 0);
230 | if (rc != SQLITE_OK) {
231 | validationSucceeded = NO;
232 | if (error) {
233 | *error = [NSError errorWithDomain:NSCocoaErrorDomain
234 | code:[self lastErrorCode]
235 | userInfo:[NSDictionary dictionaryWithObject:[self lastErrorMessage]
236 | forKey:NSLocalizedDescriptionKey]];
237 | }
238 | }
239 |
240 | sqlite3_finalize(pStmt);
241 |
242 | return validationSucceeded;
243 | }
244 |
245 | @end
246 |
--------------------------------------------------------------------------------
/BGFMDB/libs/FMDB/FMDatabasePool.h:
--------------------------------------------------------------------------------
1 | //
2 | // FMDatabasePool.h
3 | // fmdb
4 | //
5 | // Created by August Mueller on 6/22/11.
6 | // Copyright 2011 Flying Meat Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 | @class FMDatabase;
14 |
15 | /** Pool of `` objects.
16 |
17 | ### See also
18 |
19 | - ``
20 | - ``
21 |
22 | @warning Before using `FMDatabasePool`, please consider using `` instead.
23 |
24 | If you really really really know what you're doing and `FMDatabasePool` is what
25 | you really really need (ie, you're using a read only database), OK you can use
26 | it. But just be careful not to deadlock!
27 |
28 | For an example on deadlocking, search for:
29 | `ONLY_USE_THE_POOL_IF_YOU_ARE_DOING_READS_OTHERWISE_YOULL_DEADLOCK_USE_FMDATABASEQUEUE_INSTEAD`
30 | in the main.m file.
31 | */
32 |
33 | @interface FMDatabasePool : NSObject
34 |
35 | /** Database path */
36 |
37 | @property (atomic, copy, nullable) NSString *path;
38 |
39 | /** Delegate object */
40 |
41 | @property (atomic, assign, nullable) id delegate;
42 |
43 | /** Maximum number of databases to create */
44 |
45 | @property (atomic, assign) NSUInteger maximumNumberOfDatabasesToCreate;
46 |
47 | /** Open flags */
48 |
49 | @property (atomic, readonly) int openFlags;
50 |
51 | /** Custom virtual file system name */
52 |
53 | @property (atomic, copy, nullable) NSString *vfsName;
54 |
55 |
56 | ///---------------------
57 | /// @name Initialization
58 | ///---------------------
59 |
60 | /** Create pool using path.
61 |
62 | @param aPath The file path of the database.
63 |
64 | @return The `FMDatabasePool` object. `nil` on error.
65 | */
66 |
67 | + (instancetype)databasePoolWithPath:(NSString * _Nullable)aPath;
68 |
69 | /** Create pool using file URL.
70 |
71 | @param url The file `NSURL` of the database.
72 |
73 | @return The `FMDatabasePool` object. `nil` on error.
74 | */
75 |
76 | + (instancetype)databasePoolWithURL:(NSURL * _Nullable)url;
77 |
78 | /** Create pool using path and specified flags
79 |
80 | @param aPath The file path of the database.
81 | @param openFlags Flags passed to the openWithFlags method of the database.
82 |
83 | @return The `FMDatabasePool` object. `nil` on error.
84 | */
85 |
86 | + (instancetype)databasePoolWithPath:(NSString * _Nullable)aPath flags:(int)openFlags;
87 |
88 | /** Create pool using file URL and specified flags
89 |
90 | @param url The file `NSURL` of the database.
91 | @param openFlags Flags passed to the openWithFlags method of the database.
92 |
93 | @return The `FMDatabasePool` object. `nil` on error.
94 | */
95 |
96 | + (instancetype)databasePoolWithURL:(NSURL * _Nullable)url flags:(int)openFlags;
97 |
98 | /** Create pool using path.
99 |
100 | @param aPath The file path of the database.
101 |
102 | @return The `FMDatabasePool` object. `nil` on error.
103 | */
104 |
105 | - (instancetype)initWithPath:(NSString * _Nullable)aPath;
106 |
107 | /** Create pool using file URL.
108 |
109 | @param url The file `NSURL of the database.
110 |
111 | @return The `FMDatabasePool` object. `nil` on error.
112 | */
113 |
114 | - (instancetype)initWithURL:(NSURL * _Nullable)url;
115 |
116 | /** Create pool using path and specified flags.
117 |
118 | @param aPath The file path of the database.
119 | @param openFlags Flags passed to the openWithFlags method of the database
120 |
121 | @return The `FMDatabasePool` object. `nil` on error.
122 | */
123 |
124 | - (instancetype)initWithPath:(NSString * _Nullable)aPath flags:(int)openFlags;
125 |
126 | /** Create pool using file URL and specified flags.
127 |
128 | @param url The file `NSURL` of the database.
129 | @param openFlags Flags passed to the openWithFlags method of the database
130 |
131 | @return The `FMDatabasePool` object. `nil` on error.
132 | */
133 |
134 | - (instancetype)initWithURL:(NSURL * _Nullable)url flags:(int)openFlags;
135 |
136 | /** Create pool using path and specified flags.
137 |
138 | @param aPath The file path of the database.
139 | @param openFlags Flags passed to the openWithFlags method of the database
140 | @param vfsName The name of a custom virtual file system
141 |
142 | @return The `FMDatabasePool` object. `nil` on error.
143 | */
144 |
145 | - (instancetype)initWithPath:(NSString * _Nullable)aPath flags:(int)openFlags vfs:(NSString * _Nullable)vfsName;
146 |
147 | /** Create pool using file URL and specified flags.
148 |
149 | @param url The file `NSURL` of the database.
150 | @param openFlags Flags passed to the openWithFlags method of the database
151 | @param vfsName The name of a custom virtual file system
152 |
153 | @return The `FMDatabasePool` object. `nil` on error.
154 | */
155 |
156 | - (instancetype)initWithURL:(NSURL * _Nullable)url flags:(int)openFlags vfs:(NSString * _Nullable)vfsName;
157 |
158 | /** Returns the Class of 'FMDatabase' subclass, that will be used to instantiate database object.
159 |
160 | Subclasses can override this method to return specified Class of 'FMDatabase' subclass.
161 |
162 | @return The Class of 'FMDatabase' subclass, that will be used to instantiate database object.
163 | */
164 |
165 | + (Class)databaseClass;
166 |
167 | ///------------------------------------------------
168 | /// @name Keeping track of checked in/out databases
169 | ///------------------------------------------------
170 |
171 | /** Number of checked-in databases in pool
172 | */
173 |
174 | @property (nonatomic, readonly) NSUInteger countOfCheckedInDatabases;
175 |
176 | /** Number of checked-out databases in pool
177 | */
178 |
179 | @property (nonatomic, readonly) NSUInteger countOfCheckedOutDatabases;
180 |
181 | /** Total number of databases in pool
182 | */
183 |
184 | @property (nonatomic, readonly) NSUInteger countOfOpenDatabases;
185 |
186 | /** Release all databases in pool */
187 |
188 | - (void)releaseAllDatabases;
189 |
190 | ///------------------------------------------
191 | /// @name Perform database operations in pool
192 | ///------------------------------------------
193 |
194 | /** Synchronously perform database operations in pool.
195 |
196 | @param block The code to be run on the `FMDatabasePool` pool.
197 | */
198 |
199 | - (void)inDatabase:(__attribute__((noescape)) void (^)(FMDatabase *db))block;
200 |
201 | /** Synchronously perform database operations in pool using transaction.
202 |
203 | @param block The code to be run on the `FMDatabasePool` pool.
204 | */
205 |
206 | - (void)inTransaction:(__attribute__((noescape)) void (^)(FMDatabase *db, BOOL *rollback))block;
207 |
208 | /** Synchronously perform database operations in pool using deferred transaction.
209 |
210 | @param block The code to be run on the `FMDatabasePool` pool.
211 | */
212 |
213 | - (void)inDeferredTransaction:(__attribute__((noescape)) void (^)(FMDatabase *db, BOOL *rollback))block;
214 |
215 | /** Synchronously perform database operations in pool using save point.
216 |
217 | @param block The code to be run on the `FMDatabasePool` pool.
218 |
219 | @return `NSError` object if error; `nil` if successful.
220 |
221 | @warning You can not nest these, since calling it will pull another database out of the pool and you'll get a deadlock. If you need to nest, use `<[FMDatabase startSavePointWithName:error:]>` instead.
222 | */
223 |
224 | - (NSError * _Nullable)inSavePoint:(__attribute__((noescape)) void (^)(FMDatabase *db, BOOL *rollback))block;
225 |
226 | @end
227 |
228 |
229 | /** FMDatabasePool delegate category
230 |
231 | This is a category that defines the protocol for the FMDatabasePool delegate
232 | */
233 |
234 | @interface NSObject (FMDatabasePoolDelegate)
235 |
236 | /** Asks the delegate whether database should be added to the pool.
237 |
238 | @param pool The `FMDatabasePool` object.
239 | @param database The `FMDatabase` object.
240 |
241 | @return `YES` if it should add database to pool; `NO` if not.
242 |
243 | */
244 |
245 | - (BOOL)databasePool:(FMDatabasePool*)pool shouldAddDatabaseToPool:(FMDatabase*)database;
246 |
247 | /** Tells the delegate that database was added to the pool.
248 |
249 | @param pool The `FMDatabasePool` object.
250 | @param database The `FMDatabase` object.
251 |
252 | */
253 |
254 | - (void)databasePool:(FMDatabasePool*)pool didAddDatabase:(FMDatabase*)database;
255 |
256 | @end
257 |
258 | NS_ASSUME_NONNULL_END
259 |
--------------------------------------------------------------------------------
/BGFMDB/libs/FMDB/FMDatabasePool.m:
--------------------------------------------------------------------------------
1 | //
2 | // FMDatabasePool.m
3 | // fmdb
4 | //
5 | // Created by August Mueller on 6/22/11.
6 | // Copyright 2011 Flying Meat Inc. All rights reserved.
7 | //
8 |
9 | #if FMDB_SQLITE_STANDALONE
10 | #import
11 | #else
12 | #import
13 | #endif
14 |
15 | #import "FMDatabasePool.h"
16 | #import "FMDatabase.h"
17 |
18 | @interface FMDatabasePool () {
19 | dispatch_queue_t _lockQueue;
20 |
21 | NSMutableArray *_databaseInPool;
22 | NSMutableArray *_databaseOutPool;
23 | }
24 |
25 | - (void)pushDatabaseBackInPool:(FMDatabase*)db;
26 | - (FMDatabase*)db;
27 |
28 | @end
29 |
30 |
31 | @implementation FMDatabasePool
32 | @synthesize path=_path;
33 | @synthesize delegate=_delegate;
34 | @synthesize maximumNumberOfDatabasesToCreate=_maximumNumberOfDatabasesToCreate;
35 | @synthesize openFlags=_openFlags;
36 |
37 |
38 | + (instancetype)databasePoolWithPath:(NSString *)aPath {
39 | return FMDBReturnAutoreleased([[self alloc] initWithPath:aPath]);
40 | }
41 |
42 | + (instancetype)databasePoolWithURL:(NSURL *)url {
43 | return FMDBReturnAutoreleased([[self alloc] initWithPath:url.path]);
44 | }
45 |
46 | + (instancetype)databasePoolWithPath:(NSString *)aPath flags:(int)openFlags {
47 | return FMDBReturnAutoreleased([[self alloc] initWithPath:aPath flags:openFlags]);
48 | }
49 |
50 | + (instancetype)databasePoolWithURL:(NSURL *)url flags:(int)openFlags {
51 | return FMDBReturnAutoreleased([[self alloc] initWithPath:url.path flags:openFlags]);
52 | }
53 |
54 | - (instancetype)initWithURL:(NSURL *)url flags:(int)openFlags vfs:(NSString *)vfsName {
55 | return [self initWithPath:url.path flags:openFlags vfs:vfsName];
56 | }
57 |
58 | - (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags vfs:(NSString *)vfsName {
59 |
60 | self = [super init];
61 |
62 | if (self != nil) {
63 | _path = [aPath copy];
64 | _lockQueue = dispatch_queue_create([[NSString stringWithFormat:@"fmdb.%@", self] UTF8String], NULL);
65 | _databaseInPool = FMDBReturnRetained([NSMutableArray array]);
66 | _databaseOutPool = FMDBReturnRetained([NSMutableArray array]);
67 | _openFlags = openFlags;
68 | _vfsName = [vfsName copy];
69 | }
70 |
71 | return self;
72 | }
73 |
74 | - (instancetype)initWithPath:(NSString *)aPath flags:(int)openFlags {
75 | return [self initWithPath:aPath flags:openFlags vfs:nil];
76 | }
77 |
78 | - (instancetype)initWithURL:(NSURL *)url flags:(int)openFlags {
79 | return [self initWithPath:url.path flags:openFlags vfs:nil];
80 | }
81 |
82 | - (instancetype)initWithPath:(NSString*)aPath {
83 | // default flags for sqlite3_open
84 | return [self initWithPath:aPath flags:SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE];
85 | }
86 |
87 | - (instancetype)initWithURL:(NSURL *)url {
88 | return [self initWithPath:url.path];
89 | }
90 |
91 | - (instancetype)init {
92 | return [self initWithPath:nil];
93 | }
94 |
95 | + (Class)databaseClass {
96 | return [FMDatabase class];
97 | }
98 |
99 | - (void)dealloc {
100 |
101 | _delegate = 0x00;
102 | FMDBRelease(_path);
103 | FMDBRelease(_databaseInPool);
104 | FMDBRelease(_databaseOutPool);
105 | FMDBRelease(_vfsName);
106 |
107 | if (_lockQueue) {
108 | FMDBDispatchQueueRelease(_lockQueue);
109 | _lockQueue = 0x00;
110 | }
111 | #if ! __has_feature(objc_arc)
112 | [super dealloc];
113 | #endif
114 | }
115 |
116 |
117 | - (void)executeLocked:(void (^)(void))aBlock {
118 | dispatch_sync(_lockQueue, aBlock);
119 | }
120 |
121 | - (void)pushDatabaseBackInPool:(FMDatabase*)db {
122 |
123 | if (!db) { // db can be null if we set an upper bound on the # of databases to create.
124 | return;
125 | }
126 |
127 | [self executeLocked:^() {
128 |
129 | if ([self->_databaseInPool containsObject:db]) {
130 | [[NSException exceptionWithName:@"Database already in pool" reason:@"The FMDatabase being put back into the pool is already present in the pool" userInfo:nil] raise];
131 | }
132 |
133 | [self->_databaseInPool addObject:db];
134 | [self->_databaseOutPool removeObject:db];
135 |
136 | }];
137 | }
138 |
139 | - (FMDatabase*)db {
140 |
141 | __block FMDatabase *db;
142 |
143 |
144 | [self executeLocked:^() {
145 | db = [self->_databaseInPool lastObject];
146 |
147 | BOOL shouldNotifyDelegate = NO;
148 |
149 | if (db) {
150 | [self->_databaseOutPool addObject:db];
151 | [self->_databaseInPool removeLastObject];
152 | }
153 | else {
154 |
155 | if (self->_maximumNumberOfDatabasesToCreate) {
156 | NSUInteger currentCount = [self->_databaseOutPool count] + [self->_databaseInPool count];
157 |
158 | if (currentCount >= self->_maximumNumberOfDatabasesToCreate) {
159 | NSLog(@"Maximum number of databases (%ld) has already been reached!", (long)currentCount);
160 | return;
161 | }
162 | }
163 |
164 | db = [[[self class] databaseClass] databaseWithPath:self->_path];
165 | shouldNotifyDelegate = YES;
166 | }
167 |
168 | //This ensures that the db is opened before returning
169 | #if SQLITE_VERSION_NUMBER >= 3005000
170 | BOOL success = [db openWithFlags:self->_openFlags vfs:self->_vfsName];
171 | #else
172 | BOOL success = [db open];
173 | #endif
174 | if (success) {
175 | if ([self->_delegate respondsToSelector:@selector(databasePool:shouldAddDatabaseToPool:)] && ![self->_delegate databasePool:self shouldAddDatabaseToPool:db]) {
176 | [db close];
177 | db = 0x00;
178 | }
179 | else {
180 | //It should not get added in the pool twice if lastObject was found
181 | if (![self->_databaseOutPool containsObject:db]) {
182 | [self->_databaseOutPool addObject:db];
183 |
184 | if (shouldNotifyDelegate && [self->_delegate respondsToSelector:@selector(databasePool:didAddDatabase:)]) {
185 | [self->_delegate databasePool:self didAddDatabase:db];
186 | }
187 | }
188 | }
189 | }
190 | else {
191 | NSLog(@"Could not open up the database at path %@", self->_path);
192 | db = 0x00;
193 | }
194 | }];
195 |
196 | return db;
197 | }
198 |
199 | - (NSUInteger)countOfCheckedInDatabases {
200 |
201 | __block NSUInteger count;
202 |
203 | [self executeLocked:^() {
204 | count = [self->_databaseInPool count];
205 | }];
206 |
207 | return count;
208 | }
209 |
210 | - (NSUInteger)countOfCheckedOutDatabases {
211 |
212 | __block NSUInteger count;
213 |
214 | [self executeLocked:^() {
215 | count = [self->_databaseOutPool count];
216 | }];
217 |
218 | return count;
219 | }
220 |
221 | - (NSUInteger)countOfOpenDatabases {
222 | __block NSUInteger count;
223 |
224 | [self executeLocked:^() {
225 | count = [self->_databaseOutPool count] + [self->_databaseInPool count];
226 | }];
227 |
228 | return count;
229 | }
230 |
231 | - (void)releaseAllDatabases {
232 | [self executeLocked:^() {
233 | [self->_databaseOutPool removeAllObjects];
234 | [self->_databaseInPool removeAllObjects];
235 | }];
236 | }
237 |
238 | - (void)inDatabase:(void (^)(FMDatabase *db))block {
239 |
240 | FMDatabase *db = [self db];
241 |
242 | block(db);
243 |
244 | [self pushDatabaseBackInPool:db];
245 | }
246 |
247 | - (void)beginTransaction:(BOOL)useDeferred withBlock:(void (^)(FMDatabase *db, BOOL *rollback))block {
248 |
249 | BOOL shouldRollback = NO;
250 |
251 | FMDatabase *db = [self db];
252 |
253 | if (useDeferred) {
254 | [db beginDeferredTransaction];
255 | }
256 | else {
257 | [db beginTransaction];
258 | }
259 |
260 |
261 | block(db, &shouldRollback);
262 |
263 | if (shouldRollback) {
264 | [db rollback];
265 | }
266 | else {
267 | [db commit];
268 | }
269 |
270 | [self pushDatabaseBackInPool:db];
271 | }
272 |
273 | - (void)inDeferredTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block {
274 | [self beginTransaction:YES withBlock:block];
275 | }
276 |
277 | - (void)inTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block {
278 | [self beginTransaction:NO withBlock:block];
279 | }
280 |
281 | - (NSError*)inSavePoint:(void (^)(FMDatabase *db, BOOL *rollback))block {
282 | #if SQLITE_VERSION_NUMBER >= 3007000
283 | static unsigned long savePointIdx = 0;
284 |
285 | NSString *name = [NSString stringWithFormat:@"savePoint%ld", savePointIdx++];
286 |
287 | BOOL shouldRollback = NO;
288 |
289 | FMDatabase *db = [self db];
290 |
291 | NSError *err = 0x00;
292 |
293 | if (![db startSavePointWithName:name error:&err]) {
294 | [self pushDatabaseBackInPool:db];
295 | return err;
296 | }
297 |
298 | block(db, &shouldRollback);
299 |
300 | if (shouldRollback) {
301 | // We need to rollback and release this savepoint to remove it
302 | [db rollbackToSavePointWithName:name error:&err];
303 | }
304 | [db releaseSavePointWithName:name error:&err];
305 |
306 | [self pushDatabaseBackInPool:db];
307 |
308 | return err;
309 | #else
310 | NSString *errorMessage = NSLocalizedString(@"Save point functions require SQLite 3.7", nil);
311 | if (self.logsErrors) NSLog(@"%@", errorMessage);
312 | return [NSError errorWithDomain:@"FMDatabase" code:0 userInfo:@{NSLocalizedDescriptionKey : errorMessage}];
313 | #endif
314 | }
315 |
316 | @end
317 |
--------------------------------------------------------------------------------
/BGFMDB/libs/FMDB/FMDatabaseQueue.h:
--------------------------------------------------------------------------------
1 | //
2 | // FMDatabaseQueue.h
3 | // fmdb
4 | //
5 | // Created by August Mueller on 6/22/11.
6 | // Copyright 2011 Flying Meat Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 | @class FMDatabase;
14 |
15 | /** To perform queries and updates on multiple threads, you'll want to use `FMDatabaseQueue`.
16 |
17 | Using a single instance of `` from multiple threads at once is a bad idea. It has always been OK to make a `` object *per thread*. Just don't share a single instance across threads, and definitely not across multiple threads at the same time.
18 |
19 | Instead, use `FMDatabaseQueue`. Here's how to use it:
20 |
21 | First, make your queue.
22 |
23 | FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:aPath];
24 |
25 | Then use it like so:
26 |
27 | [queue inDatabase:^(FMDatabase *db) {
28 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:1]];
29 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:2]];
30 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:3]];
31 |
32 | FMResultSet *rs = [db executeQuery:@"select * from foo"];
33 | while ([rs next]) {
34 | //…
35 | }
36 | }];
37 |
38 | An easy way to wrap things up in a transaction can be done like this:
39 |
40 | [queue inTransaction:^(FMDatabase *db, BOOL *rollback) {
41 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:1]];
42 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:2]];
43 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:3]];
44 |
45 | if (whoopsSomethingWrongHappened) {
46 | *rollback = YES;
47 | return;
48 | }
49 | // etc…
50 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:4]];
51 | }];
52 |
53 | `FMDatabaseQueue` will run the blocks on a serialized queue (hence the name of the class). So if you call `FMDatabaseQueue`'s methods from multiple threads at the same time, they will be executed in the order they are received. This way queries and updates won't step on each other's toes, and every one is happy.
54 |
55 | ### See also
56 |
57 | - ``
58 |
59 | @warning Do not instantiate a single `` object and use it across multiple threads. Use `FMDatabaseQueue` instead.
60 |
61 | @warning The calls to `FMDatabaseQueue`'s methods are blocking. So even though you are passing along blocks, they will **not** be run on another thread.
62 |
63 | */
64 |
65 | @interface FMDatabaseQueue : NSObject
66 | /** Path of database */
67 |
68 | @property (atomic, retain, nullable) NSString *path;
69 |
70 | /** Open flags */
71 |
72 | @property (atomic, readonly) int openFlags;
73 |
74 | /** Custom virtual file system name */
75 |
76 | @property (atomic, copy, nullable) NSString *vfsName;
77 |
78 | ///----------------------------------------------------
79 | /// @name Initialization, opening, and closing of queue
80 | ///----------------------------------------------------
81 |
82 | /** Create queue using path.
83 |
84 | @param aPath The file path of the database.
85 |
86 | @return The `FMDatabaseQueue` object. `nil` on error.
87 | */
88 |
89 | + (instancetype)databaseQueueWithPath:(NSString * _Nullable)aPath;
90 |
91 | /** Create queue using file URL.
92 |
93 | @param url The file `NSURL` of the database.
94 |
95 | @return The `FMDatabaseQueue` object. `nil` on error.
96 | */
97 |
98 | + (instancetype)databaseQueueWithURL:(NSURL * _Nullable)url;
99 |
100 | /** Create queue using path and specified flags.
101 |
102 | @param aPath The file path of the database.
103 | @param openFlags Flags passed to the openWithFlags method of the database.
104 |
105 | @return The `FMDatabaseQueue` object. `nil` on error.
106 | */
107 | + (instancetype)databaseQueueWithPath:(NSString * _Nullable)aPath flags:(int)openFlags;
108 |
109 | /** Create queue using file URL and specified flags.
110 |
111 | @param url The file `NSURL` of the database.
112 | @param openFlags Flags passed to the openWithFlags method of the database.
113 |
114 | @return The `FMDatabaseQueue` object. `nil` on error.
115 | */
116 | + (instancetype)databaseQueueWithURL:(NSURL * _Nullable)url flags:(int)openFlags;
117 |
118 | /** Create queue using path.
119 |
120 | @param aPath The file path of the database.
121 |
122 | @return The `FMDatabaseQueue` object. `nil` on error.
123 | */
124 |
125 | - (instancetype)initWithPath:(NSString * _Nullable)aPath;
126 |
127 | /** Create queue using file URL.
128 |
129 | @param url The file `NSURL of the database.
130 |
131 | @return The `FMDatabaseQueue` object. `nil` on error.
132 | */
133 |
134 | - (instancetype)initWithURL:(NSURL * _Nullable)url;
135 |
136 | /** Create queue using path and specified flags.
137 |
138 | @param aPath The file path of the database.
139 | @param openFlags Flags passed to the openWithFlags method of the database.
140 |
141 | @return The `FMDatabaseQueue` object. `nil` on error.
142 | */
143 |
144 | - (instancetype)initWithPath:(NSString * _Nullable)aPath flags:(int)openFlags;
145 |
146 | /** Create queue using file URL and specified flags.
147 |
148 | @param url The file path of the database.
149 | @param openFlags Flags passed to the openWithFlags method of the database.
150 |
151 | @return The `FMDatabaseQueue` object. `nil` on error.
152 | */
153 |
154 | - (instancetype)initWithURL:(NSURL * _Nullable)url flags:(int)openFlags;
155 |
156 | /** Create queue using path and specified flags.
157 |
158 | @param aPath The file path of the database.
159 | @param openFlags Flags passed to the openWithFlags method of the database
160 | @param vfsName The name of a custom virtual file system
161 |
162 | @return The `FMDatabaseQueue` object. `nil` on error.
163 | */
164 |
165 | - (instancetype)initWithPath:(NSString * _Nullable)aPath flags:(int)openFlags vfs:(NSString * _Nullable)vfsName;
166 |
167 | /** Create queue using file URL and specified flags.
168 |
169 | @param url The file `NSURL of the database.
170 | @param openFlags Flags passed to the openWithFlags method of the database
171 | @param vfsName The name of a custom virtual file system
172 |
173 | @return The `FMDatabaseQueue` object. `nil` on error.
174 | */
175 |
176 | - (instancetype)initWithURL:(NSURL * _Nullable)url flags:(int)openFlags vfs:(NSString * _Nullable)vfsName;
177 |
178 | /** Returns the Class of 'FMDatabase' subclass, that will be used to instantiate database object.
179 |
180 | Subclasses can override this method to return specified Class of 'FMDatabase' subclass.
181 |
182 | @return The Class of 'FMDatabase' subclass, that will be used to instantiate database object.
183 | */
184 |
185 | + (Class)databaseClass;
186 |
187 | /** Close database used by queue. */
188 |
189 | - (void)close;
190 |
191 | /** Interupt pending database operation. */
192 |
193 | - (void)interrupt;
194 |
195 | ///-----------------------------------------------
196 | /// @name Dispatching database operations to queue
197 | ///-----------------------------------------------
198 |
199 | /** Synchronously perform database operations on queue.
200 |
201 | @param block The code to be run on the queue of `FMDatabaseQueue`
202 | */
203 |
204 | - (void)inDatabase:(__attribute__((noescape)) void (^)(FMDatabase *db))block;
205 |
206 | /** Synchronously perform database operations on queue, using transactions.
207 |
208 | @param block The code to be run on the queue of `FMDatabaseQueue`
209 | */
210 |
211 | - (void)inTransaction:(__attribute__((noescape)) void (^)(FMDatabase *db, BOOL *rollback))block;
212 |
213 | /** Synchronously perform database operations on queue, using deferred transactions.
214 |
215 | @param block The code to be run on the queue of `FMDatabaseQueue`
216 | */
217 |
218 | - (void)inDeferredTransaction:(__attribute__((noescape)) void (^)(FMDatabase *db, BOOL *rollback))block;
219 |
220 | ///-----------------------------------------------
221 | /// @name Dispatching database operations to queue
222 | ///-----------------------------------------------
223 |
224 | /** Synchronously perform database operations using save point.
225 |
226 | @param block The code to be run on the queue of `FMDatabaseQueue`
227 | */
228 |
229 | // NOTE: you can not nest these, since calling it will pull another database out of the pool and you'll get a deadlock.
230 | // If you need to nest, use FMDatabase's startSavePointWithName:error: instead.
231 | - (NSError * _Nullable)inSavePoint:(__attribute__((noescape)) void (^)(FMDatabase *db, BOOL *rollback))block;
232 |
233 | @end
234 |
235 | NS_ASSUME_NONNULL_END
236 |
--------------------------------------------------------------------------------
/BGFMDB/libs/FMDB/FMDatabaseQueue.m:
--------------------------------------------------------------------------------
1 | //
2 | // FMDatabaseQueue.m
3 | // fmdb
4 | //
5 | // Created by August Mueller on 6/22/11.
6 | // Copyright 2011 Flying Meat Inc. All rights reserved.
7 | //
8 |
9 | #import "FMDatabaseQueue.h"
10 | #import "FMDatabase.h"
11 |
12 | #if FMDB_SQLITE_STANDALONE
13 | #import
14 | #else
15 | #import
16 | #endif
17 |
18 | /*
19 |
20 | Note: we call [self retain]; before using dispatch_sync, just incase
21 | FMDatabaseQueue is released on another thread and we're in the middle of doing
22 | something in dispatch_sync
23 |
24 | */
25 |
26 | /*
27 | * A key used to associate the FMDatabaseQueue object with the dispatch_queue_t it uses.
28 | * This in turn is used for deadlock detection by seeing if inDatabase: is called on
29 | * the queue's dispatch queue, which should not happen and causes a deadlock.
30 | */
31 | static const void * const kDispatchQueueSpecificKey = &kDispatchQueueSpecificKey;
32 |
33 | @interface FMDatabaseQueue () {
34 | dispatch_queue_t _queue;
35 | FMDatabase *_db;
36 | }
37 | @end
38 |
39 | @implementation FMDatabaseQueue
40 |
41 | + (instancetype)databaseQueueWithPath:(NSString *)aPath {
42 | FMDatabaseQueue *q = [[self alloc] initWithPath:aPath];
43 |
44 | FMDBAutorelease(q);
45 |
46 | return q;
47 | }
48 |
49 | + (instancetype)databaseQueueWithURL:(NSURL *)url {
50 | return [self databaseQueueWithPath:url.path];
51 | }
52 |
53 | + (instancetype)databaseQueueWithPath:(NSString *)aPath flags:(int)openFlags {
54 | FMDatabaseQueue *q = [[self alloc] initWithPath:aPath flags:openFlags];
55 |
56 | FMDBAutorelease(q);
57 |
58 | return q;
59 | }
60 |
61 | + (instancetype)databaseQueueWithURL:(NSURL *)url flags:(int)openFlags {
62 | return [self databaseQueueWithPath:url.path flags:openFlags];
63 | }
64 |
65 | + (Class)databaseClass {
66 | return [FMDatabase class];
67 | }
68 |
69 | - (instancetype)initWithURL:(NSURL *)url flags:(int)openFlags vfs:(NSString *)vfsName {
70 | return [self initWithPath:url.path flags:openFlags vfs:vfsName];
71 | }
72 |
73 | - (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags vfs:(NSString *)vfsName {
74 | self = [super init];
75 |
76 | if (self != nil) {
77 |
78 | _db = [[[self class] databaseClass] databaseWithPath:aPath];
79 | FMDBRetain(_db);
80 |
81 | #if SQLITE_VERSION_NUMBER >= 3005000
82 | BOOL success = [_db openWithFlags:openFlags vfs:vfsName];
83 | #else
84 | BOOL success = [_db open];
85 | #endif
86 | if (!success) {
87 | NSLog(@"Could not create database queue for path %@", aPath);
88 | FMDBRelease(self);
89 | return 0x00;
90 | }
91 |
92 | _path = FMDBReturnRetained(aPath);
93 |
94 | _queue = dispatch_queue_create([[NSString stringWithFormat:@"fmdb.%@", self] UTF8String], NULL);
95 | dispatch_queue_set_specific(_queue, kDispatchQueueSpecificKey, (__bridge void *)self, NULL);
96 | _openFlags = openFlags;
97 | _vfsName = [vfsName copy];
98 | }
99 |
100 | return self;
101 | }
102 |
103 | - (instancetype)initWithPath:(NSString *)aPath flags:(int)openFlags {
104 | return [self initWithPath:aPath flags:openFlags vfs:nil];
105 | }
106 |
107 | - (instancetype)initWithURL:(NSURL *)url flags:(int)openFlags {
108 | return [self initWithPath:url.path flags:openFlags vfs:nil];
109 | }
110 |
111 | - (instancetype)initWithURL:(NSURL *)url {
112 | return [self initWithPath:url.path];
113 | }
114 |
115 | - (instancetype)initWithPath:(NSString *)aPath {
116 | // default flags for sqlite3_open
117 | return [self initWithPath:aPath flags:SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE vfs:nil];
118 | }
119 |
120 | - (instancetype)init {
121 | return [self initWithPath:nil];
122 | }
123 |
124 |
125 | - (void)dealloc {
126 | FMDBRelease(_db);
127 | FMDBRelease(_path);
128 | FMDBRelease(_vfsName);
129 |
130 | if (_queue) {
131 | FMDBDispatchQueueRelease(_queue);
132 | _queue = 0x00;
133 | }
134 | #if ! __has_feature(objc_arc)
135 | [super dealloc];
136 | #endif
137 | }
138 |
139 | - (void)close {
140 | FMDBRetain(self);
141 | dispatch_sync(_queue, ^() {
142 | [self->_db close];
143 | FMDBRelease(_db);
144 | self->_db = 0x00;
145 | });
146 | FMDBRelease(self);
147 | }
148 |
149 | - (void)interrupt {
150 | [[self database] interrupt];
151 | }
152 |
153 | - (FMDatabase*)database {
154 | if (!_db) {
155 | _db = FMDBReturnRetained([[[self class] databaseClass] databaseWithPath:_path]);
156 |
157 | #if SQLITE_VERSION_NUMBER >= 3005000
158 | BOOL success = [_db openWithFlags:_openFlags vfs:_vfsName];
159 | #else
160 | BOOL success = [_db open];
161 | #endif
162 | if (!success) {
163 | NSLog(@"FMDatabaseQueue could not reopen database for path %@", _path);
164 | FMDBRelease(_db);
165 | _db = 0x00;
166 | return 0x00;
167 | }
168 | }
169 |
170 | return _db;
171 | }
172 |
173 | - (void)inDatabase:(void (^)(FMDatabase *db))block {
174 | #ifndef NDEBUG
175 | /* Get the currently executing queue (which should probably be nil, but in theory could be another DB queue
176 | * and then check it against self to make sure we're not about to deadlock. */
177 | FMDatabaseQueue *currentSyncQueue = (__bridge id)dispatch_get_specific(kDispatchQueueSpecificKey);
178 | assert(currentSyncQueue != self && "inDatabase: was called reentrantly on the same queue, which would lead to a deadlock");
179 | #endif
180 |
181 | FMDBRetain(self);
182 |
183 | dispatch_sync(_queue, ^() {
184 |
185 | FMDatabase *db = [self database];
186 | block(db);
187 |
188 | if ([db hasOpenResultSets]) {
189 | NSLog(@"Warning: there is at least one open result set around after performing [FMDatabaseQueue inDatabase:]");
190 |
191 | #if defined(DEBUG) && DEBUG
192 | NSSet *openSetCopy = FMDBReturnAutoreleased([[db valueForKey:@"_openResultSets"] copy]);
193 | for (NSValue *rsInWrappedInATastyValueMeal in openSetCopy) {
194 | FMResultSet *rs = (FMResultSet *)[rsInWrappedInATastyValueMeal pointerValue];
195 | NSLog(@"query: '%@'", [rs query]);
196 | }
197 | #endif
198 | }
199 | });
200 |
201 | FMDBRelease(self);
202 | }
203 |
204 | - (void)beginTransaction:(BOOL)useDeferred withBlock:(void (^)(FMDatabase *db, BOOL *rollback))block {
205 | FMDBRetain(self);
206 | dispatch_sync(_queue, ^() {
207 |
208 | BOOL shouldRollback = NO;
209 |
210 | if (useDeferred) {
211 | [[self database] beginDeferredTransaction];
212 | }
213 | else {
214 | [[self database] beginTransaction];
215 | }
216 |
217 | block([self database], &shouldRollback);
218 |
219 | if (shouldRollback) {
220 | [[self database] rollback];
221 | }
222 | else {
223 | [[self database] commit];
224 | }
225 | });
226 |
227 | FMDBRelease(self);
228 | }
229 |
230 | - (void)inDeferredTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block {
231 | [self beginTransaction:YES withBlock:block];
232 | }
233 |
234 | - (void)inTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block {
235 | [self beginTransaction:NO withBlock:block];
236 | }
237 |
238 | - (NSError*)inSavePoint:(void (^)(FMDatabase *db, BOOL *rollback))block {
239 | #if SQLITE_VERSION_NUMBER >= 3007000
240 | static unsigned long savePointIdx = 0;
241 | __block NSError *err = 0x00;
242 | FMDBRetain(self);
243 | dispatch_sync(_queue, ^() {
244 |
245 | NSString *name = [NSString stringWithFormat:@"savePoint%ld", savePointIdx++];
246 |
247 | BOOL shouldRollback = NO;
248 |
249 | if ([[self database] startSavePointWithName:name error:&err]) {
250 |
251 | block([self database], &shouldRollback);
252 |
253 | if (shouldRollback) {
254 | // We need to rollback and release this savepoint to remove it
255 | [[self database] rollbackToSavePointWithName:name error:&err];
256 | }
257 | [[self database] releaseSavePointWithName:name error:&err];
258 |
259 | }
260 | });
261 | FMDBRelease(self);
262 | return err;
263 | #else
264 | NSString *errorMessage = NSLocalizedString(@"Save point functions require SQLite 3.7", nil);
265 | if (self.logsErrors) NSLog(@"%@", errorMessage);
266 | return [NSError errorWithDomain:@"FMDatabase" code:0 userInfo:@{NSLocalizedDescriptionKey : errorMessage}];
267 | #endif
268 | }
269 |
270 | @end
271 |
--------------------------------------------------------------------------------
/BGFMDB/libs/FMDB/FMResultSet.h:
--------------------------------------------------------------------------------
1 | #import
2 |
3 | NS_ASSUME_NONNULL_BEGIN
4 |
5 | #ifndef __has_feature // Optional.
6 | #define __has_feature(x) 0 // Compatibility with non-clang compilers.
7 | #endif
8 |
9 | #ifndef NS_RETURNS_NOT_RETAINED
10 | #if __has_feature(attribute_ns_returns_not_retained)
11 | #define NS_RETURNS_NOT_RETAINED __attribute__((ns_returns_not_retained))
12 | #else
13 | #define NS_RETURNS_NOT_RETAINED
14 | #endif
15 | #endif
16 |
17 | @class FMDatabase;
18 | @class FMStatement;
19 |
20 | /** Represents the results of executing a query on an ``.
21 |
22 | ### See also
23 |
24 | - ``
25 | */
26 |
27 | @interface FMResultSet : NSObject
28 |
29 | @property (nonatomic, retain, nullable) FMDatabase *parentDB;
30 |
31 | ///-----------------
32 | /// @name Properties
33 | ///-----------------
34 |
35 | /** Executed query */
36 |
37 | @property (atomic, retain, nullable) NSString *query;
38 |
39 | /** `NSMutableDictionary` mapping column names to numeric index */
40 |
41 | @property (readonly) NSMutableDictionary *columnNameToIndexMap;
42 |
43 | /** `FMStatement` used by result set. */
44 |
45 | @property (atomic, retain, nullable) FMStatement *statement;
46 |
47 | ///------------------------------------
48 | /// @name Creating and closing database
49 | ///------------------------------------
50 |
51 | /** Create result set from ``
52 |
53 | @param statement A `` to be performed
54 |
55 | @param aDB A `` to be used
56 |
57 | @return A `FMResultSet` on success; `nil` on failure
58 | */
59 |
60 | + (instancetype)resultSetWithStatement:(FMStatement *)statement usingParentDatabase:(FMDatabase*)aDB;
61 |
62 | /** Close result set */
63 |
64 | - (void)close;
65 |
66 | ///---------------------------------------
67 | /// @name Iterating through the result set
68 | ///---------------------------------------
69 |
70 | /** Retrieve next row for result set.
71 |
72 | You must always invoke `next` or `nextWithError` before attempting to access the values returned in a query, even if you're only expecting one.
73 |
74 | @return `YES` if row successfully retrieved; `NO` if end of result set reached
75 |
76 | @see hasAnotherRow
77 | */
78 |
79 | - (BOOL)next;
80 |
81 | /** Retrieve next row for result set.
82 |
83 | You must always invoke `next` or `nextWithError` before attempting to access the values returned in a query, even if you're only expecting one.
84 |
85 | @param outErr A 'NSError' object to receive any error object (if any).
86 |
87 | @return 'YES' if row successfully retrieved; 'NO' if end of result set reached
88 |
89 | @see hasAnotherRow
90 | */
91 |
92 | - (BOOL)nextWithError:(NSError * _Nullable *)outErr;
93 |
94 | /** Did the last call to `` succeed in retrieving another row?
95 |
96 | @return `YES` if the last call to `` succeeded in retrieving another record; `NO` if not.
97 |
98 | @see next
99 |
100 | @warning The `hasAnotherRow` method must follow a call to ``. If the previous database interaction was something other than a call to `next`, then this method may return `NO`, whether there is another row of data or not.
101 | */
102 |
103 | - (BOOL)hasAnotherRow;
104 |
105 | ///---------------------------------------------
106 | /// @name Retrieving information from result set
107 | ///---------------------------------------------
108 |
109 | /** How many columns in result set
110 |
111 | @return Integer value of the number of columns.
112 | */
113 |
114 | @property (nonatomic, readonly) int columnCount;
115 |
116 | /** Column index for column name
117 |
118 | @param columnName `NSString` value of the name of the column.
119 |
120 | @return Zero-based index for column.
121 | */
122 |
123 | - (int)columnIndexForName:(NSString*)columnName;
124 |
125 | /** Column name for column index
126 |
127 | @param columnIdx Zero-based index for column.
128 |
129 | @return columnName `NSString` value of the name of the column.
130 | */
131 |
132 | - (NSString * _Nullable)columnNameForIndex:(int)columnIdx;
133 |
134 | /** Result set integer value for column.
135 |
136 | @param columnName `NSString` value of the name of the column.
137 |
138 | @return `int` value of the result set's column.
139 | */
140 |
141 | - (int)intForColumn:(NSString*)columnName;
142 |
143 | /** Result set integer value for column.
144 |
145 | @param columnIdx Zero-based index for column.
146 |
147 | @return `int` value of the result set's column.
148 | */
149 |
150 | - (int)intForColumnIndex:(int)columnIdx;
151 |
152 | /** Result set `long` value for column.
153 |
154 | @param columnName `NSString` value of the name of the column.
155 |
156 | @return `long` value of the result set's column.
157 | */
158 |
159 | - (long)longForColumn:(NSString*)columnName;
160 |
161 | /** Result set long value for column.
162 |
163 | @param columnIdx Zero-based index for column.
164 |
165 | @return `long` value of the result set's column.
166 | */
167 |
168 | - (long)longForColumnIndex:(int)columnIdx;
169 |
170 | /** Result set `long long int` value for column.
171 |
172 | @param columnName `NSString` value of the name of the column.
173 |
174 | @return `long long int` value of the result set's column.
175 | */
176 |
177 | - (long long int)longLongIntForColumn:(NSString*)columnName;
178 |
179 | /** Result set `long long int` value for column.
180 |
181 | @param columnIdx Zero-based index for column.
182 |
183 | @return `long long int` value of the result set's column.
184 | */
185 |
186 | - (long long int)longLongIntForColumnIndex:(int)columnIdx;
187 |
188 | /** Result set `unsigned long long int` value for column.
189 |
190 | @param columnName `NSString` value of the name of the column.
191 |
192 | @return `unsigned long long int` value of the result set's column.
193 | */
194 |
195 | - (unsigned long long int)unsignedLongLongIntForColumn:(NSString*)columnName;
196 |
197 | /** Result set `unsigned long long int` value for column.
198 |
199 | @param columnIdx Zero-based index for column.
200 |
201 | @return `unsigned long long int` value of the result set's column.
202 | */
203 |
204 | - (unsigned long long int)unsignedLongLongIntForColumnIndex:(int)columnIdx;
205 |
206 | /** Result set `BOOL` value for column.
207 |
208 | @param columnName `NSString` value of the name of the column.
209 |
210 | @return `BOOL` value of the result set's column.
211 | */
212 |
213 | - (BOOL)boolForColumn:(NSString*)columnName;
214 |
215 | /** Result set `BOOL` value for column.
216 |
217 | @param columnIdx Zero-based index for column.
218 |
219 | @return `BOOL` value of the result set's column.
220 | */
221 |
222 | - (BOOL)boolForColumnIndex:(int)columnIdx;
223 |
224 | /** Result set `double` value for column.
225 |
226 | @param columnName `NSString` value of the name of the column.
227 |
228 | @return `double` value of the result set's column.
229 |
230 | */
231 |
232 | - (double)doubleForColumn:(NSString*)columnName;
233 |
234 | /** Result set `double` value for column.
235 |
236 | @param columnIdx Zero-based index for column.
237 |
238 | @return `double` value of the result set's column.
239 |
240 | */
241 |
242 | - (double)doubleForColumnIndex:(int)columnIdx;
243 |
244 | /** Result set `NSString` value for column.
245 |
246 | @param columnName `NSString` value of the name of the column.
247 |
248 | @return String value of the result set's column.
249 |
250 | */
251 |
252 | - (NSString * _Nullable)stringForColumn:(NSString*)columnName;
253 |
254 | /** Result set `NSString` value for column.
255 |
256 | @param columnIdx Zero-based index for column.
257 |
258 | @return String value of the result set's column.
259 | */
260 |
261 | - (NSString * _Nullable)stringForColumnIndex:(int)columnIdx;
262 |
263 | /** Result set `NSDate` value for column.
264 |
265 | @param columnName `NSString` value of the name of the column.
266 |
267 | @return Date value of the result set's column.
268 | */
269 |
270 | - (NSDate * _Nullable)dateForColumn:(NSString*)columnName;
271 |
272 | /** Result set `NSDate` value for column.
273 |
274 | @param columnIdx Zero-based index for column.
275 |
276 | @return Date value of the result set's column.
277 |
278 | */
279 |
280 | - (NSDate * _Nullable)dateForColumnIndex:(int)columnIdx;
281 |
282 | /** Result set `NSData` value for column.
283 |
284 | This is useful when storing binary data in table (such as image or the like).
285 |
286 | @param columnName `NSString` value of the name of the column.
287 |
288 | @return Data value of the result set's column.
289 |
290 | */
291 |
292 | - (NSData * _Nullable)dataForColumn:(NSString*)columnName;
293 |
294 | /** Result set `NSData` value for column.
295 |
296 | @param columnIdx Zero-based index for column.
297 |
298 | @return Data value of the result set's column.
299 | */
300 |
301 | - (NSData * _Nullable)dataForColumnIndex:(int)columnIdx;
302 |
303 | /** Result set `(const unsigned char *)` value for column.
304 |
305 | @param columnName `NSString` value of the name of the column.
306 |
307 | @return `(const unsigned char *)` value of the result set's column.
308 | */
309 |
310 | - (const unsigned char * _Nullable)UTF8StringForColumn:(NSString*)columnName;
311 |
312 | - (const unsigned char * _Nullable)UTF8StringForColumnName:(NSString*)columnName __deprecated_msg("Use UTF8StringForColumn instead");
313 |
314 | /** Result set `(const unsigned char *)` value for column.
315 |
316 | @param columnIdx Zero-based index for column.
317 |
318 | @return `(const unsigned char *)` value of the result set's column.
319 | */
320 |
321 | - (const unsigned char * _Nullable)UTF8StringForColumnIndex:(int)columnIdx;
322 |
323 | /** Result set object for column.
324 |
325 | @param columnName Name of the column.
326 |
327 | @return Either `NSNumber`, `NSString`, `NSData`, or `NSNull`. If the column was `NULL`, this returns `[NSNull null]` object.
328 |
329 | @see objectForKeyedSubscript:
330 | */
331 |
332 | - (id _Nullable)objectForColumn:(NSString*)columnName;
333 |
334 | - (id _Nullable)objectForColumnName:(NSString*)columnName __deprecated_msg("Use objectForColumn instead");
335 |
336 | /** Result set object for column.
337 |
338 | @param columnIdx Zero-based index for column.
339 |
340 | @return Either `NSNumber`, `NSString`, `NSData`, or `NSNull`. If the column was `NULL`, this returns `[NSNull null]` object.
341 |
342 | @see objectAtIndexedSubscript:
343 | */
344 |
345 | - (id _Nullable)objectForColumnIndex:(int)columnIdx;
346 |
347 | /** Result set object for column.
348 |
349 | This method allows the use of the "boxed" syntax supported in Modern Objective-C. For example, by defining this method, the following syntax is now supported:
350 |
351 | id result = rs[@"employee_name"];
352 |
353 | This simplified syntax is equivalent to calling:
354 |
355 | id result = [rs objectForKeyedSubscript:@"employee_name"];
356 |
357 | which is, it turns out, equivalent to calling:
358 |
359 | id result = [rs objectForColumnName:@"employee_name"];
360 |
361 | @param columnName `NSString` value of the name of the column.
362 |
363 | @return Either `NSNumber`, `NSString`, `NSData`, or `NSNull`. If the column was `NULL`, this returns `[NSNull null]` object.
364 | */
365 |
366 | - (id _Nullable)objectForKeyedSubscript:(NSString *)columnName;
367 |
368 | /** Result set object for column.
369 |
370 | This method allows the use of the "boxed" syntax supported in Modern Objective-C. For example, by defining this method, the following syntax is now supported:
371 |
372 | id result = rs[0];
373 |
374 | This simplified syntax is equivalent to calling:
375 |
376 | id result = [rs objectForKeyedSubscript:0];
377 |
378 | which is, it turns out, equivalent to calling:
379 |
380 | id result = [rs objectForColumnName:0];
381 |
382 | @param columnIdx Zero-based index for column.
383 |
384 | @return Either `NSNumber`, `NSString`, `NSData`, or `NSNull`. If the column was `NULL`, this returns `[NSNull null]` object.
385 | */
386 |
387 | - (id _Nullable)objectAtIndexedSubscript:(int)columnIdx;
388 |
389 | /** Result set `NSData` value for column.
390 |
391 | @param columnName `NSString` value of the name of the column.
392 |
393 | @return Data value of the result set's column.
394 |
395 | @warning If you are going to use this data after you iterate over the next row, or after you close the
396 | result set, make sure to make a copy of the data first (or just use ``/``)
397 | If you don't, you're going to be in a world of hurt when you try and use the data.
398 |
399 | */
400 |
401 | - (NSData * _Nullable)dataNoCopyForColumn:(NSString *)columnName NS_RETURNS_NOT_RETAINED;
402 |
403 | /** Result set `NSData` value for column.
404 |
405 | @param columnIdx Zero-based index for column.
406 |
407 | @return Data value of the result set's column.
408 |
409 | @warning If you are going to use this data after you iterate over the next row, or after you close the
410 | result set, make sure to make a copy of the data first (or just use ``/``)
411 | If you don't, you're going to be in a world of hurt when you try and use the data.
412 |
413 | */
414 |
415 | - (NSData * _Nullable)dataNoCopyForColumnIndex:(int)columnIdx NS_RETURNS_NOT_RETAINED;
416 |
417 | /** Is the column `NULL`?
418 |
419 | @param columnIdx Zero-based index for column.
420 |
421 | @return `YES` if column is `NULL`; `NO` if not `NULL`.
422 | */
423 |
424 | - (BOOL)columnIndexIsNull:(int)columnIdx;
425 |
426 | /** Is the column `NULL`?
427 |
428 | @param columnName `NSString` value of the name of the column.
429 |
430 | @return `YES` if column is `NULL`; `NO` if not `NULL`.
431 | */
432 |
433 | - (BOOL)columnIsNull:(NSString*)columnName;
434 |
435 |
436 | /** Returns a dictionary of the row results mapped to case sensitive keys of the column names.
437 |
438 | @warning The keys to the dictionary are case sensitive of the column names.
439 | */
440 |
441 | @property (nonatomic, readonly, nullable) NSDictionary *resultDictionary;
442 |
443 | /** Returns a dictionary of the row results
444 |
445 | @see resultDictionary
446 |
447 | @warning **Deprecated**: Please use `` instead. Also, beware that `` is case sensitive!
448 | */
449 |
450 | - (NSDictionary * _Nullable)resultDict __deprecated_msg("Use resultDictionary instead");
451 |
452 | ///-----------------------------
453 | /// @name Key value coding magic
454 | ///-----------------------------
455 |
456 | /** Performs `setValue` to yield support for key value observing.
457 |
458 | @param object The object for which the values will be set. This is the key-value-coding compliant object that you might, for example, observe.
459 |
460 | */
461 |
462 | - (void)kvcMagic:(id)object;
463 |
464 |
465 | @end
466 |
467 | NS_ASSUME_NONNULL_END
468 |
--------------------------------------------------------------------------------
/BGFMDB/libs/FMDB/FMResultSet.m:
--------------------------------------------------------------------------------
1 | #import "FMResultSet.h"
2 | #import "FMDatabase.h"
3 | #import "unistd.h"
4 |
5 | #if FMDB_SQLITE_STANDALONE
6 | #import
7 | #else
8 | #import
9 | #endif
10 |
11 | @interface FMDatabase ()
12 | - (void)resultSetDidClose:(FMResultSet *)resultSet;
13 | @end
14 |
15 | @interface FMResultSet () {
16 | NSMutableDictionary *_columnNameToIndexMap;
17 | }
18 | @end
19 |
20 | @implementation FMResultSet
21 |
22 | + (instancetype)resultSetWithStatement:(FMStatement *)statement usingParentDatabase:(FMDatabase*)aDB {
23 |
24 | FMResultSet *rs = [[FMResultSet alloc] init];
25 |
26 | [rs setStatement:statement];
27 | [rs setParentDB:aDB];
28 |
29 | NSParameterAssert(![statement inUse]);
30 | [statement setInUse:YES]; // weak reference
31 |
32 | return FMDBReturnAutoreleased(rs);
33 | }
34 |
35 | #if ! __has_feature(objc_arc)
36 | - (void)finalize {
37 | [self close];
38 | [super finalize];
39 | }
40 | #endif
41 |
42 | - (void)dealloc {
43 | [self close];
44 |
45 | FMDBRelease(_query);
46 | _query = nil;
47 |
48 | FMDBRelease(_columnNameToIndexMap);
49 | _columnNameToIndexMap = nil;
50 |
51 | #if ! __has_feature(objc_arc)
52 | [super dealloc];
53 | #endif
54 | }
55 |
56 | - (void)close {
57 | [_statement reset];
58 | FMDBRelease(_statement);
59 | _statement = nil;
60 |
61 | // we don't need this anymore... (i think)
62 | //[_parentDB setInUse:NO];
63 | [_parentDB resultSetDidClose:self];
64 | _parentDB = nil;
65 | }
66 |
67 | - (int)columnCount {
68 | return sqlite3_column_count([_statement statement]);
69 | }
70 |
71 | - (NSMutableDictionary *)columnNameToIndexMap {
72 | if (!_columnNameToIndexMap) {
73 | int columnCount = sqlite3_column_count([_statement statement]);
74 | _columnNameToIndexMap = [[NSMutableDictionary alloc] initWithCapacity:(NSUInteger)columnCount];
75 | int columnIdx = 0;
76 | for (columnIdx = 0; columnIdx < columnCount; columnIdx++) {
77 | [_columnNameToIndexMap setObject:[NSNumber numberWithInt:columnIdx]
78 | forKey:[[NSString stringWithUTF8String:sqlite3_column_name([_statement statement], columnIdx)] lowercaseString]];
79 | }
80 | }
81 | return _columnNameToIndexMap;
82 | }
83 |
84 | - (void)kvcMagic:(id)object {
85 |
86 | int columnCount = sqlite3_column_count([_statement statement]);
87 |
88 | int columnIdx = 0;
89 | for (columnIdx = 0; columnIdx < columnCount; columnIdx++) {
90 |
91 | const char *c = (const char *)sqlite3_column_text([_statement statement], columnIdx);
92 |
93 | // check for a null row
94 | if (c) {
95 | NSString *s = [NSString stringWithUTF8String:c];
96 |
97 | [object setValue:s forKey:[NSString stringWithUTF8String:sqlite3_column_name([_statement statement], columnIdx)]];
98 | }
99 | }
100 | }
101 |
102 | #pragma clang diagnostic push
103 | #pragma clang diagnostic ignored "-Wdeprecated-implementations"
104 |
105 | - (NSDictionary *)resultDict {
106 |
107 | NSUInteger num_cols = (NSUInteger)sqlite3_data_count([_statement statement]);
108 |
109 | if (num_cols > 0) {
110 | NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:num_cols];
111 |
112 | NSEnumerator *columnNames = [[self columnNameToIndexMap] keyEnumerator];
113 | NSString *columnName = nil;
114 | while ((columnName = [columnNames nextObject])) {
115 | id objectValue = [self objectForColumnName:columnName];
116 | [dict setObject:objectValue forKey:columnName];
117 | }
118 |
119 | return FMDBReturnAutoreleased([dict copy]);
120 | }
121 | else {
122 | NSLog(@"Warning: There seem to be no columns in this set.");
123 | }
124 |
125 | return nil;
126 | }
127 |
128 | #pragma clang diagnostic pop
129 |
130 | - (NSDictionary*)resultDictionary {
131 |
132 | NSUInteger num_cols = (NSUInteger)sqlite3_data_count([_statement statement]);
133 |
134 | if (num_cols > 0) {
135 | NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:num_cols];
136 |
137 | int columnCount = sqlite3_column_count([_statement statement]);
138 |
139 | int columnIdx = 0;
140 | for (columnIdx = 0; columnIdx < columnCount; columnIdx++) {
141 |
142 | NSString *columnName = [NSString stringWithUTF8String:sqlite3_column_name([_statement statement], columnIdx)];
143 | id objectValue = [self objectForColumnIndex:columnIdx];
144 | [dict setObject:objectValue forKey:columnName];
145 | }
146 |
147 | return dict;
148 | }
149 | else {
150 | NSLog(@"Warning: There seem to be no columns in this set.");
151 | }
152 |
153 | return nil;
154 | }
155 |
156 |
157 |
158 |
159 | - (BOOL)next {
160 | return [self nextWithError:nil];
161 | }
162 |
163 | - (BOOL)nextWithError:(NSError **)outErr {
164 |
165 | int rc = sqlite3_step([_statement statement]);
166 |
167 | if (SQLITE_BUSY == rc || SQLITE_LOCKED == rc) {
168 | NSLog(@"%s:%d Database busy (%@)", __FUNCTION__, __LINE__, [_parentDB databasePath]);
169 | NSLog(@"Database busy");
170 | if (outErr) {
171 | *outErr = [_parentDB lastError];
172 | }
173 | }
174 | else if (SQLITE_DONE == rc || SQLITE_ROW == rc) {
175 | // all is well, let's return.
176 | }
177 | else if (SQLITE_ERROR == rc) {
178 | NSLog(@"Error calling sqlite3_step (%d: %s) rs", rc, sqlite3_errmsg([_parentDB sqliteHandle]));
179 | if (outErr) {
180 | *outErr = [_parentDB lastError];
181 | }
182 | }
183 | else if (SQLITE_MISUSE == rc) {
184 | // uh oh.
185 | NSLog(@"Error calling sqlite3_step (%d: %s) rs", rc, sqlite3_errmsg([_parentDB sqliteHandle]));
186 | if (outErr) {
187 | if (_parentDB) {
188 | *outErr = [_parentDB lastError];
189 | }
190 | else {
191 | // If 'next' or 'nextWithError' is called after the result set is closed,
192 | // we need to return the appropriate error.
193 | NSDictionary* errorMessage = [NSDictionary dictionaryWithObject:@"parentDB does not exist" forKey:NSLocalizedDescriptionKey];
194 | *outErr = [NSError errorWithDomain:@"FMDatabase" code:SQLITE_MISUSE userInfo:errorMessage];
195 | }
196 |
197 | }
198 | }
199 | else {
200 | // wtf?
201 | NSLog(@"Unknown error calling sqlite3_step (%d: %s) rs", rc, sqlite3_errmsg([_parentDB sqliteHandle]));
202 | if (outErr) {
203 | *outErr = [_parentDB lastError];
204 | }
205 | }
206 |
207 |
208 | if (rc != SQLITE_ROW) {
209 | [self close];
210 | }
211 |
212 | return (rc == SQLITE_ROW);
213 | }
214 |
215 | - (BOOL)hasAnotherRow {
216 | return sqlite3_errcode([_parentDB sqliteHandle]) == SQLITE_ROW;
217 | }
218 |
219 | - (int)columnIndexForName:(NSString*)columnName {
220 | columnName = [columnName lowercaseString];
221 |
222 | NSNumber *n = [[self columnNameToIndexMap] objectForKey:columnName];
223 |
224 | if (n != nil) {
225 | return [n intValue];
226 | }
227 |
228 | NSLog(@"Warning: I could not find the column named '%@'.", columnName);
229 |
230 | return -1;
231 | }
232 |
233 | - (int)intForColumn:(NSString*)columnName {
234 | return [self intForColumnIndex:[self columnIndexForName:columnName]];
235 | }
236 |
237 | - (int)intForColumnIndex:(int)columnIdx {
238 | return sqlite3_column_int([_statement statement], columnIdx);
239 | }
240 |
241 | - (long)longForColumn:(NSString*)columnName {
242 | return [self longForColumnIndex:[self columnIndexForName:columnName]];
243 | }
244 |
245 | - (long)longForColumnIndex:(int)columnIdx {
246 | return (long)sqlite3_column_int64([_statement statement], columnIdx);
247 | }
248 |
249 | - (long long int)longLongIntForColumn:(NSString*)columnName {
250 | return [self longLongIntForColumnIndex:[self columnIndexForName:columnName]];
251 | }
252 |
253 | - (long long int)longLongIntForColumnIndex:(int)columnIdx {
254 | return sqlite3_column_int64([_statement statement], columnIdx);
255 | }
256 |
257 | - (unsigned long long int)unsignedLongLongIntForColumn:(NSString*)columnName {
258 | return [self unsignedLongLongIntForColumnIndex:[self columnIndexForName:columnName]];
259 | }
260 |
261 | - (unsigned long long int)unsignedLongLongIntForColumnIndex:(int)columnIdx {
262 | return (unsigned long long int)[self longLongIntForColumnIndex:columnIdx];
263 | }
264 |
265 | - (BOOL)boolForColumn:(NSString*)columnName {
266 | return [self boolForColumnIndex:[self columnIndexForName:columnName]];
267 | }
268 |
269 | - (BOOL)boolForColumnIndex:(int)columnIdx {
270 | return ([self intForColumnIndex:columnIdx] != 0);
271 | }
272 |
273 | - (double)doubleForColumn:(NSString*)columnName {
274 | return [self doubleForColumnIndex:[self columnIndexForName:columnName]];
275 | }
276 |
277 | - (double)doubleForColumnIndex:(int)columnIdx {
278 | return sqlite3_column_double([_statement statement], columnIdx);
279 | }
280 |
281 | - (NSString *)stringForColumnIndex:(int)columnIdx {
282 |
283 | if (sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL || (columnIdx < 0) || columnIdx >= sqlite3_column_count([_statement statement])) {
284 | return nil;
285 | }
286 |
287 | const char *c = (const char *)sqlite3_column_text([_statement statement], columnIdx);
288 |
289 | if (!c) {
290 | // null row.
291 | return nil;
292 | }
293 |
294 | return [NSString stringWithUTF8String:c];
295 | }
296 |
297 | - (NSString*)stringForColumn:(NSString*)columnName {
298 | return [self stringForColumnIndex:[self columnIndexForName:columnName]];
299 | }
300 |
301 | - (NSDate*)dateForColumn:(NSString*)columnName {
302 | return [self dateForColumnIndex:[self columnIndexForName:columnName]];
303 | }
304 |
305 | - (NSDate*)dateForColumnIndex:(int)columnIdx {
306 |
307 | if (sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL || (columnIdx < 0) || columnIdx >= sqlite3_column_count([_statement statement])) {
308 | return nil;
309 | }
310 |
311 | return [_parentDB hasDateFormatter] ? [_parentDB dateFromString:[self stringForColumnIndex:columnIdx]] : [NSDate dateWithTimeIntervalSince1970:[self doubleForColumnIndex:columnIdx]];
312 | }
313 |
314 |
315 | - (NSData*)dataForColumn:(NSString*)columnName {
316 | return [self dataForColumnIndex:[self columnIndexForName:columnName]];
317 | }
318 |
319 | - (NSData*)dataForColumnIndex:(int)columnIdx {
320 |
321 | if (sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL || (columnIdx < 0) || columnIdx >= sqlite3_column_count([_statement statement])) {
322 | return nil;
323 | }
324 |
325 | const char *dataBuffer = sqlite3_column_blob([_statement statement], columnIdx);
326 | int dataSize = sqlite3_column_bytes([_statement statement], columnIdx);
327 |
328 | if (dataBuffer == NULL) {
329 | return nil;
330 | }
331 |
332 | return [NSData dataWithBytes:(const void *)dataBuffer length:(NSUInteger)dataSize];
333 | }
334 |
335 |
336 | - (NSData*)dataNoCopyForColumn:(NSString*)columnName {
337 | return [self dataNoCopyForColumnIndex:[self columnIndexForName:columnName]];
338 | }
339 |
340 | - (NSData*)dataNoCopyForColumnIndex:(int)columnIdx {
341 |
342 | if (sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL || (columnIdx < 0) || columnIdx >= sqlite3_column_count([_statement statement])) {
343 | return nil;
344 | }
345 |
346 | const char *dataBuffer = sqlite3_column_blob([_statement statement], columnIdx);
347 | int dataSize = sqlite3_column_bytes([_statement statement], columnIdx);
348 |
349 | NSData *data = [NSData dataWithBytesNoCopy:(void *)dataBuffer length:(NSUInteger)dataSize freeWhenDone:NO];
350 |
351 | return data;
352 | }
353 |
354 |
355 | - (BOOL)columnIndexIsNull:(int)columnIdx {
356 | return sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL;
357 | }
358 |
359 | - (BOOL)columnIsNull:(NSString*)columnName {
360 | return [self columnIndexIsNull:[self columnIndexForName:columnName]];
361 | }
362 |
363 | - (const unsigned char *)UTF8StringForColumnIndex:(int)columnIdx {
364 |
365 | if (sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL || (columnIdx < 0) || columnIdx >= sqlite3_column_count([_statement statement])) {
366 | return nil;
367 | }
368 |
369 | return sqlite3_column_text([_statement statement], columnIdx);
370 | }
371 |
372 | - (const unsigned char *)UTF8StringForColumn:(NSString*)columnName {
373 | return [self UTF8StringForColumnIndex:[self columnIndexForName:columnName]];
374 | }
375 |
376 | - (const unsigned char *)UTF8StringForColumnName:(NSString*)columnName {
377 | return [self UTF8StringForColumn:columnName];
378 | }
379 |
380 | - (id)objectForColumnIndex:(int)columnIdx {
381 | if (columnIdx < 0 || columnIdx >= sqlite3_column_count([_statement statement])) {
382 | return nil;
383 | }
384 |
385 | int columnType = sqlite3_column_type([_statement statement], columnIdx);
386 |
387 | id returnValue = nil;
388 |
389 | if (columnType == SQLITE_INTEGER) {
390 | returnValue = [NSNumber numberWithLongLong:[self longLongIntForColumnIndex:columnIdx]];
391 | }
392 | else if (columnType == SQLITE_FLOAT) {
393 | returnValue = [NSNumber numberWithDouble:[self doubleForColumnIndex:columnIdx]];
394 | }
395 | else if (columnType == SQLITE_BLOB) {
396 | returnValue = [self dataForColumnIndex:columnIdx];
397 | }
398 | else {
399 | //default to a string for everything else
400 | returnValue = [self stringForColumnIndex:columnIdx];
401 | }
402 |
403 | if (returnValue == nil) {
404 | returnValue = [NSNull null];
405 | }
406 |
407 | return returnValue;
408 | }
409 |
410 | - (id)objectForColumnName:(NSString*)columnName {
411 | return [self objectForColumn:columnName];
412 | }
413 |
414 | - (id)objectForColumn:(NSString*)columnName {
415 | return [self objectForColumnIndex:[self columnIndexForName:columnName]];
416 | }
417 |
418 | // returns autoreleased NSString containing the name of the column in the result set
419 | - (NSString*)columnNameForIndex:(int)columnIdx {
420 | return [NSString stringWithUTF8String: sqlite3_column_name([_statement statement], columnIdx)];
421 | }
422 |
423 | - (id)objectAtIndexedSubscript:(int)columnIdx {
424 | return [self objectForColumnIndex:columnIdx];
425 | }
426 |
427 | - (id)objectForKeyedSubscript:(NSString *)columnName {
428 | return [self objectForColumn:columnName];
429 | }
430 |
431 |
432 | @end
433 |
--------------------------------------------------------------------------------
/BGFMDB/libs/FMDB/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 2.7.2
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(CURRENT_PROJECT_VERSION)
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/BGFMDB/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // BGFMDB
4 | //
5 | // Created by huangzhibiao on 16/4/28.
6 | // Copyright © 2016年 Biao. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "AppDelegate.h"
11 |
12 | int main(int argc, char * argv[]) {
13 | @autoreleasepool {
14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/BGFMDB/people.h:
--------------------------------------------------------------------------------
1 | //
2 | // people.h
3 | // BGFMDB
4 | //
5 | // Created by huangzhibiao on 16/9/27.
6 | // Copyright © 2016年 Biao. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 | #import "BGFMDB.h" //添加该头文件,本类就具有了存储功能.
12 | @class People;
13 | @interface Human : NSObject
14 |
15 | @property(nonatomic,copy)NSString* sex;
16 | @property(nonatomic,copy)NSString* body;
17 | @property(nonatomic,assign)NSInteger humanAge;
18 | @property(nonatomic,assign)int age;
19 | @property(nonatomic,assign)int num;
20 | @property(nonatomic,assign)int counts;
21 | @property(nonatomic,copy)NSString* food;
22 | @property(nonatomic,strong)NSData* data;
23 | @property(nonatomic,strong)NSArray* array;
24 | @property(nonatomic,strong)NSDictionary* dict;
25 | @end
26 |
27 | @interface Student : NSObject
28 |
29 | @property(nonatomic,copy)NSString* num;
30 | @property(nonatomic,strong)NSArray* names;
31 | @property(nonatomic,strong)Human* human;
32 | @property(nonatomic,assign)int count;
33 | @end
34 |
35 | @interface User : NSObject
36 |
37 | @property(nonatomic,strong)NSDictionary* attri;
38 | @property(nonatomic,strong)NSNumber* userNumer;
39 | @property(nonatomic,strong)Student* student;//第二层类嵌套 , 可以无穷嵌套...
40 | @property(nonatomic,strong)People *userP;
41 | @property(nonatomic,assign)int userAge;
42 | @property(nonatomic,copy)NSString* name;
43 | @end
44 |
45 | @interface People : NSObject
46 | {
47 | @public
48 | int testAge;
49 | NSString* testName;
50 | }
51 |
52 |
53 | @property(nonatomic,copy)NSString* name;
54 | @property(nonatomic,strong)NSNumber* num;
55 | @property(nonatomic,assign)int age;
56 | @property(nonatomic,copy)NSString* sex;
57 | @property(nonatomic,copy)NSString* eye;
58 | @property(nonatomic,copy)NSString* sex_old;
59 | @property(nonatomic,strong)NSArray* students;
60 | @property(nonatomic,strong)NSDictionary* infoDic;
61 | @property(nonatomic,strong)User* user;//第一层类嵌套
62 | @property(nonatomic,strong)User* user1;
63 |
64 | @property(nonatomic,assign)int bint1;
65 | @property(nonatomic,assign)short bshort;
66 | @property(nonatomic,assign)signed bsigned;
67 | @property(nonatomic,assign)long long blonglong;
68 | @property(nonatomic,assign)unsigned bunsigned;
69 | @property(nonatomic,assign)float bfloat;
70 | @property(nonatomic,assign)double bdouble;
71 | @property(nonatomic,assign)CGFloat bCGFloat;
72 | @property(nonatomic,assign)NSInteger bNSInteger;
73 | @property(nonatomic,assign)long blong;
74 | @property(nonatomic,assign)BOOL addBool;
75 |
76 | @property(nonatomic,assign)CGRect rect;
77 | @property(nonatomic,assign)CGPoint point;
78 | @property(nonatomic,assign)CGSize size;
79 | @property(nonatomic,assign)NSRange range;
80 |
81 | @property(nonatomic,strong)NSMutableArray* arrM;
82 | @property(nonatomic,strong)NSMutableArray* datasM;
83 | @property(nonatomic,strong)NSMutableDictionary* dictM;
84 | @property(nonatomic,strong)NSSet* nsset;
85 | @property(nonatomic,strong)NSMutableSet* setM;
86 | @property(nonatomic,strong)NSMapTable* mapTable;
87 | @property(nonatomic,strong)NSHashTable* hashTable;
88 |
89 | @property(nonatomic,strong)NSDate* date;
90 | @property(nonatomic,strong)NSData* data2;
91 | //@property(nonatomic,strong)NSMutableData* dataM;
92 | @property(nonatomic,strong)UIImage* image;
93 | @property(nonatomic,strong)UIColor* color;
94 | @property(nonatomic,strong)NSAttributedString* attriStr;
95 |
96 | @property(nonatomic,strong)NSURL* Url;
97 | @end
98 |
99 | @interface Man : NSObject
100 |
101 | @property(nonatomic,copy)NSString* Man_name;
102 | @property(nonatomic,strong)NSNumber* Man_num;
103 | @property(nonatomic,assign)int Man_age;
104 | @property(nonatomic,strong)UIImage* image;
105 |
106 | @end
107 |
108 | @class T1;
109 | @interface testT:NSObject
110 | @property(nonatomic,strong) id t1;
111 | @end
112 |
113 | @interface T1: NSObject
114 | @property(nonatomic,copy) NSString* name;
115 | @end
116 |
117 | @interface T2: T1
118 | @property(nonatomic,copy) NSString* t2;
119 | @end
120 |
121 | @interface T3 : T1
122 | @property(nonatomic,copy) NSString* t3;
123 | @property(nonatomic,strong) id t2;
124 | @end
125 |
--------------------------------------------------------------------------------
/BGFMDB/people.m:
--------------------------------------------------------------------------------
1 | //
2 | // people.m
3 | // BGFMDB
4 | //
5 | // Created by huangzhibiao on 16/9/27.
6 | // Copyright © 2016年 Biao. All rights reserved.
7 | //
8 |
9 | #import "people.h"
10 |
11 | @implementation Man
12 |
13 | @end
14 |
15 | @implementation People
16 |
17 | /**
18 | 如果需要指定“唯一约束”字段,就实现该函数,这里指定 name 为“唯一约束”.
19 | */
20 | //+(NSArray *)bg_uniqueKeys{
21 | // return @[@"name"];
22 | //}
23 |
24 | /**
25 | 设置不需要存储的属性.
26 | */
27 | //+(NSArray *)bg_ignoreKeys{
28 | // return @[@"eye",@"sex",@"num"];
29 | //}
30 |
31 | /**
32 | 自定义“联合主键” ,这里指定 name和age 为“联合主键”.
33 | */
34 | //+(NSArray *)bg_unionPrimaryKeys{
35 | // return @[@"name",@"age"];
36 | //}
37 |
38 | @end
39 |
40 | @implementation User
41 | //+(NSArray *)bg_ignoreKeys{
42 | // return @[@"attri",@"userNumer",@"student",@"userP"];
43 | //}
44 | @end
45 |
46 | @implementation Student
47 |
48 | @end
49 |
50 | @implementation Human
51 |
52 | @end
53 |
54 | @implementation testT
55 |
56 | @end
57 |
58 | @implementation T1
59 |
60 | @end
61 |
62 | @implementation T2
63 |
64 | @end
65 |
66 | @implementation T3
67 |
68 | @end
69 |
--------------------------------------------------------------------------------
/BGFMDB/stockController/stockController.h:
--------------------------------------------------------------------------------
1 | //
2 | // stockController.h
3 | // BGFMDB
4 | //
5 | // Created by huangzhibiao on 17/3/9.
6 | // Copyright © 2017年 Biao. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface stockController : UIViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/BGFMDB/stockController/stockController.m:
--------------------------------------------------------------------------------
1 | //
2 | // stockController.m
3 | // BGFMDB
4 | //
5 | // Created by huangzhibiao on 17/3/9.
6 | // Copyright © 2017年 Biao. All rights reserved.
7 | //
8 |
9 | #import "stockController.h"
10 | #import "stockModel.h"
11 |
12 | @interface stockController ()
13 |
14 | @property(nonatomic,strong)NSNumber* shenData;
15 | @property(nonatomic,strong)NSNumber* huData;
16 | @property(nonatomic,strong)NSNumber* chuangData;
17 |
18 | @property(nonatomic,strong)stockModel* shenStock;
19 | @property(nonatomic,strong)stockModel* huStock;
20 | @property(nonatomic,strong)stockModel* chuangStock;
21 |
22 | @property (weak, nonatomic) IBOutlet UILabel *shenLab;
23 | @property (weak, nonatomic) IBOutlet UILabel *huLab;
24 | @property (weak, nonatomic) IBOutlet UILabel *chuangLab;
25 |
26 | @property(nonatomic,assign)BOOL updateFlag;//停止循环更新标志;
27 | - (IBAction)backAction:(id)sender;
28 |
29 | @end
30 |
31 | @implementation stockController
32 |
33 | -(void)dealloc{
34 | //移除数据变化监听.
35 | [stockModel bg_removeChangeForTableName:nil identify:@"stock"];
36 | //恢复默认值.
37 | bg_setDisableCloseDB(NO);
38 | }
39 |
40 | - (void)viewDidLoad {
41 | [super viewDidLoad];
42 | //设置操作过程中不可关闭数据库(即closeDB函数无效),防止数据更新的时候频繁关闭开启数据库.
43 | bg_setDisableCloseDB(YES);
44 | //注册数据变化监听.
45 | [self registerChange];
46 |
47 | //深市数据初始
48 | _shenData = @(10427.24);
49 | stockModel* shenStock = [stockModel stockWithName:@"深市" stockData:_shenData];
50 | _shenStock = shenStock;
51 | [shenStock bg_saveOrUpdate];
52 | //沪市数据初始
53 | _huData = @(3013.56);
54 | stockModel* huStock = [stockModel stockWithName:@"沪市" stockData:_huData];
55 | _huStock = huStock;
56 | [huStock bg_saveOrUpdate];
57 | //创业板数据初始
58 | _chuangData = @(1954.91);
59 | stockModel* chuangStock = [stockModel stockWithName:@"创业版" stockData:_chuangData];
60 | _chuangStock = chuangStock;
61 | [chuangStock bg_saveOrUpdate];
62 |
63 | _updateFlag = YES;//设置循环更新标志.
64 | [self performSelector:@selector(updateData) withObject:nil afterDelay:1.0];
65 | }
66 |
67 | -(void)updateData{
68 | //更新深市数据
69 | _shenData = [NSNumber numberWithFloat:(float)(rand()%300) + 10427.24];
70 | _shenStock.stockData = _shenData;
71 | NSString* where1 = [NSString stringWithFormat:@"where %@=%@",bg_sqlKey(@"name"),bg_sqlValue(@"深市")];
72 | [_shenStock bg_updateWhere:where1];
73 | //更新沪市数据
74 | _huData = [NSNumber numberWithFloat:(float)(rand()%200) + 3013.56];
75 | _huStock.stockData = _huData;
76 | NSString* where2 = [NSString stringWithFormat:@"where %@=%@",bg_sqlKey(@"name"),bg_sqlValue(@"沪市")];
77 | [_huStock bg_updateWhere:where2];
78 | //更新创业板数据
79 | _chuangData = [NSNumber numberWithFloat:(float)(rand()%500) + 1954.91];
80 | _chuangStock.stockData = _chuangData;
81 | NSString* where3 = [NSString stringWithFormat:@"where %@=%@",bg_sqlKey(@"name"),bg_sqlValue(@"创业版")];
82 | [_chuangStock bg_updateWhere:where3];
83 |
84 | !_updateFlag?:[self performSelector:@selector(updateData) withObject:nil afterDelay:1.0];
85 | }
86 |
87 | //注册数据变化监听.
88 | -(void)registerChange{
89 | //注册数据变化监听.
90 | __weak typeof(self) BGSelf = self;
91 | [stockModel bg_registerChangeForTableName:nil identify:@"stock" block:^(bg_changeState result) {
92 | NSLog(@"当前线程 = %@",[NSThread currentThread]);
93 | if ((result==bg_insert) || (result==bg_update)){
94 | //读取深市数据.
95 | NSString* where1 = [NSString stringWithFormat:@"where %@=%@",bg_sqlKey(@"name"),bg_sqlValue(@"深市")];
96 | stockModel* shen = [stockModel bg_find:nil where:where1].lastObject;
97 | BGSelf.shenLab.text = shen.stockData.stringValue;
98 | //读取沪市数据.
99 | NSString* where2 = [NSString stringWithFormat:@"where %@=%@",bg_sqlKey(@"name"),bg_sqlValue(@"沪市")];
100 | stockModel* hu = [stockModel bg_find:nil where:where2].lastObject;
101 | BGSelf.huLab.text = hu.stockData.stringValue;
102 | //读取创业版数据.
103 | NSString* where3 = [NSString stringWithFormat:@"where %@=%@",bg_sqlKey(@"name"),bg_sqlValue(@"创业版")];
104 | stockModel* chuang = [stockModel bg_find:nil where:where3].lastObject;
105 | BGSelf.chuangLab.text = chuang.stockData.stringValue;
106 | }
107 | }];
108 | }
109 |
110 | - (IBAction)backAction:(id)sender {
111 | _updateFlag = NO;//停止更新操作.
112 | [self dismissViewControllerAnimated:YES completion:nil];
113 | }
114 | @end
115 |
--------------------------------------------------------------------------------
/BGFMDB/stockController/stockController.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
29 |
36 |
43 |
50 |
57 |
69 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/BGFMDB/stockController/stockModel.h:
--------------------------------------------------------------------------------
1 | //
2 | // stockModel.h
3 | // BGFMDB
4 | //
5 | // Created by huangzhibiao on 17/3/9.
6 | // Copyright © 2017年 Biao. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "BGFMDB.h" //引入所需的头文件
11 |
12 | @interface stockModel : NSObject
13 |
14 | @property(nonatomic,copy)NSString* name;
15 | @property(nonatomic,strong)NSNumber* stockData;
16 |
17 | +(instancetype)stockWithName:(NSString*)name stockData:(NSNumber*)stockData;
18 | @end
19 |
--------------------------------------------------------------------------------
/BGFMDB/stockController/stockModel.m:
--------------------------------------------------------------------------------
1 | //
2 | // stockModel.m
3 | // BGFMDB
4 | //
5 | // Created by huangzhibiao on 17/3/9.
6 | // Copyright © 2017年 Biao. All rights reserved.
7 | //
8 |
9 | #import "stockModel.h"
10 |
11 | @implementation stockModel
12 |
13 | +(instancetype)stockWithName:(NSString*)name stockData:(NSNumber*)stockData{
14 | stockModel* stock = [stockModel new];
15 | stock.name = name;
16 | stock.stockData = stockData;
17 | return stock;
18 | }
19 |
20 | //实现该函数,返回指定的 “唯一约束” name.
21 | +(NSArray *)bg_uniqueKeys{
22 | return @[@"name"];
23 | }
24 | @end
25 |
--------------------------------------------------------------------------------
/BGFMDBTests/BGFMDBTests.m:
--------------------------------------------------------------------------------
1 | //
2 | // BGFMDBTests.m
3 | // BGFMDBTests
4 | //
5 | // Created by huangzhibiao on 16/4/28.
6 | // Copyright © 2016年 Biao. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface BGFMDBTests : XCTestCase
12 |
13 | @end
14 |
15 | @implementation BGFMDBTests
16 |
17 | - (void)setUp {
18 | [super setUp];
19 | // Put setup code here. This method is called before the invocation of each test method in the class.
20 | }
21 |
22 | - (void)tearDown {
23 | // Put teardown code here. This method is called after the invocation of each test method in the class.
24 | [super tearDown];
25 | }
26 |
27 | - (void)testExample {
28 | // This is an example of a functional test case.
29 | // Use XCTAssert and related functions to verify your tests produce the correct results.
30 | }
31 |
32 | - (void)testPerformanceExample {
33 | // This is an example of a performance test case.
34 | [self measureBlock:^{
35 | // Put the code you want to measure the time of here.
36 | }];
37 | }
38 |
39 | @end
40 |
--------------------------------------------------------------------------------
/BGFMDBTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/BGFMDBUITests/BGFMDBUITests.m:
--------------------------------------------------------------------------------
1 | //
2 | // BGFMDBUITests.m
3 | // BGFMDBUITests
4 | //
5 | // Created by huangzhibiao on 16/4/28.
6 | // Copyright © 2016年 Biao. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface BGFMDBUITests : XCTestCase
12 |
13 | @end
14 |
15 | @implementation BGFMDBUITests
16 |
17 | - (void)setUp {
18 | [super setUp];
19 |
20 | // Put setup code here. This method is called before the invocation of each test method in the class.
21 |
22 | // In UI tests it is usually best to stop immediately when a failure occurs.
23 | self.continueAfterFailure = NO;
24 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method.
25 | [[[XCUIApplication alloc] init] launch];
26 |
27 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
28 | }
29 |
30 | - (void)tearDown {
31 | // Put teardown code here. This method is called after the invocation of each test method in the class.
32 | [super tearDown];
33 | }
34 |
35 | - (void)testExample {
36 | // Use recording to get started writing UI tests.
37 | // Use XCTAssert and related functions to verify your tests produce the correct results.
38 | }
39 |
40 | @end
41 |
--------------------------------------------------------------------------------
/BGFMDBUITests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # BGFMDB让数据的增删改查分别只需要一行代码即可,就是这么简单任性.
2 | ## 最新重大更新:
3 | 1.增加了自定义“联合主键”的功能.
4 | 2.进行了大重构,优化缩减API,支持多个'唯一约束',ignoredKeys放到模型类.m文件实现bg_ignoreKeys类函数即可,增加自定义表名功能.
5 | ## Swift工程中使用方式
6 | 目前可以存储Swift工程中的OC类model,在桥接文件导入OC类model的头文件即可, 但是不能解析存储Swift类model,后面会补上Swift类model解析部分😊.
7 | ## 小伙伴们的使用反馈
8 | 
9 | ## 交流QQ群:
10 | 使用交流QQ群: 572359447
11 | 如果在使用过程中发现什么问题或有什么疑问,请加群反馈.
12 | ## 完美支持:
13 | int,long,signed,float,double,NSInteger,CGFloat,BOOL,NSString,NSMutableString,NSMutableAttributedString,NSAttributedString,NSNumber,NSArray,NSMutableArray,NSDictionary,NSMutableDictionary,NSMapTable,NSHashTable,NSData,NSMutableData,UIImage,NSDate,NSURL,NSRange,CGRect,CGSize,CGPoint,自定义对象 等的存储.
14 | ## 写本库的动机: 在对coredata和realm做了探究总结后,发现了很多有缺陷的地方,最明显的就是下面的原因:
15 | ### realm缺陷:
16 | Realm不支持集合类型,这一点也是比较蛋疼。
17 | Realm支持以下的属性类型:BOOL、bool、int、NSInteger、long、long long、float、double、NSString、NSDate、NSData以及 被特殊类型标记的NSNumber。CGFloat属性的支持被取消了,因为它不具备平台独立性。
18 | 这里就是不支持集合,比如说NSArray,NSMutableArray,NSDictionary,NSMutableDictionary,NSSet,NSMutableSet。如果服务器传来的一个字典,key是一个字符串,对应的value就是一个数组,这时候就想存储这个数组就比较困难了。
19 | ### coredata缺陷:
20 | coredata虽然通过Transformable可以存取集合类型,但需要开发者去进行转换处理,使用起来不方便直观,虽然coredata有很多好用的封装库,像ResKit,MMRecord等,但这些库比较庞大,而且都是英文介绍,不利于国内初中级开发的快速开发使用.
21 | ## 虽然国内也已经有了对FMDB面相对象层的封装,比如像JRDB,LKDBHelper等,但是在使用总结后还是发现不少的问题,问题如下:
22 | JRDB存储数组需要传入对象的泛型,同时还要复写一些函数和映射,这对于初中级开发者是很不利的,看的很萌逼.
23 | LKDBHelper好一点,但也要复写不少的函数,而且LKDBHelper的使用demo有点乱,还有就是不支持NSMaptable,NSHashTable的存储,LKDBHelper还有一个致命的弱点就是当类变量名称跟sqlite的关键字一样时,会发生冲突错误!
24 | ### 而最重要的是: JRDB,LKDBHelper都不支持同一数组中存储不同类型的自定义类型数据,BGFMDB则完美支持,JRDB,LKDBHelper已经成为过去,现在是BGFMDB的时代,作者的宣言是:“要把BGFMDB写成不会写代码的人都会用的库”,欢迎大家反馈和吐槽问题,骚年作者等着你们.
25 | ## 综合上述原因后,我决定写一款适合国内初中级开发者使用的存储封装库(BGFMDB),不管是从使用步骤还是支持的存储类型上,都比JRDB,LKDB简单好用和全面.
26 | ## 本库几乎支持存储ios所有基本的自带数据类型.
27 | ## 使用介绍(喜欢的话别忘了给本库一个Star😊).
28 | ## 想加密数据库的,请借鉴此demo:
29 | ## CocoaPods的方式.
30 | ### Podfile
31 | ```Podfile
32 | platform :ios, '8.0'
33 |
34 | target '工程名称' do
35 | pod 'BGFMDB', '~> 2.0.9'
36 | end
37 | ```
38 | ## 直接下载库代码使用方式.
39 | ### 添加所需依赖库
40 | libsqlite3
41 | ### 导入头文件
42 | ```Objective-C
43 | /**
44 | 只要在自己的类中导入了BGFMDB.h这个头文件,本类就具有了存储功能.
45 | */
46 | #import
47 | #import "BGFMDB.h"
48 | @interface stockModel : NSObject
49 | @property(nonatomic,copy)NSString* name;
50 | @property(nonatomic,strong)NSNumber* stockData;
51 | +(instancetype)stockWithName:(NSString*)name stockData:(NSNumber*)stockData;
52 | @end
53 | ```
54 | ### 主键
55 | ```Objective-C
56 | /**
57 | 本库自带的自动增长主键.
58 | */
59 | @property(nonatomic,strong)NSNumber*_Nullable bg_id;
60 |
61 | /**
62 | 为了方便开发者,特此加入以下两个字段属性供开发者做参考.(自动记录数据的存入时间和更新时间)
63 | */
64 | @property(nonatomic,copy)NSString* _Nonnull bg_createTime;//数据创建时间(即存入数据库的时间)
65 | @property(nonatomic,copy)NSString* _Nonnull bg_updateTime;//数据最后那次更新的时间.
66 |
67 | /**
68 | 自定义表名
69 | */
70 | @property(nonatomic,copy)NSString* _Nonnull bg_tableName;
71 | ```
72 | ### 联合主键
73 | ```Objective-C
74 | /**
75 | 自定义“联合主键” ,这里指定 name和age 为“联合主键”.
76 | */
77 | +(NSArray *)bg_unionPrimaryKeys{
78 | return @[@"name",@"age"];
79 | }
80 | ```
81 | ### 唯一约束
82 | ```Objective-C
83 | /**
84 | 如果需要指定“唯一约束”字段, 在模型.m文件中实现该函数,这里指定 name和age 为“唯一约束”.
85 | */
86 | +(NSArray *)bg_uniqueKeys{
87 | return @[@"name",@"age"];
88 | }
89 | ```
90 | ### 设置不需要存储的属性
91 | ```Objective-C
92 | /**
93 | 设置不需要存储的属性, 在模型.m文件中实现该函数.
94 | */
95 | +(NSArray *)bg_ignoreKeys{
96 | return @[@"eye",@"sex",@"num"];
97 | }
98 | ```
99 | ### 初始化对象
100 | ```Objective-C
101 | People* p = [self people];
102 | ```
103 | ### 存储
104 | ```Objective-C
105 | /**
106 | 同步存储.
107 | */
108 | [p bg_save];
109 |
110 | /**
111 | 异步存储.
112 | */
113 | [p bg_saveAsync:^(BOOL isSuccess) {
114 | //you code
115 | }];
116 |
117 | /**
118 | 覆盖掉原来People类的所有数据,只存储当前对象的数据.
119 | */
120 | [p bg_cover];
121 |
122 | /**
123 | 同步存储或更新.
124 | 当"唯一约束"或"主键"存在时,此接口会更新旧数据,没有则存储新数据.
125 | 提示:“唯一约束”优先级高于"主键".
126 | */
127 | [p bg_saveOrUpdate];
128 |
129 | /**
130 | 同步 存储或更新 数组元素.
131 | 当"唯一约束"或"主键"存在时,此接口会更新旧数据,没有则存储新数据.
132 | 提示:“唯一约束”优先级高于"主键".
133 | */
134 | [People bg_saveOrUpdateArray:@[p,p1,p2]];
135 | ```
136 | ### 查询
137 | ```Objective-C
138 | /**
139 | 同步查询所有数据.
140 | */
141 | NSArray* finfAlls = [People bg_findAll:bg_tablename];
142 |
143 | /**
144 | 按条件查询.
145 | */
146 | NSString* where = [NSString stringWithFormat:@"where %@=%@",bg_sqlKey(@"name"),bg_sqlValue(@"斯巴达")];
147 | NSArray* arr = [People bg_find:bg_tablename where:where];
148 |
149 | /**
150 | 直接写SQL语句操作.
151 | */
152 | NSArray* arr = bg_executeSql(@"select * from yy", bg_tablename, [People class]);//查询时,后面两个参数必须要传入.
153 |
154 | /**
155 | 根据范围查询.
156 | */
157 | NSArray* arr = [People bg_find:bg_tablename range:NSMakeRange(i,50) orderBy:nil desc:NO];
158 | ```
159 | ### 更新
160 | ```Objective-C
161 | /**
162 | 单个对象更新.
163 | 支持keyPath.
164 | */
165 | NSString* where = [NSString stringWithFormat:@"where %@ or %@=%@",bg_keyPathValues(@[@"user.student.human.body",bg_equal,@"小芳"]),bg_sqlKey(@"age"),bg_sqlValue(@(31))];
166 | [p bg_updateWhere:where];
167 |
168 | /**
169 | sql语句批量更新.
170 | */
171 | NSString* where = [NSString stringWithFormat:@"set %@=%@ where %@=%@",bg_sqlKey(@"name"),bg_sqlValue(@"马化腾"),bg_sqlKey(@"name"),bg_sqlValue(@"天朝")];
172 | [People bg_update:bg_tablename where:where];
173 |
174 | /**
175 | 直接写SQL语句操作
176 | */
177 | bg_executeSql(@"update yy set BG_name='标哥'", nil, nil);//更新或删除等操作时,后两个参数不必传入.
178 | ```
179 | ### 删除
180 | ```Objective-C
181 | /**
182 | 按条件删除.
183 | */
184 | NSString* where = [NSString stringWithFormat:@"where %@=%@",bg_sqlKey(@"name"),bg_sqlValue(@"斯巴达")];
185 | [People bg_delete:bg_tablename where:where];
186 |
187 | /**
188 | 清除表的所有数据.
189 | */
190 | [People bg_clear:bg_tablename];
191 |
192 | /**
193 | 删除数据库表.
194 | */
195 | [People bg_drop:bg_tablename];
196 |
197 | ```
198 | ### 获取类数据库版本
199 | ```Objective-C
200 | /**
201 | 获取该类的数据库版本号;
202 | */
203 | NSInteger version = [People bg_version:bg_tablename];
204 | ```
205 | ### 类数据库版本手动升级(当'唯一约束','联合主键','属性类型改变',发生改变时需要手动调用升级,其他情况库自动检测升级)
206 | ```Objective-C
207 | //注: 版本号从1开始,依次往后递增,本次更新版本号不得 低于或等于 上次的版本号,否则不会更新.
208 | /**
209 | 如果类'唯一约束','联合主键','属性类型'发生改变.
210 | 则调用此API刷新该类数据库,不需要新旧映射的情况下使用此API.
211 | */
212 | [People bg_update:bg_tablename version:version];
213 |
214 | /**
215 | 如果类'唯一约束','联合主键','属性类型'发生改变.
216 | 则调用此API刷新该类数据库.data2是新变量名,data是旧变量名,即将旧的值映射到新的变量名,其他不变的变量名会自动复制,只管写出变化的对应映射即可.
217 | */
218 | [People bg_update:bg_tablename version:version keyDict:@{@"data2":@"data"}];
219 | ```
220 | ### 事务操作
221 | ```Objective-C
222 | /**
223 | 事务操作,返回YES提交事务,返回NO则回滚事务.
224 | */
225 | bg_inTransaction(^BOOL{
226 | [p bg_save];//存储
227 | return NO;
228 | });
229 | ```
230 | ### 快速查询数据条数
231 | ```Objective-C
232 | /**
233 | 按条件查询表中所有数据的条数.
234 | */
235 | NSInteger count = [People bg_count:bg_tablename where:nil];
236 | ```
237 | ### 类数据之间的拷贝
238 | ```Objective-C
239 | /**
240 | 将People表的数据拷贝给bg_tablename表, name拷贝给Man的Man_name,其他同理.
241 | */
242 | [People bg_copy:nil toTable:bg_tablename keyDict:@{@"name":@"Man_name",
243 | @"num":@"Man_num",
244 | @"age":@"Man_age",
245 | @"image":@"image"} append:NO];
246 | ```
247 | ### 直接存取数组
248 | ```Objective-C
249 | NSMutableArray* testA = [NSMutableArray array];
250 | [testA addObject:@"我是"];
251 | [testA addObject:@(10)];
252 | [testA addObject:@(9.999)];
253 | [testA addObject:@{@"key":@"value"}];
254 | /**
255 | 存储标识名为testA的数组.
256 | */
257 | [testA bg_saveArrayWithName:@"testA"];
258 |
259 | /**
260 | 往标识名为@"testA"的数组中添加元素.
261 | */
262 | [NSArray bg_addObjectWithName:@"testA" object:@[@(1),@"哈哈"]];
263 |
264 | /**
265 | 删除标识名为testA的数组某个位置上的元素.
266 | */
267 | [NSArray bg_deleteObjectWithName:@"testA" Index:3];
268 |
269 | /**
270 | 查询标识名为testA的数组全部元素.
271 | */
272 | NSArray* testResult = [NSArray bg_arrayWithName:@"testA"];
273 |
274 | /**
275 | 获取标识名为testA的数组某个位置上的元素.
276 | */
277 | id arrObject = [NSArray bg_objectWithName:@"testA" Index:3];
278 |
279 | /**
280 | 清除标识名为testA的数组所有元素.
281 | */
282 | [NSArray bg_clearArrayWithName:@"testA"];
283 | ```
284 | ### 直接存取字典
285 | ```Objective-C
286 | NSDictionary* dict = @{@"one":@(1),@"key":@"value",@"array":@[@(1.2),@"哈哈"]};
287 | /**
288 | 存储字典.
289 | */
290 | [dict bg_saveDictionary];
291 |
292 | /**
293 | 添加字典元素.
294 | */
295 | [NSDictionary bg_setValue:@"标哥" forKey:@"name"];
296 |
297 | /**
298 | 获取某个字典元素.
299 | */
300 | id num = [NSDictionary bg_valueForKey:@"one"];
301 |
302 | /**
303 | 移除字典某个元素.
304 | */
305 | [NSDictionary bg_removeValueForKey:@"key"];
306 |
307 | /**
308 | 遍历字典元素.
309 | */
310 | [NSDictionary bg_enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, id _Nonnull value, BOOL *stop) {
311 | NSLog(@"key = %@ , value = %@",key,value);
312 | }];
313 |
314 | /**
315 | 清空字典.
316 | */
317 | [NSDictionary bg_clearDictionary];
318 | ```
319 | ### 注册数据变化监听
320 | ```Objective-C
321 | /**
322 | 注册监听bg_tablename表的数据变化,唯一识别标识是@"change".
323 | */
324 | [People bg_registerChangeForTableName:bg_tablename identify:@"change" block:^(bg_changeState result) {
325 | switch (result) {
326 | case bg_insert:
327 | NSLog(@"有数据插入");
328 | break;
329 | case bg_update:
330 | NSLog(@"有数据更新");
331 | break;
332 | case bg_delete:
333 | NSLog(@"有数据删删除");
334 | break;
335 | case bg_drop:
336 | NSLog(@"有表删除");
337 | break;
338 | default:
339 | break;
340 | }
341 | }];
342 | ```
343 | ### 移除数据监听
344 | ```Objective-C
345 | /**
346 | 移除bg_tablename表数据变化的监听,唯一识别标识是@"change".
347 | */
348 | [People bg_removeChangeForTableName:bg_tablename identify:@"change"];
349 | ```
350 | ### 字典转模型
351 | ```Objective-C
352 | NSDictionary* dictAni = [self getDogDict];
353 | /**
354 | 一代码搞定字典转模型.
355 | */
356 | Dog* dog = [Dog bg_objectWithKeyValues:dictAni];
357 |
358 | NSDictionary* dictMy = [self getMyDict];
359 | /**
360 | 一代码搞定字典转模型.
361 | */
362 | My* my = [My bg_objectWithDictionary:dictMy];
363 | ```
364 | ### 模型转字典
365 | ```Objective-C
366 | /**
367 | 一句代码搞定模型转字典.
368 | */
369 | NSDictionary* dictBodyAll = [body bg_keyValuesIgnoredKeys:nil];
370 |
371 | /**
372 | 忽略掉hand这个变量不转.
373 | */
374 | NSDictionary* dictBody = [body bg_keyValuesIgnoredKeys:@[@"hand"]];
375 | ```
376 | ### 如果模型中的数组变量存储的是自定义类,则需要实现下面的这个函数:
377 | ```Objective-C
378 | /**
379 | 如果模型中有数组且存放的是自定义的类(NSString等系统自带的类型就不必要了),那就实现该函数,key是数组名称,value是自定的类Class,用法跟MJExtension一样.
380 | (‘字典转模型’ 或 ’模型转字典‘ 都需要实现该函数)
381 | */
382 | +(NSDictionary *)bg_objectClassInArray{
383 | return @{@"dogs":[Dog class],@"bodys":[Body class]};
384 | }
385 |
386 | /**
387 | 如果模型中有自定义类变量,则实现该函数对应进行集合到模型的转换.
388 | 将json数据中body这个key对应的值转化为Body类变量body对象.
389 | */
390 | +(NSDictionary *)bg_objectClassForCustom{
391 | return @{@"body":[Body class]};
392 | }
393 |
394 | /**
395 | 替换变量的功能(及当字典的key和属性名不一样时,进行映射对应起来)
396 | 即将字典里key为descri的值 赋给 属性名为intro的变量,性别和sex同理.
397 | */
398 | +(NSDictionary *)bg_replacedKeyFromPropertyName{
399 | return @{@"descri":@"intro",@"性别":@"sex"};
400 | }
401 | ```
402 | ### 更多功能请下载demo运行了解使用.
403 |
--------------------------------------------------------------------------------