├── Podfile
├── Podfile.lock
├── Pods
├── FMDB
│ ├── LICENSE.txt
│ ├── README.markdown
│ └── src
│ │ └── fmdb
│ │ ├── FMDB.h
│ │ ├── FMDatabase.h
│ │ ├── FMDatabase.m
│ │ ├── FMDatabaseAdditions.h
│ │ ├── FMDatabaseAdditions.m
│ │ ├── FMDatabasePool.h
│ │ ├── FMDatabasePool.m
│ │ ├── FMDatabaseQueue.h
│ │ ├── FMDatabaseQueue.m
│ │ ├── FMResultSet.h
│ │ └── FMResultSet.m
├── Headers
│ ├── Private
│ │ └── FMDB
│ │ │ ├── FMDB.h
│ │ │ ├── FMDatabase.h
│ │ │ ├── FMDatabaseAdditions.h
│ │ │ ├── FMDatabasePool.h
│ │ │ ├── FMDatabaseQueue.h
│ │ │ └── FMResultSet.h
│ └── Public
│ │ └── FMDB
│ │ ├── FMDB.h
│ │ ├── FMDatabase.h
│ │ ├── FMDatabaseAdditions.h
│ │ ├── FMDatabasePool.h
│ │ ├── FMDatabaseQueue.h
│ │ └── FMResultSet.h
├── Manifest.lock
├── Pods.xcodeproj
│ ├── project.pbxproj
│ └── xcuserdata
│ │ └── apple.xcuserdatad
│ │ └── xcschemes
│ │ ├── FMDB.xcscheme
│ │ ├── Pods-WebCrawler.xcscheme
│ │ └── xcschememanagement.plist
└── Target Support Files
│ ├── FMDB
│ ├── FMDB-dummy.m
│ ├── FMDB-prefix.pch
│ └── FMDB.xcconfig
│ └── Pods-WebCrawler
│ ├── Pods-WebCrawler-acknowledgements.markdown
│ ├── Pods-WebCrawler-acknowledgements.plist
│ ├── Pods-WebCrawler-dummy.m
│ ├── Pods-WebCrawler-frameworks.sh
│ ├── Pods-WebCrawler-resources.sh
│ ├── Pods-WebCrawler.debug.xcconfig
│ └── Pods-WebCrawler.release.xcconfig
├── README.md
├── WebCrawler.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcuserdata
│ │ └── apple.xcuserdatad
│ │ └── UserInterfaceState.xcuserstate
└── xcuserdata
│ └── apple.xcuserdatad
│ └── xcschemes
│ └── xcschememanagement.plist
├── WebCrawler.xcworkspace
├── contents.xcworkspacedata
└── xcuserdata
│ └── apple.xcuserdatad
│ ├── UserInterfaceState.xcuserstate
│ └── xcdebugger
│ └── Breakpoints_v2.xcbkptlist
└── WebCrawler
├── NSString+Substring.h
├── NSString+Substring.m
├── WechatIMG13.jpeg
└── main.m
/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment the next line to define a global platform for your project
2 | # platform :ios, '9.0'
3 |
4 | target 'WebCrawler' do
5 | # Uncomment the next line if you're using Swift or would like to use dynamic frameworks
6 | # use_frameworks!
7 |
8 | # Pods for WebCrawler
9 | pod "FMDB"
10 | end
11 |
--------------------------------------------------------------------------------
/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - FMDB (2.7.2):
3 | - FMDB/standard (= 2.7.2)
4 | - FMDB/standard (2.7.2)
5 |
6 | DEPENDENCIES:
7 | - FMDB
8 |
9 | SPEC CHECKSUMS:
10 | FMDB: 6198a90e7b6900cfc046e6bc0ef6ebb7be9236aa
11 |
12 | PODFILE CHECKSUM: 784b79b502ce23f1b3d906b095721a12c1affe55
13 |
14 | COCOAPODS: 1.2.1
15 |
--------------------------------------------------------------------------------
/Pods/FMDB/LICENSE.txt:
--------------------------------------------------------------------------------
1 | If you are using FMDB in your project, I'd love to hear about it. Let Gus know
2 | by sending an email to gus@flyingmeat.com.
3 |
4 | And if you happen to come across either Gus Mueller or Rob Ryan in a bar, you
5 | might consider purchasing a drink of their choosing if FMDB has been useful to
6 | you.
7 |
8 | Finally, and shortly, this is the MIT License.
9 |
10 | Copyright (c) 2008-2014 Flying Meat Inc.
11 |
12 | Permission is hereby granted, free of charge, to any person obtaining a copy
13 | of this software and associated documentation files (the "Software"), to deal
14 | in the Software without restriction, including without limitation the rights
15 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 | copies of the Software, and to permit persons to whom the Software is
17 | furnished to do so, subject to the following conditions:
18 |
19 | The above copyright notice and this permission notice shall be included in
20 | all copies or substantial portions of the Software.
21 |
22 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
28 | THE SOFTWARE.
--------------------------------------------------------------------------------
/Pods/FMDB/README.markdown:
--------------------------------------------------------------------------------
1 | # FMDB v2.7
2 |
3 | [](https://img.shields.io/cocoapods/v/FMDB.svg)
4 | [](https://github.com/Carthage/Carthage)
5 |
6 | This is an Objective-C wrapper around SQLite: http://sqlite.org/
7 |
8 | ## The FMDB Mailing List:
9 | http://groups.google.com/group/fmdb
10 |
11 | ## Read the SQLite FAQ:
12 | http://www.sqlite.org/faq.html
13 |
14 | Since FMDB is built on top of SQLite, you're going to want to read this page top to bottom at least once. And while you're there, make sure to bookmark the SQLite Documentation page: http://www.sqlite.org/docs.html
15 |
16 | ## Contributing
17 | Do you have an awesome idea that deserves to be in FMDB? You might consider pinging ccgus first to make sure he hasn't already ruled it out for some reason. Otherwise pull requests are great, and make sure you stick to the local coding conventions. However, please be patient and if you haven't heard anything from ccgus for a week or more, you might want to send a note asking what's up.
18 |
19 | ## Installing
20 |
21 | ### CocoaPods
22 |
23 | [](https://www.versioneye.com/objective-c/fmdb/2.3)
24 | [](https://www.versioneye.com/objective-c/fmdb/references)
25 |
26 | FMDB can be installed using [CocoaPods](https://cocoapods.org/).
27 |
28 | If you haven't done so already, you might want to initialize the project, to have it produce a `Podfile` template for you:
29 |
30 | ```
31 | $ pod init
32 | ```
33 |
34 | Then, edit the `Podfile`, adding `FMDB`:
35 |
36 | ```ruby
37 | # Uncomment the next line to define a global platform for your project
38 | # platform :ios, '9.0'
39 |
40 | target 'MyApp' do
41 | # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
42 | use_frameworks!
43 |
44 | # Pods for MyApp2
45 |
46 | pod 'FMDB'
47 | # pod 'FMDB/FTS' # FMDB with FTS
48 | # pod 'FMDB/standalone' # FMDB with latest SQLite amalgamation source
49 | # pod 'FMDB/standalone/FTS' # FMDB with latest SQLite amalgamation source and FTS
50 | # pod 'FMDB/SQLCipher' # FMDB with SQLCipher
51 | end
52 | ```
53 |
54 | Then install the pods:
55 |
56 | ```
57 | $ pod install
58 | ```
59 |
60 | Then open the `.xcworkspace` rather than the `.xcodeproj`.
61 |
62 | For more information on Cocoapods visit https://cocoapods.org.
63 |
64 | **If using FMDB with [SQLCipher](https://www.zetetic.net/sqlcipher/) you must use the FMDB/SQLCipher subspec. The FMDB/SQLCipher subspec declares SQLCipher as a dependency, allowing FMDB to be compiled with the `-DSQLITE_HAS_CODEC` flag.**
65 |
66 | ### Carthage
67 |
68 | Once you make sure you have [the latest version of Carthage](https://github.com/Carthage/Carthage/releases), you can open up a command line terminal, navigate to your project's main directory, and then do the following commands:
69 |
70 | ```
71 | $ echo ' github "ccgus/fmdb" ' > ./Cartfile
72 | $ carthage update
73 | ```
74 |
75 | You can then configure your project as outlined in Carthage's [Getting Started](https://github.com/Carthage/Carthage#getting-started) (i.e. for iOS, adding the framework to the "Link Binary with Libraries" in your target and adding the `copy-frameworks` script; in macOS, adding the framework to the list of "Embedded Binaries").
76 |
77 | ## FMDB Class Reference:
78 | http://ccgus.github.io/fmdb/html/index.html
79 |
80 | ## Automatic Reference Counting (ARC) or Manual Memory Management?
81 | You can use either style in your Cocoa project. FMDB will figure out which you are using at compile time and do the right thing.
82 |
83 | ## What's New in FMDB 2.7
84 |
85 | FMDB 2.7 attempts to support a more natural interface. This represents a fairly significant change for Swift developers (audited for nullability; shifted to properties in external interfaces where possible rather than methods; etc.). For Objective-C developers, this should be a fairly seamless transition (unless you were using the ivars that were previously exposed in the public interface, which you shouldn't have been doing, anyway!).
86 |
87 | ### Nullability and Swift Optionals
88 |
89 | FMDB 2.7 is largely the same as prior versions, but has been audited for nullability. For Objective-C users, this simply means that if you perform a static analysis of your FMDB-based project, you may receive more meaningful warnings as you review your project, but there are likely to be few, if any, changes necessary in your code.
90 |
91 | For Swift users, this nullability audit results in changes that are not entirely backward compatible with FMDB 2.6, but is a little more Swifty. Before FMDB was audited for nullability, Swift was forced to defensively assume that variables were optional, but the library now more accurately knows which properties and method parameters are optional, and which are not.
92 |
93 | This means, though, that Swift code written for FMDB 2.7 may require changes. For example, consider the following Swift 3/Swift 4 code for FMDB 2.6:
94 | ```swift
95 |
96 | guard let queue = FMDatabaseQueue(path: fileURL.path) else {
97 | print("Unable to create FMDatabaseQueue")
98 | return
99 | }
100 |
101 | queue.inTransaction { db, rollback in
102 | do {
103 | guard let db == db else {
104 | // handle error here
105 | return
106 | }
107 |
108 | try db.executeUpdate("INSERT INTO foo (bar) VALUES (?)", values: [1])
109 | try db.executeUpdate("INSERT INTO foo (bar) VALUES (?)", values: [2])
110 | } catch {
111 | rollback?.pointee = true
112 | }
113 | }
114 | ```
115 |
116 | Because FMDB 2.6 was not audited for nullability, Swift inferred that `db` and `rollback` were optionals. But, now, in FMDB 2.7, Swift now knows that, for example, neither `db` nor `rollback` above can be `nil`, so they are no longer optionals. Thus it becomes:
117 |
118 | ```swift
119 |
120 | let queue = FMDatabaseQueue(url: fileURL)
121 |
122 | queue.inTransaction { db, rollback in
123 | do {
124 | try db.executeUpdate("INSERT INTO foo (bar) VALUES (?)", values: [1])
125 | try db.executeUpdate("INSERT INTO foo (bar) VALUES (?)", values: [2])
126 | } catch {
127 | rollback.pointee = true
128 | }
129 | }
130 | ```
131 |
132 | ### Custom Functions
133 |
134 | In the past, when writing custom functions, you would have to generally include your own `@autoreleasepool` block to avoid problems when writing functions that scanned through a large table. Now, FMDB will automatically wrap it in an autorelease pool, so you don't have to.
135 |
136 | Also, in the past, when retrieving the values passed to the function, you had to drop down to the SQLite C API and include your own `sqlite3_value_XXX` calls. There are now `FMDatabase` methods, `valueInt`, `valueString`, etc., so you can stay within Swift and/or Objective-C, without needing to call the C functions yourself. Likewise, when specifying the return values, you no longer need to call `sqlite3_result_XXX` C API, but rather you can use `FMDatabase` methods, `resultInt`, `resultString`, etc. There is a new `enum` for `valueType` called `SqliteValueType`, which can be used for checking the type of parameter passed to the custom function.
137 |
138 | Thus, you can do something like (as of Swift 3):
139 |
140 | ```swift
141 | db.makeFunctionNamed("RemoveDiacritics", arguments: 1) { context, argc, argv in
142 | guard db.valueType(argv[0]) == .text || db.valueType(argv[0]) == .null else {
143 | db.resultError("Expected string parameter", context: context)
144 | return
145 | }
146 |
147 | if let string = db.valueString(argv[0])?.folding(options: .diacriticInsensitive, locale: nil) {
148 | db.resultString(string, context: context)
149 | } else {
150 | db.resultNull(context: context)
151 | }
152 | }
153 | ```
154 |
155 | And you can then use that function in your SQL (in this case, matching both "Jose" and "José"):
156 |
157 | ```sql
158 | SELECT * FROM employees WHERE RemoveDiacritics(first_name) LIKE 'jose'
159 | ```
160 |
161 | Note, the method `makeFunctionNamed:maximumArguments:withBlock:` has been renamed to `makeFunctionNamed:arguments:block:`, to more accurately reflect the functional intent of the second parameter.
162 |
163 | ### API Changes
164 |
165 | In addition to the `makeFunctionNamed` noted above, there are a few other API changes. Specifically,
166 |
167 | - To become consistent with the rest of the API, the methods `objectForColumnName` and `UTF8StringForColumnName` have been renamed to `objectForColumn` and `UTF8StringForColumn`.
168 |
169 | - Note, the `objectForColumn` (and the associted subscript operator) now returns `nil` if an invalid column name/index is passed to it. It used to return `NSNull`.
170 |
171 | - To avoid confusion with `FMDatabaseQueue` method `inTransaction`, which performs transactions, the `FMDatabase` method to determine whether you are in a transaction or not, `inTransaction`, has been replaced with a read-only property, `isInTransaction`.
172 |
173 | - Several functions have been converted to properties, namely, `databasePath`, `maxBusyRetryTimeInterval`, `shouldCacheStatements`, `sqliteHandle`, `hasOpenResultSets`, `lastInsertRowId`, `changes`, `goodConnection`, `columnCount`, `resultDictionary`, `applicationID`, `applicationIDString`, `userVersion`, `countOfCheckedInDatabases`, `countOfCheckedOutDatabases`, and `countOfOpenDatabases`. For Objective-C users, this has little material impact, but for Swift users, it results in a slightly more natural interface. Note: For Objective-C developers, previously versions of FMDB exposed many ivars (but we hope you weren't using them directly, anyway!), but the implmentation details for these are no longer exposed.
174 |
175 | ### URL Methods
176 |
177 | In keeping with Apple's shift from paths to URLs, there are now `NSURL` renditions of the various `init` methods, previously only accepting paths.
178 |
179 | ## Usage
180 | There are three main classes in FMDB:
181 |
182 | 1. `FMDatabase` - Represents a single SQLite database. Used for executing SQL statements.
183 | 2. `FMResultSet` - Represents the results of executing a query on an `FMDatabase`.
184 | 3. `FMDatabaseQueue` - If you're wanting to perform queries and updates on multiple threads, you'll want to use this class. It's described in the "Thread Safety" section below.
185 |
186 | ### Database Creation
187 | An `FMDatabase` is created with a path to a SQLite database file. This path can be one of these three:
188 |
189 | 1. A file system path. The file does not have to exist on disk. If it does not exist, it is created for you.
190 | 2. An empty string (`@""`). An empty database is created at a temporary location. This database is deleted with the `FMDatabase` connection is closed.
191 | 3. `NULL`. An in-memory database is created. This database will be destroyed with the `FMDatabase` connection is closed.
192 |
193 | (For more information on temporary and in-memory databases, read the sqlite documentation on the subject: http://www.sqlite.org/inmemorydb.html)
194 |
195 | ```objc
196 | NSString *path = [NSTemporaryDirectory() stringByAppendingPathComponent:@"tmp.db"];
197 | FMDatabase *db = [FMDatabase databaseWithPath:path];
198 | ```
199 |
200 | ### Opening
201 |
202 | Before you can interact with the database, it must be opened. Opening fails if there are insufficient resources or permissions to open and/or create the database.
203 |
204 | ```objc
205 | if (![db open]) {
206 | // [db release]; // uncomment this line in manual referencing code; in ARC, this is not necessary/permitted
207 | db = nil;
208 | return;
209 | }
210 | ```
211 |
212 | ### Executing Updates
213 |
214 | Any sort of SQL statement which is not a `SELECT` statement qualifies as an update. This includes `CREATE`, `UPDATE`, `INSERT`, `ALTER`, `COMMIT`, `BEGIN`, `DETACH`, `DELETE`, `DROP`, `END`, `EXPLAIN`, `VACUUM`, and `REPLACE` statements (plus many more). Basically, if your SQL statement does not begin with `SELECT`, it is an update statement.
215 |
216 | Executing updates returns a single value, a `BOOL`. A return value of `YES` means the update was successfully executed, and a return value of `NO` means that some error was encountered. You may invoke the `-lastErrorMessage` and `-lastErrorCode` methods to retrieve more information.
217 |
218 | ### Executing Queries
219 |
220 | A `SELECT` statement is a query and is executed via one of the `-executeQuery...` methods.
221 |
222 | Executing queries returns an `FMResultSet` object if successful, and `nil` upon failure. You should use the `-lastErrorMessage` and `-lastErrorCode` methods to determine why a query failed.
223 |
224 | In order to iterate through the results of your query, you use a `while()` loop. You also need to "step" from one record to the other. With FMDB, the easiest way to do that is like this:
225 |
226 | ```objc
227 | FMResultSet *s = [db executeQuery:@"SELECT * FROM myTable"];
228 | while ([s next]) {
229 | //retrieve values for each record
230 | }
231 | ```
232 |
233 | You must always invoke `-[FMResultSet next]` before attempting to access the values returned in a query, even if you're only expecting one:
234 |
235 | ```objc
236 | FMResultSet *s = [db executeQuery:@"SELECT COUNT(*) FROM myTable"];
237 | if ([s next]) {
238 | int totalCount = [s intForColumnIndex:0];
239 | }
240 | ```
241 |
242 | `FMResultSet` has many methods to retrieve data in an appropriate format:
243 |
244 | - `intForColumn:`
245 | - `longForColumn:`
246 | - `longLongIntForColumn:`
247 | - `boolForColumn:`
248 | - `doubleForColumn:`
249 | - `stringForColumn:`
250 | - `dateForColumn:`
251 | - `dataForColumn:`
252 | - `dataNoCopyForColumn:`
253 | - `UTF8StringForColumn:`
254 | - `objectForColumn:`
255 |
256 | Each of these methods also has a `{type}ForColumnIndex:` variant that is used to retrieve the data based on the position of the column in the results, as opposed to the column's name.
257 |
258 | Typically, there's no need to `-close` an `FMResultSet` yourself, since that happens when either the result set is deallocated, or the parent database is closed.
259 |
260 | ### Closing
261 |
262 | When you have finished executing queries and updates on the database, you should `-close` the `FMDatabase` connection so that SQLite will relinquish any resources it has acquired during the course of its operation.
263 |
264 | ```objc
265 | [db close];
266 | ```
267 |
268 | ### Transactions
269 |
270 | `FMDatabase` can begin and commit a transaction by invoking one of the appropriate methods or executing a begin/end transaction statement.
271 |
272 | ### Multiple Statements and Batch Stuff
273 |
274 | You can use `FMDatabase`'s executeStatements:withResultBlock: to do multiple statements in a string:
275 |
276 | ```objc
277 | NSString *sql = @"create table bulktest1 (id integer primary key autoincrement, x text);"
278 | "create table bulktest2 (id integer primary key autoincrement, y text);"
279 | "create table bulktest3 (id integer primary key autoincrement, z text);"
280 | "insert into bulktest1 (x) values ('XXX');"
281 | "insert into bulktest2 (y) values ('YYY');"
282 | "insert into bulktest3 (z) values ('ZZZ');";
283 |
284 | success = [db executeStatements:sql];
285 |
286 | sql = @"select count(*) as count from bulktest1;"
287 | "select count(*) as count from bulktest2;"
288 | "select count(*) as count from bulktest3;";
289 |
290 | success = [self.db executeStatements:sql withResultBlock:^int(NSDictionary *dictionary) {
291 | NSInteger count = [dictionary[@"count"] integerValue];
292 | XCTAssertEqual(count, 1, @"expected one record for dictionary %@", dictionary);
293 | return 0;
294 | }];
295 | ```
296 |
297 | ### Data Sanitization
298 |
299 | When providing a SQL statement to FMDB, you should not attempt to "sanitize" any values before insertion. Instead, you should use the standard SQLite binding syntax:
300 |
301 | ```sql
302 | INSERT INTO myTable VALUES (?, ?, ?, ?)
303 | ```
304 |
305 | The `?` character is recognized by SQLite as a placeholder for a value to be inserted. The execution methods all accept a variable number of arguments (or a representation of those arguments, such as an `NSArray`, `NSDictionary`, or a `va_list`), which are properly escaped for you.
306 |
307 | And, to use that SQL with the `?` placeholders from Objective-C:
308 |
309 | ```objc
310 | NSInteger identifier = 42;
311 | NSString *name = @"Liam O'Flaherty (\"the famous Irish author\")";
312 | NSDate *date = [NSDate date];
313 | NSString *comment = nil;
314 |
315 | BOOL success = [db executeUpdate:@"INSERT INTO authors (identifier, name, date, comment) VALUES (?, ?, ?, ?)", @(identifier), name, date, comment ?: [NSNull null]];
316 | if (!success) {
317 | NSLog(@"error = %@", [db lastErrorMessage]);
318 | }
319 | ```
320 |
321 | > **Note:** Fundamental data types, like the `NSInteger` variable `identifier`, should be as a `NSNumber` objects, achieved by using the `@` syntax, shown above. Or you can use the `[NSNumber numberWithInt:identifier]` syntax, too.
322 | >
323 | > Likewise, SQL `NULL` values should be inserted as `[NSNull null]`. For example, in the case of `comment` which might be `nil` (and is in this example), you can use the `comment ?: [NSNull null]` syntax, which will insert the string if `comment` is not `nil`, but will insert `[NSNull null]` if it is `nil`.
324 |
325 | In Swift, you would use `executeUpdate(values:)`, which not only is a concise Swift syntax, but also `throws` errors for proper error handling:
326 |
327 | ```swift
328 | do {
329 | let identifier = 42
330 | let name = "Liam O'Flaherty (\"the famous Irish author\")"
331 | let date = Date()
332 | let comment: String? = nil
333 |
334 | try db.executeUpdate("INSERT INTO authors (identifier, name, date, comment) VALUES (?, ?, ?, ?)", values: [identifier, name, date, comment ?? NSNull()])
335 | } catch {
336 | print("error = \(error)")
337 | }
338 | ```
339 |
340 | > **Note:** In Swift, you don't have to wrap fundamental numeric types like you do in Objective-C. But if you are going to insert an optional string, you would probably use the `comment ?? NSNull()` syntax (i.e., if it is `nil`, use `NSNull`, otherwise use the string).
341 |
342 | Alternatively, you may use named parameters syntax:
343 |
344 | ```sql
345 | INSERT INTO authors (identifier, name, date, comment) VALUES (:identifier, :name, :date, :comment)
346 | ```
347 |
348 | The parameters *must* start with a colon. SQLite itself supports other characters, but internally the dictionary keys are prefixed with a colon, do **not** include the colon in your dictionary keys.
349 |
350 | ```objc
351 | NSDictionary *arguments = @{@"identifier": @(identifier), @"name": name, @"date": date, @"comment": comment ?: [NSNull null]};
352 | BOOL success = [db executeUpdate:@"INSERT INTO authors (identifier, name, date, comment) VALUES (:identifier, :name, :date, :comment)" withParameterDictionary:arguments];
353 | if (!success) {
354 | NSLog(@"error = %@", [db lastErrorMessage]);
355 | }
356 | ```
357 |
358 | The key point is that one should not use `NSString` method `stringWithFormat` to manually insert values into the SQL statement, itself. Nor should one Swift string interpolation to insert values into the SQL. Use `?` placeholders for values to be inserted into the database (or used in `WHERE` clauses in `SELECT` statements).
359 |
360 |
Using FMDatabaseQueue and Thread Safety.
361 |
362 | Using a single instance of `FMDatabase` from multiple threads at once is a bad idea. It has always been OK to make a `FMDatabase` object *per thread*. Just don't share a single instance across threads, and definitely not across multiple threads at the same time. Bad things will eventually happen and you'll eventually get something to crash, or maybe get an exception, or maybe meteorites will fall out of the sky and hit your Mac Pro. *This would suck*.
363 |
364 | **So don't instantiate a single `FMDatabase` object and use it across multiple threads.**
365 |
366 | Instead, use `FMDatabaseQueue`. Instantiate a single `FMDatabaseQueue` and use it across multiple threads. The `FMDatabaseQueue` object will synchronize and coordinate access across the multiple threads. Here's how to use it:
367 |
368 | First, make your queue.
369 |
370 | ```objc
371 | FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:aPath];
372 | ```
373 |
374 | Then use it like so:
375 |
376 |
377 | ```objc
378 | [queue inDatabase:^(FMDatabase *db) {
379 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", @1];
380 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", @2];
381 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", @3];
382 |
383 | FMResultSet *rs = [db executeQuery:@"select * from foo"];
384 | while ([rs next]) {
385 | …
386 | }
387 | }];
388 | ```
389 |
390 | An easy way to wrap things up in a transaction can be done like this:
391 |
392 | ```objc
393 | [queue inTransaction:^(FMDatabase *db, BOOL *rollback) {
394 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", @1];
395 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", @2];
396 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", @3];
397 |
398 | if (whoopsSomethingWrongHappened) {
399 | *rollback = YES;
400 | return;
401 | }
402 |
403 | // etc ...
404 | }];
405 | ```
406 |
407 | The Swift equivalent would be:
408 |
409 | ```swift
410 | queue.inTransaction { db, rollback in
411 | do {
412 | try db.executeUpdate("INSERT INTO myTable VALUES (?)", values: [1])
413 | try db.executeUpdate("INSERT INTO myTable VALUES (?)", values: [2])
414 | try db.executeUpdate("INSERT INTO myTable VALUES (?)", values: [3])
415 |
416 | if whoopsSomethingWrongHappened {
417 | rollback.pointee = true
418 | return
419 | }
420 |
421 | // etc ...
422 | } catch {
423 | rollback.pointee = true
424 | print(error)
425 | }
426 | }
427 | ```
428 |
429 | (Note, as of Swift 3, use `pointee`. But in Swift 2.3, use `memory` rather than `pointee`.)
430 |
431 | `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.
432 |
433 | **Note:** The calls to `FMDatabaseQueue`'s methods are blocking. So even though you are passing along blocks, they will **not** be run on another thread.
434 |
435 | ## Making custom sqlite functions, based on blocks.
436 |
437 | You can do this! For an example, look for `-makeFunctionNamed:` in main.m
438 |
439 | ## Swift
440 |
441 | You can use FMDB in Swift projects too.
442 |
443 | To do this, you must:
444 |
445 | 1. Copy the relevant `.m` and `.h` files from the FMDB `src` folder into your project.
446 |
447 | You can copy all of them (which is easiest), or only the ones you need. Likely you will need [`FMDatabase`](http://ccgus.github.io/fmdb/html/Classes/FMDatabase.html) and [`FMResultSet`](http://ccgus.github.io/fmdb/html/Classes/FMResultSet.html) at a minimum. [`FMDatabaseAdditions`](http://ccgus.github.io/fmdb/html/Categories/FMDatabase+FMDatabaseAdditions.html) provides some very useful convenience methods, so you will likely want that, too. If you are doing multithreaded access to a database, [`FMDatabaseQueue`](http://ccgus.github.io/fmdb/html/Classes/FMDatabaseQueue.html) is quite useful, too. If you choose to not copy all of the files from the `src` directory, though, you may want to update `FMDB.h` to only reference the files that you included in your project.
448 |
449 | Note, if you're copying all of the files from the `src` folder into to your project (which is recommended), you may want to drag the individual files into your project, not the folder, itself, because if you drag the folder, you won't be prompted to add the bridging header (see next point).
450 |
451 | 2. If prompted to create a "bridging header", you should do so. If not prompted and if you don't already have a bridging header, add one.
452 |
453 | For more information on bridging headers, see [Swift and Objective-C in the Same Project](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html#//apple_ref/doc/uid/TP40014216-CH10-XID_76).
454 |
455 | 3. In your bridging header, add a line that says:
456 | ```objc
457 | #import "FMDB.h"
458 | ```
459 |
460 | 4. Use the variations of `executeQuery` and `executeUpdate` with the `sql` and `values` parameters with `try` pattern, as shown below. These renditions of `executeQuery` and `executeUpdate` both `throw` errors in true Swift fashion.
461 |
462 | If you do the above, you can then write Swift code that uses `FMDatabase`. For example, as of Swift 3:
463 |
464 | ```swift
465 | let fileURL = try! FileManager.default
466 | .url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
467 | .appendingPathComponent("test.sqlite")
468 |
469 | let database = FMDatabase(url: fileURL)
470 |
471 | guard database.open() else {
472 | print("Unable to open database")
473 | return
474 | }
475 |
476 | do {
477 | try database.executeUpdate("create table test(x text, y text, z text)", values: nil)
478 | try database.executeUpdate("insert into test (x, y, z) values (?, ?, ?)", values: ["a", "b", "c"])
479 | try database.executeUpdate("insert into test (x, y, z) values (?, ?, ?)", values: ["e", "f", "g"])
480 |
481 | let rs = try database.executeQuery("select x, y, z from test", values: nil)
482 | while rs.next() {
483 | if let x = rs.string(forColumn: "x"), let y = rs.string(forColumn: "y"), let z = rs.string(forColumn: "z") {
484 | print("x = \(x); y = \(y); z = \(z)")
485 | }
486 | }
487 | } catch {
488 | print("failed: \(error.localizedDescription)")
489 | }
490 |
491 | database.close()
492 | ```
493 |
494 | ## History
495 |
496 | The history and changes are availbe on its [GitHub page](https://github.com/ccgus/fmdb) and are summarized in the "CHANGES_AND_TODO_LIST.txt" file.
497 |
498 | ## Contributors
499 |
500 | The contributors to FMDB are contained in the "Contributors.txt" file.
501 |
502 | ## Additional projects using FMDB, which might be interesting to the discerning developer.
503 |
504 | * FMDBMigrationManager, A SQLite schema migration management system for FMDB: https://github.com/layerhq/FMDBMigrationManager
505 | * FCModel, An alternative to Core Data for people who like having direct SQL access: https://github.com/marcoarment/FCModel
506 |
507 | ## Quick notes on FMDB's coding style
508 |
509 | Spaces, not tabs. Square brackets, not dot notation. Look at what FMDB already does with curly brackets and such, and stick to that style.
510 |
511 | ## Reporting bugs
512 |
513 | Reduce your bug down to the smallest amount of code possible. You want to make it super easy for the developers to see and reproduce your bug. If it helps, pretend that the person who can fix your bug is active on shipping 3 major products, works on a handful of open source projects, has a newborn baby, and is generally very very busy.
514 |
515 | And we've even added a template function to main.m (FMDBReportABugFunction) in the FMDB distribution to help you out:
516 |
517 | * Open up fmdb project in Xcode.
518 | * Open up main.m and modify the FMDBReportABugFunction to reproduce your bug.
519 | * Setup your table(s) in the code.
520 | * Make your query or update(s).
521 | * Add some assertions which demonstrate the bug.
522 |
523 | Then you can bring it up on the FMDB mailing list by showing your nice and compact FMDBReportABugFunction, or you can report the bug via the github FMDB bug reporter.
524 |
525 | **Optional:**
526 |
527 | Figure out where the bug is, fix it, and send a patch in or bring that up on the mailing list. Make sure all the other tests run after your modifications.
528 |
529 | ## Support
530 |
531 | The support channels for FMDB are the mailing list (see above), filing a bug here, or maybe on Stack Overflow. So that is to say, support is provided by the community and on a voluntary basis.
532 |
533 | FMDB development is overseen by Gus Mueller of Flying Meat. If FMDB been helpful to you, consider purchasing an app from FM or telling all your friends about it.
534 |
535 | ## License
536 |
537 | The license for FMDB is contained in the "License.txt" file.
538 |
539 | If you happen to come across either Gus Mueller or Rob Ryan in a bar, you might consider purchasing a drink of their choosing if FMDB has been useful to you.
540 |
541 | (The drink is for them of course, shame on you for trying to keep it.)
542 |
--------------------------------------------------------------------------------
/Pods/FMDB/src/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 |
--------------------------------------------------------------------------------
/Pods/FMDB/src/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 |
--------------------------------------------------------------------------------
/Pods/FMDB/src/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 |
--------------------------------------------------------------------------------
/Pods/FMDB/src/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 |
--------------------------------------------------------------------------------
/Pods/FMDB/src/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 |
--------------------------------------------------------------------------------
/Pods/FMDB/src/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 |
--------------------------------------------------------------------------------
/Pods/FMDB/src/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 |
--------------------------------------------------------------------------------
/Pods/FMDB/src/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 |
--------------------------------------------------------------------------------
/Pods/FMDB/src/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 |
--------------------------------------------------------------------------------
/Pods/Headers/Private/FMDB/FMDB.h:
--------------------------------------------------------------------------------
1 | ../../../FMDB/src/fmdb/FMDB.h
--------------------------------------------------------------------------------
/Pods/Headers/Private/FMDB/FMDatabase.h:
--------------------------------------------------------------------------------
1 | ../../../FMDB/src/fmdb/FMDatabase.h
--------------------------------------------------------------------------------
/Pods/Headers/Private/FMDB/FMDatabaseAdditions.h:
--------------------------------------------------------------------------------
1 | ../../../FMDB/src/fmdb/FMDatabaseAdditions.h
--------------------------------------------------------------------------------
/Pods/Headers/Private/FMDB/FMDatabasePool.h:
--------------------------------------------------------------------------------
1 | ../../../FMDB/src/fmdb/FMDatabasePool.h
--------------------------------------------------------------------------------
/Pods/Headers/Private/FMDB/FMDatabaseQueue.h:
--------------------------------------------------------------------------------
1 | ../../../FMDB/src/fmdb/FMDatabaseQueue.h
--------------------------------------------------------------------------------
/Pods/Headers/Private/FMDB/FMResultSet.h:
--------------------------------------------------------------------------------
1 | ../../../FMDB/src/fmdb/FMResultSet.h
--------------------------------------------------------------------------------
/Pods/Headers/Public/FMDB/FMDB.h:
--------------------------------------------------------------------------------
1 | ../../../FMDB/src/fmdb/FMDB.h
--------------------------------------------------------------------------------
/Pods/Headers/Public/FMDB/FMDatabase.h:
--------------------------------------------------------------------------------
1 | ../../../FMDB/src/fmdb/FMDatabase.h
--------------------------------------------------------------------------------
/Pods/Headers/Public/FMDB/FMDatabaseAdditions.h:
--------------------------------------------------------------------------------
1 | ../../../FMDB/src/fmdb/FMDatabaseAdditions.h
--------------------------------------------------------------------------------
/Pods/Headers/Public/FMDB/FMDatabasePool.h:
--------------------------------------------------------------------------------
1 | ../../../FMDB/src/fmdb/FMDatabasePool.h
--------------------------------------------------------------------------------
/Pods/Headers/Public/FMDB/FMDatabaseQueue.h:
--------------------------------------------------------------------------------
1 | ../../../FMDB/src/fmdb/FMDatabaseQueue.h
--------------------------------------------------------------------------------
/Pods/Headers/Public/FMDB/FMResultSet.h:
--------------------------------------------------------------------------------
1 | ../../../FMDB/src/fmdb/FMResultSet.h
--------------------------------------------------------------------------------
/Pods/Manifest.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - FMDB (2.7.2):
3 | - FMDB/standard (= 2.7.2)
4 | - FMDB/standard (2.7.2)
5 |
6 | DEPENDENCIES:
7 | - FMDB
8 |
9 | SPEC CHECKSUMS:
10 | FMDB: 6198a90e7b6900cfc046e6bc0ef6ebb7be9236aa
11 |
12 | PODFILE CHECKSUM: 784b79b502ce23f1b3d906b095721a12c1affe55
13 |
14 | COCOAPODS: 1.2.1
15 |
--------------------------------------------------------------------------------
/Pods/Pods.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 48;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 0E87507BC811EF557551A30C06652274 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 270DD1219F1E6CF00379D39F252D87C6 /* Cocoa.framework */; };
11 | 2012864C735C3DD88ECE425F6C981F6B /* FMDatabasePool.h in Headers */ = {isa = PBXBuildFile; fileRef = 1AF3AEDDA16DD8E28B59FF0788FDDC03 /* FMDatabasePool.h */; settings = {ATTRIBUTES = (Public, ); }; };
12 | 398A5C11EFB816892FD5E18AD24F03D4 /* FMResultSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 69CC8B63F837EA7B053AB8BA07253A25 /* FMResultSet.h */; settings = {ATTRIBUTES = (Public, ); }; };
13 | 4B3B2EABA01FE0065CA6693CEE33CA92 /* FMResultSet.m in Sources */ = {isa = PBXBuildFile; fileRef = 71B69D4A7150AC2F65A57B7D04F092D4 /* FMResultSet.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; };
14 | 4CFC810CEB4E6310064E79583ADFE117 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 270DD1219F1E6CF00379D39F252D87C6 /* Cocoa.framework */; };
15 | 4DB541C1C41B1C597EC36CDAB5243D1A /* FMDatabaseAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 3BCC0EED53ED8D7C1931178E0E4269B4 /* FMDatabaseAdditions.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; };
16 | 6199817CB29DADBC9AB1D4C44E52F5BA /* FMDatabase.m in Sources */ = {isa = PBXBuildFile; fileRef = DC7C30F9E55829B027C4913D1F19D68C /* FMDatabase.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; };
17 | 6B068984D1221265BD950F8B6FB002F9 /* Pods-WebCrawler-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = C3F7A9DFE0C4627AC4BA1DF608F7A0D2 /* Pods-WebCrawler-dummy.m */; };
18 | 8021697A1557D425AC130472DA1317CC /* FMDatabasePool.m in Sources */ = {isa = PBXBuildFile; fileRef = 400AFB42920EB39709666D3F1A73D6C2 /* FMDatabasePool.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; };
19 | 889D48A9B81ADF617C1D4E4E9473E3A9 /* FMDB.h in Headers */ = {isa = PBXBuildFile; fileRef = 91893D40185E0EFA40FC217BE44A7C0D /* FMDB.h */; settings = {ATTRIBUTES = (Public, ); }; };
20 | 98ABF277A45F1AB72A8D02D53FFE67BF /* FMDatabaseQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = C11A8F38580C7A7FF38ACB6A3B412884 /* FMDatabaseQueue.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; };
21 | 99714143FA44A34F87D1F2AA6D254177 /* FMDatabaseQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 33F15B71183AD666DFC49D907F769ACF /* FMDatabaseQueue.h */; settings = {ATTRIBUTES = (Public, ); }; };
22 | C40CFE1274D588CA1A9DF9394BF76EAE /* FMDB-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 6D76813CB39ACC402A9EE3DC12B4E682 /* FMDB-dummy.m */; };
23 | D852415DFD46E85C293E0DDE01868EA2 /* FMDatabase.h in Headers */ = {isa = PBXBuildFile; fileRef = 638E465E4B27490B0FB423614C3ADD11 /* FMDatabase.h */; settings = {ATTRIBUTES = (Public, ); }; };
24 | F00CCFAB93A4F18419CD91217B1D5F66 /* FMDatabaseAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = D2DD52CB174E1DC79111C38E770F6FC8 /* FMDatabaseAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; };
25 | /* End PBXBuildFile section */
26 |
27 | /* Begin PBXContainerItemProxy section */
28 | 969B55CA1854D252C04254C3166BA8F1 /* PBXContainerItemProxy */ = {
29 | isa = PBXContainerItemProxy;
30 | containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */;
31 | proxyType = 1;
32 | remoteGlobalIDString = 8642CC820CE8C5B88C113D7F47AF4BC3;
33 | remoteInfo = FMDB;
34 | };
35 | /* End PBXContainerItemProxy section */
36 |
37 | /* Begin PBXFileReference section */
38 | 1AA3C14CF426B6CBCA80882E599974EC /* Pods-WebCrawler.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-WebCrawler.debug.xcconfig"; sourceTree = ""; };
39 | 1AF3AEDDA16DD8E28B59FF0788FDDC03 /* FMDatabasePool.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FMDatabasePool.h; path = src/fmdb/FMDatabasePool.h; sourceTree = ""; };
40 | 270DD1219F1E6CF00379D39F252D87C6 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/System/Library/Frameworks/Cocoa.framework; sourceTree = DEVELOPER_DIR; };
41 | 33F15B71183AD666DFC49D907F769ACF /* FMDatabaseQueue.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FMDatabaseQueue.h; path = src/fmdb/FMDatabaseQueue.h; sourceTree = ""; };
42 | 38A0100ABA506C00D0455583C6EB4CDC /* libFMDB.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; name = libFMDB.a; path = libFMDB.a; sourceTree = BUILT_PRODUCTS_DIR; };
43 | 3BCC0EED53ED8D7C1931178E0E4269B4 /* FMDatabaseAdditions.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FMDatabaseAdditions.m; path = src/fmdb/FMDatabaseAdditions.m; sourceTree = ""; };
44 | 3E5CD9656810C066589D6EF2524F59D0 /* Pods-WebCrawler.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-WebCrawler.release.xcconfig"; sourceTree = ""; };
45 | 400AFB42920EB39709666D3F1A73D6C2 /* FMDatabasePool.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FMDatabasePool.m; path = src/fmdb/FMDatabasePool.m; sourceTree = ""; };
46 | 638E465E4B27490B0FB423614C3ADD11 /* FMDatabase.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FMDatabase.h; path = src/fmdb/FMDatabase.h; sourceTree = ""; };
47 | 69CC8B63F837EA7B053AB8BA07253A25 /* FMResultSet.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FMResultSet.h; path = src/fmdb/FMResultSet.h; sourceTree = ""; };
48 | 6D76813CB39ACC402A9EE3DC12B4E682 /* FMDB-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "FMDB-dummy.m"; sourceTree = ""; };
49 | 71B69D4A7150AC2F65A57B7D04F092D4 /* FMResultSet.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FMResultSet.m; path = src/fmdb/FMResultSet.m; sourceTree = ""; };
50 | 91893D40185E0EFA40FC217BE44A7C0D /* FMDB.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FMDB.h; path = src/fmdb/FMDB.h; sourceTree = ""; };
51 | 93A4A3777CF96A4AAC1D13BA6DCCEA73 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; lastKnownFileType = text; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; xcLanguageSpecificationIdentifier = xcode.lang.ruby; };
52 | 9825149996E578654D83F000F8E06A4B /* Pods-WebCrawler-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-WebCrawler-frameworks.sh"; sourceTree = ""; };
53 | A1448204AE8E2DC37C8C36438BED7AD8 /* FMDB-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "FMDB-prefix.pch"; sourceTree = ""; };
54 | A18E276F288118D52C75B329A7981DC9 /* libPods-WebCrawler.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; name = "libPods-WebCrawler.a"; path = "libPods-WebCrawler.a"; sourceTree = BUILT_PRODUCTS_DIR; };
55 | A55180D3816CB80932CE80F193361FD7 /* Pods-WebCrawler-resources.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-WebCrawler-resources.sh"; sourceTree = ""; };
56 | B2AC8D08AB9E95E701EC049C53414AEB /* FMDB.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = FMDB.xcconfig; sourceTree = ""; };
57 | BEE65713320B22B65C5DBF872486201B /* Pods-WebCrawler-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-WebCrawler-acknowledgements.plist"; sourceTree = ""; };
58 | C11A8F38580C7A7FF38ACB6A3B412884 /* FMDatabaseQueue.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FMDatabaseQueue.m; path = src/fmdb/FMDatabaseQueue.m; sourceTree = ""; };
59 | C3F7A9DFE0C4627AC4BA1DF608F7A0D2 /* Pods-WebCrawler-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-WebCrawler-dummy.m"; sourceTree = ""; };
60 | D2DD52CB174E1DC79111C38E770F6FC8 /* FMDatabaseAdditions.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FMDatabaseAdditions.h; path = src/fmdb/FMDatabaseAdditions.h; sourceTree = ""; };
61 | DC7C30F9E55829B027C4913D1F19D68C /* FMDatabase.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FMDatabase.m; path = src/fmdb/FMDatabase.m; sourceTree = ""; };
62 | FAE3065565639139E260F66EE0AF86AF /* Pods-WebCrawler-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-WebCrawler-acknowledgements.markdown"; sourceTree = ""; };
63 | /* End PBXFileReference section */
64 |
65 | /* Begin PBXFrameworksBuildPhase section */
66 | 4EF77C58D8635373393E889341E8FB33 /* Frameworks */ = {
67 | isa = PBXFrameworksBuildPhase;
68 | buildActionMask = 2147483647;
69 | files = (
70 | 4CFC810CEB4E6310064E79583ADFE117 /* Cocoa.framework in Frameworks */,
71 | );
72 | runOnlyForDeploymentPostprocessing = 0;
73 | };
74 | 6F5C24339975CB7ADAC01EA3CA998D81 /* Frameworks */ = {
75 | isa = PBXFrameworksBuildPhase;
76 | buildActionMask = 2147483647;
77 | files = (
78 | 0E87507BC811EF557551A30C06652274 /* Cocoa.framework in Frameworks */,
79 | );
80 | runOnlyForDeploymentPostprocessing = 0;
81 | };
82 | /* End PBXFrameworksBuildPhase section */
83 |
84 | /* Begin PBXGroup section */
85 | 04C068A18C5413F804A2959126093416 /* OS X */ = {
86 | isa = PBXGroup;
87 | children = (
88 | 270DD1219F1E6CF00379D39F252D87C6 /* Cocoa.framework */,
89 | );
90 | name = "OS X";
91 | sourceTree = "";
92 | };
93 | 2030CEEA188BE47B15B065303A6F9025 /* Pods-WebCrawler */ = {
94 | isa = PBXGroup;
95 | children = (
96 | FAE3065565639139E260F66EE0AF86AF /* Pods-WebCrawler-acknowledgements.markdown */,
97 | BEE65713320B22B65C5DBF872486201B /* Pods-WebCrawler-acknowledgements.plist */,
98 | C3F7A9DFE0C4627AC4BA1DF608F7A0D2 /* Pods-WebCrawler-dummy.m */,
99 | 9825149996E578654D83F000F8E06A4B /* Pods-WebCrawler-frameworks.sh */,
100 | A55180D3816CB80932CE80F193361FD7 /* Pods-WebCrawler-resources.sh */,
101 | 1AA3C14CF426B6CBCA80882E599974EC /* Pods-WebCrawler.debug.xcconfig */,
102 | 3E5CD9656810C066589D6EF2524F59D0 /* Pods-WebCrawler.release.xcconfig */,
103 | );
104 | name = "Pods-WebCrawler";
105 | path = "Target Support Files/Pods-WebCrawler";
106 | sourceTree = "";
107 | };
108 | 39E9EE8210D861DFD82346C1F5EB7218 /* Frameworks */ = {
109 | isa = PBXGroup;
110 | children = (
111 | 04C068A18C5413F804A2959126093416 /* OS X */,
112 | );
113 | name = Frameworks;
114 | sourceTree = "";
115 | };
116 | 6A65CEB166911CC900621A37BC272B1F /* Support Files */ = {
117 | isa = PBXGroup;
118 | children = (
119 | B2AC8D08AB9E95E701EC049C53414AEB /* FMDB.xcconfig */,
120 | 6D76813CB39ACC402A9EE3DC12B4E682 /* FMDB-dummy.m */,
121 | A1448204AE8E2DC37C8C36438BED7AD8 /* FMDB-prefix.pch */,
122 | );
123 | name = "Support Files";
124 | path = "../Target Support Files/FMDB";
125 | sourceTree = "";
126 | };
127 | 7DB346D0F39D3F0E887471402A8071AB = {
128 | isa = PBXGroup;
129 | children = (
130 | 93A4A3777CF96A4AAC1D13BA6DCCEA73 /* Podfile */,
131 | 39E9EE8210D861DFD82346C1F5EB7218 /* Frameworks */,
132 | BFB8C92E749ED180124155E2270474D2 /* Pods */,
133 | 823FCA565FD8AB16E2EDC4068157A09E /* Products */,
134 | ADF2CE7CDBC908DAB62F45D0CE1EEE2E /* Targets Support Files */,
135 | );
136 | sourceTree = "";
137 | };
138 | 823FCA565FD8AB16E2EDC4068157A09E /* Products */ = {
139 | isa = PBXGroup;
140 | children = (
141 | 38A0100ABA506C00D0455583C6EB4CDC /* libFMDB.a */,
142 | A18E276F288118D52C75B329A7981DC9 /* libPods-WebCrawler.a */,
143 | );
144 | name = Products;
145 | sourceTree = "";
146 | };
147 | ADF2CE7CDBC908DAB62F45D0CE1EEE2E /* Targets Support Files */ = {
148 | isa = PBXGroup;
149 | children = (
150 | 2030CEEA188BE47B15B065303A6F9025 /* Pods-WebCrawler */,
151 | );
152 | name = "Targets Support Files";
153 | sourceTree = "";
154 | };
155 | BFB8C92E749ED180124155E2270474D2 /* Pods */ = {
156 | isa = PBXGroup;
157 | children = (
158 | DEA37EDFE575D4B41E183255F5C2B8C8 /* FMDB */,
159 | );
160 | name = Pods;
161 | sourceTree = "";
162 | };
163 | C89A6930D6DE6039F840782BFE7A2DFB /* standard */ = {
164 | isa = PBXGroup;
165 | children = (
166 | 638E465E4B27490B0FB423614C3ADD11 /* FMDatabase.h */,
167 | DC7C30F9E55829B027C4913D1F19D68C /* FMDatabase.m */,
168 | D2DD52CB174E1DC79111C38E770F6FC8 /* FMDatabaseAdditions.h */,
169 | 3BCC0EED53ED8D7C1931178E0E4269B4 /* FMDatabaseAdditions.m */,
170 | 1AF3AEDDA16DD8E28B59FF0788FDDC03 /* FMDatabasePool.h */,
171 | 400AFB42920EB39709666D3F1A73D6C2 /* FMDatabasePool.m */,
172 | 33F15B71183AD666DFC49D907F769ACF /* FMDatabaseQueue.h */,
173 | C11A8F38580C7A7FF38ACB6A3B412884 /* FMDatabaseQueue.m */,
174 | 91893D40185E0EFA40FC217BE44A7C0D /* FMDB.h */,
175 | 69CC8B63F837EA7B053AB8BA07253A25 /* FMResultSet.h */,
176 | 71B69D4A7150AC2F65A57B7D04F092D4 /* FMResultSet.m */,
177 | );
178 | name = standard;
179 | sourceTree = "";
180 | };
181 | DEA37EDFE575D4B41E183255F5C2B8C8 /* FMDB */ = {
182 | isa = PBXGroup;
183 | children = (
184 | C89A6930D6DE6039F840782BFE7A2DFB /* standard */,
185 | 6A65CEB166911CC900621A37BC272B1F /* Support Files */,
186 | );
187 | name = FMDB;
188 | path = FMDB;
189 | sourceTree = "";
190 | };
191 | /* End PBXGroup section */
192 |
193 | /* Begin PBXHeadersBuildPhase section */
194 | A93D3ABB603D66C647446B37AA29FE64 /* Headers */ = {
195 | isa = PBXHeadersBuildPhase;
196 | buildActionMask = 2147483647;
197 | files = (
198 | D852415DFD46E85C293E0DDE01868EA2 /* FMDatabase.h in Headers */,
199 | F00CCFAB93A4F18419CD91217B1D5F66 /* FMDatabaseAdditions.h in Headers */,
200 | 2012864C735C3DD88ECE425F6C981F6B /* FMDatabasePool.h in Headers */,
201 | 99714143FA44A34F87D1F2AA6D254177 /* FMDatabaseQueue.h in Headers */,
202 | 889D48A9B81ADF617C1D4E4E9473E3A9 /* FMDB.h in Headers */,
203 | 398A5C11EFB816892FD5E18AD24F03D4 /* FMResultSet.h in Headers */,
204 | );
205 | runOnlyForDeploymentPostprocessing = 0;
206 | };
207 | /* End PBXHeadersBuildPhase section */
208 |
209 | /* Begin PBXNativeTarget section */
210 | 0270857B53A224205FFE0FDAAD06B8AD /* Pods-WebCrawler */ = {
211 | isa = PBXNativeTarget;
212 | buildConfigurationList = A14299E1CA843097101C450F65C8E435 /* Build configuration list for PBXNativeTarget "Pods-WebCrawler" */;
213 | buildPhases = (
214 | CEBC90CCAE85788A2E9674AD7D4F222C /* Sources */,
215 | 6F5C24339975CB7ADAC01EA3CA998D81 /* Frameworks */,
216 | );
217 | buildRules = (
218 | );
219 | dependencies = (
220 | 59D617A52F5F5E05B6AF7C55E3729066 /* PBXTargetDependency */,
221 | );
222 | name = "Pods-WebCrawler";
223 | productName = "Pods-WebCrawler";
224 | productReference = A18E276F288118D52C75B329A7981DC9 /* libPods-WebCrawler.a */;
225 | productType = "com.apple.product-type.library.static";
226 | };
227 | 8642CC820CE8C5B88C113D7F47AF4BC3 /* FMDB */ = {
228 | isa = PBXNativeTarget;
229 | buildConfigurationList = 1BA066B3D32C553BF37E3322F9113F02 /* Build configuration list for PBXNativeTarget "FMDB" */;
230 | buildPhases = (
231 | ADE36E87832B736E1FAF9E50036C1530 /* Sources */,
232 | 4EF77C58D8635373393E889341E8FB33 /* Frameworks */,
233 | A93D3ABB603D66C647446B37AA29FE64 /* Headers */,
234 | );
235 | buildRules = (
236 | );
237 | dependencies = (
238 | );
239 | name = FMDB;
240 | productName = FMDB;
241 | productReference = 38A0100ABA506C00D0455583C6EB4CDC /* libFMDB.a */;
242 | productType = "com.apple.product-type.library.static";
243 | };
244 | /* End PBXNativeTarget section */
245 |
246 | /* Begin PBXProject section */
247 | D41D8CD98F00B204E9800998ECF8427E /* Project object */ = {
248 | isa = PBXProject;
249 | attributes = {
250 | LastSwiftUpdateCheck = 0830;
251 | LastUpgradeCheck = 0700;
252 | };
253 | buildConfigurationList = 2D8E8EC45A3A1A1D94AE762CB5028504 /* Build configuration list for PBXProject "Pods" */;
254 | compatibilityVersion = "Xcode 3.2";
255 | developmentRegion = English;
256 | hasScannedForEncodings = 0;
257 | knownRegions = (
258 | en,
259 | );
260 | mainGroup = 7DB346D0F39D3F0E887471402A8071AB;
261 | productRefGroup = 823FCA565FD8AB16E2EDC4068157A09E /* Products */;
262 | projectDirPath = "";
263 | projectRoot = "";
264 | targets = (
265 | 8642CC820CE8C5B88C113D7F47AF4BC3 /* FMDB */,
266 | 0270857B53A224205FFE0FDAAD06B8AD /* Pods-WebCrawler */,
267 | );
268 | };
269 | /* End PBXProject section */
270 |
271 | /* Begin PBXSourcesBuildPhase section */
272 | ADE36E87832B736E1FAF9E50036C1530 /* Sources */ = {
273 | isa = PBXSourcesBuildPhase;
274 | buildActionMask = 2147483647;
275 | files = (
276 | 6199817CB29DADBC9AB1D4C44E52F5BA /* FMDatabase.m in Sources */,
277 | 4DB541C1C41B1C597EC36CDAB5243D1A /* FMDatabaseAdditions.m in Sources */,
278 | 8021697A1557D425AC130472DA1317CC /* FMDatabasePool.m in Sources */,
279 | 98ABF277A45F1AB72A8D02D53FFE67BF /* FMDatabaseQueue.m in Sources */,
280 | C40CFE1274D588CA1A9DF9394BF76EAE /* FMDB-dummy.m in Sources */,
281 | 4B3B2EABA01FE0065CA6693CEE33CA92 /* FMResultSet.m in Sources */,
282 | );
283 | runOnlyForDeploymentPostprocessing = 0;
284 | };
285 | CEBC90CCAE85788A2E9674AD7D4F222C /* Sources */ = {
286 | isa = PBXSourcesBuildPhase;
287 | buildActionMask = 2147483647;
288 | files = (
289 | 6B068984D1221265BD950F8B6FB002F9 /* Pods-WebCrawler-dummy.m in Sources */,
290 | );
291 | runOnlyForDeploymentPostprocessing = 0;
292 | };
293 | /* End PBXSourcesBuildPhase section */
294 |
295 | /* Begin PBXTargetDependency section */
296 | 59D617A52F5F5E05B6AF7C55E3729066 /* PBXTargetDependency */ = {
297 | isa = PBXTargetDependency;
298 | name = FMDB;
299 | target = 8642CC820CE8C5B88C113D7F47AF4BC3 /* FMDB */;
300 | targetProxy = 969B55CA1854D252C04254C3166BA8F1 /* PBXContainerItemProxy */;
301 | };
302 | /* End PBXTargetDependency section */
303 |
304 | /* Begin XCBuildConfiguration section */
305 | 0FCC01CFB467D325132CE2B1625B2AD8 /* Release */ = {
306 | isa = XCBuildConfiguration;
307 | baseConfigurationReference = B2AC8D08AB9E95E701EC049C53414AEB /* FMDB.xcconfig */;
308 | buildSettings = {
309 | CODE_SIGN_IDENTITY = "-";
310 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
311 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
312 | "CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
313 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
314 | ENABLE_STRICT_OBJC_MSGSEND = YES;
315 | EXECUTABLE_PREFIX = lib;
316 | GCC_NO_COMMON_BLOCKS = YES;
317 | GCC_PREFIX_HEADER = "Target Support Files/FMDB/FMDB-prefix.pch";
318 | MACOSX_DEPLOYMENT_TARGET = 10.6;
319 | MTL_ENABLE_DEBUG_INFO = NO;
320 | OTHER_LDFLAGS = "";
321 | OTHER_LIBTOOLFLAGS = "";
322 | PRIVATE_HEADERS_FOLDER_PATH = "";
323 | PRODUCT_NAME = "$(TARGET_NAME)";
324 | PUBLIC_HEADERS_FOLDER_PATH = "";
325 | SDKROOT = macosx;
326 | };
327 | name = Release;
328 | };
329 | 337AD37B27D7FFADF01DD8D7FE35B27B /* Debug */ = {
330 | isa = XCBuildConfiguration;
331 | buildSettings = {
332 | ALWAYS_SEARCH_USER_PATHS = NO;
333 | CLANG_ANALYZER_NONNULL = YES;
334 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES;
335 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
336 | CLANG_CXX_LIBRARY = "libc++";
337 | CLANG_ENABLE_MODULES = YES;
338 | CLANG_ENABLE_OBJC_ARC = YES;
339 | CLANG_WARN_BOOL_CONVERSION = YES;
340 | CLANG_WARN_CONSTANT_CONVERSION = YES;
341 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES;
342 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
343 | CLANG_WARN_EMPTY_BODY = YES;
344 | CLANG_WARN_ENUM_CONVERSION = YES;
345 | CLANG_WARN_INFINITE_RECURSION = YES;
346 | CLANG_WARN_INT_CONVERSION = YES;
347 | CLANG_WARN_OBJC_ROOT_CLASS = YES;
348 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
349 | CLANG_WARN_UNREACHABLE_CODE = YES;
350 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
351 | CODE_SIGNING_REQUIRED = NO;
352 | COPY_PHASE_STRIP = NO;
353 | ENABLE_TESTABILITY = YES;
354 | GCC_C_LANGUAGE_STANDARD = gnu99;
355 | GCC_DYNAMIC_NO_PIC = NO;
356 | GCC_OPTIMIZATION_LEVEL = 0;
357 | GCC_PREPROCESSOR_DEFINITIONS = (
358 | "POD_CONFIGURATION_DEBUG=1",
359 | "DEBUG=1",
360 | "$(inherited)",
361 | );
362 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
363 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
364 | GCC_WARN_ABOUT_RETURN_TYPE = YES;
365 | GCC_WARN_UNDECLARED_SELECTOR = YES;
366 | GCC_WARN_UNINITIALIZED_AUTOS = YES;
367 | GCC_WARN_UNUSED_FUNCTION = YES;
368 | GCC_WARN_UNUSED_VARIABLE = YES;
369 | MACOSX_DEPLOYMENT_TARGET = 10.12;
370 | ONLY_ACTIVE_ARCH = YES;
371 | PROVISIONING_PROFILE_SPECIFIER = NO_SIGNING/;
372 | STRIP_INSTALLED_PRODUCT = NO;
373 | SYMROOT = "${SRCROOT}/../build";
374 | };
375 | name = Debug;
376 | };
377 | AB23868CFB749E906FB18729BC78E5FB /* Debug */ = {
378 | isa = XCBuildConfiguration;
379 | baseConfigurationReference = 1AA3C14CF426B6CBCA80882E599974EC /* Pods-WebCrawler.debug.xcconfig */;
380 | buildSettings = {
381 | CODE_SIGN_IDENTITY = "-";
382 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
383 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
384 | "CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
385 | DEBUG_INFORMATION_FORMAT = dwarf;
386 | ENABLE_STRICT_OBJC_MSGSEND = YES;
387 | EXECUTABLE_PREFIX = lib;
388 | GCC_NO_COMMON_BLOCKS = YES;
389 | MACH_O_TYPE = staticlib;
390 | MACOSX_DEPLOYMENT_TARGET = 10.12;
391 | MTL_ENABLE_DEBUG_INFO = YES;
392 | OTHER_LDFLAGS = "";
393 | OTHER_LIBTOOLFLAGS = "";
394 | PODS_ROOT = "$(SRCROOT)";
395 | PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}";
396 | PRODUCT_NAME = "$(TARGET_NAME)";
397 | SDKROOT = macosx;
398 | SKIP_INSTALL = YES;
399 | };
400 | name = Debug;
401 | };
402 | CC746689163F34D1DE2633B034B7C43E /* Debug */ = {
403 | isa = XCBuildConfiguration;
404 | baseConfigurationReference = B2AC8D08AB9E95E701EC049C53414AEB /* FMDB.xcconfig */;
405 | buildSettings = {
406 | CODE_SIGN_IDENTITY = "-";
407 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
408 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
409 | "CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
410 | DEBUG_INFORMATION_FORMAT = dwarf;
411 | ENABLE_STRICT_OBJC_MSGSEND = YES;
412 | EXECUTABLE_PREFIX = lib;
413 | GCC_NO_COMMON_BLOCKS = YES;
414 | GCC_PREFIX_HEADER = "Target Support Files/FMDB/FMDB-prefix.pch";
415 | MACOSX_DEPLOYMENT_TARGET = 10.6;
416 | MTL_ENABLE_DEBUG_INFO = YES;
417 | OTHER_LDFLAGS = "";
418 | OTHER_LIBTOOLFLAGS = "";
419 | PRIVATE_HEADERS_FOLDER_PATH = "";
420 | PRODUCT_NAME = "$(TARGET_NAME)";
421 | PUBLIC_HEADERS_FOLDER_PATH = "";
422 | SDKROOT = macosx;
423 | };
424 | name = Debug;
425 | };
426 | CECAB0F9E5933251B06A31F4FB037E58 /* Release */ = {
427 | isa = XCBuildConfiguration;
428 | baseConfigurationReference = 3E5CD9656810C066589D6EF2524F59D0 /* Pods-WebCrawler.release.xcconfig */;
429 | buildSettings = {
430 | CODE_SIGN_IDENTITY = "-";
431 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
432 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
433 | "CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
434 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
435 | ENABLE_STRICT_OBJC_MSGSEND = YES;
436 | EXECUTABLE_PREFIX = lib;
437 | GCC_NO_COMMON_BLOCKS = YES;
438 | MACH_O_TYPE = staticlib;
439 | MACOSX_DEPLOYMENT_TARGET = 10.12;
440 | MTL_ENABLE_DEBUG_INFO = NO;
441 | OTHER_LDFLAGS = "";
442 | OTHER_LIBTOOLFLAGS = "";
443 | PODS_ROOT = "$(SRCROOT)";
444 | PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}";
445 | PRODUCT_NAME = "$(TARGET_NAME)";
446 | SDKROOT = macosx;
447 | SKIP_INSTALL = YES;
448 | };
449 | name = Release;
450 | };
451 | FC4738C3605827B2CD972C349A860865 /* Release */ = {
452 | isa = XCBuildConfiguration;
453 | buildSettings = {
454 | ALWAYS_SEARCH_USER_PATHS = NO;
455 | CLANG_ANALYZER_NONNULL = YES;
456 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES;
457 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
458 | CLANG_CXX_LIBRARY = "libc++";
459 | CLANG_ENABLE_MODULES = YES;
460 | CLANG_ENABLE_OBJC_ARC = YES;
461 | CLANG_WARN_BOOL_CONVERSION = YES;
462 | CLANG_WARN_CONSTANT_CONVERSION = YES;
463 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES;
464 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
465 | CLANG_WARN_EMPTY_BODY = YES;
466 | CLANG_WARN_ENUM_CONVERSION = YES;
467 | CLANG_WARN_INFINITE_RECURSION = YES;
468 | CLANG_WARN_INT_CONVERSION = YES;
469 | CLANG_WARN_OBJC_ROOT_CLASS = YES;
470 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
471 | CLANG_WARN_UNREACHABLE_CODE = YES;
472 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
473 | CODE_SIGNING_REQUIRED = NO;
474 | COPY_PHASE_STRIP = YES;
475 | ENABLE_NS_ASSERTIONS = NO;
476 | GCC_C_LANGUAGE_STANDARD = gnu99;
477 | GCC_PREPROCESSOR_DEFINITIONS = (
478 | "POD_CONFIGURATION_RELEASE=1",
479 | "$(inherited)",
480 | );
481 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
482 | GCC_WARN_ABOUT_RETURN_TYPE = YES;
483 | GCC_WARN_UNDECLARED_SELECTOR = YES;
484 | GCC_WARN_UNINITIALIZED_AUTOS = YES;
485 | GCC_WARN_UNUSED_FUNCTION = YES;
486 | GCC_WARN_UNUSED_VARIABLE = YES;
487 | MACOSX_DEPLOYMENT_TARGET = 10.12;
488 | PROVISIONING_PROFILE_SPECIFIER = NO_SIGNING/;
489 | STRIP_INSTALLED_PRODUCT = NO;
490 | SYMROOT = "${SRCROOT}/../build";
491 | VALIDATE_PRODUCT = YES;
492 | };
493 | name = Release;
494 | };
495 | /* End XCBuildConfiguration section */
496 |
497 | /* Begin XCConfigurationList section */
498 | 1BA066B3D32C553BF37E3322F9113F02 /* Build configuration list for PBXNativeTarget "FMDB" */ = {
499 | isa = XCConfigurationList;
500 | buildConfigurations = (
501 | CC746689163F34D1DE2633B034B7C43E /* Debug */,
502 | 0FCC01CFB467D325132CE2B1625B2AD8 /* Release */,
503 | );
504 | defaultConfigurationIsVisible = 0;
505 | defaultConfigurationName = Release;
506 | };
507 | 2D8E8EC45A3A1A1D94AE762CB5028504 /* Build configuration list for PBXProject "Pods" */ = {
508 | isa = XCConfigurationList;
509 | buildConfigurations = (
510 | 337AD37B27D7FFADF01DD8D7FE35B27B /* Debug */,
511 | FC4738C3605827B2CD972C349A860865 /* Release */,
512 | );
513 | defaultConfigurationIsVisible = 0;
514 | defaultConfigurationName = Release;
515 | };
516 | A14299E1CA843097101C450F65C8E435 /* Build configuration list for PBXNativeTarget "Pods-WebCrawler" */ = {
517 | isa = XCConfigurationList;
518 | buildConfigurations = (
519 | AB23868CFB749E906FB18729BC78E5FB /* Debug */,
520 | CECAB0F9E5933251B06A31F4FB037E58 /* Release */,
521 | );
522 | defaultConfigurationIsVisible = 0;
523 | defaultConfigurationName = Release;
524 | };
525 | /* End XCConfigurationList section */
526 | };
527 | rootObject = D41D8CD98F00B204E9800998ECF8427E /* Project object */;
528 | }
529 |
--------------------------------------------------------------------------------
/Pods/Pods.xcodeproj/xcuserdata/apple.xcuserdatad/xcschemes/FMDB.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
44 |
45 |
46 |
52 |
53 |
55 |
56 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/Pods/Pods.xcodeproj/xcuserdata/apple.xcuserdatad/xcschemes/Pods-WebCrawler.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
44 |
45 |
46 |
52 |
53 |
55 |
56 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/Pods/Pods.xcodeproj/xcuserdata/apple.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | FMDB.xcscheme
8 |
9 | isShown
10 |
11 | orderHint
12 | 0
13 |
14 | Pods-WebCrawler.xcscheme
15 |
16 | isShown
17 |
18 | orderHint
19 | 1
20 |
21 |
22 | SuppressBuildableAutocreation
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/FMDB/FMDB-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_FMDB : NSObject
3 | @end
4 | @implementation PodsDummy_FMDB
5 | @end
6 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/FMDB/FMDB-prefix.pch:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/FMDB/FMDB.xcconfig:
--------------------------------------------------------------------------------
1 | CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/FMDB
2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
3 | HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/FMDB" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/FMDB"
4 | OTHER_LDFLAGS = -l"sqlite3"
5 | PODS_BUILD_DIR = $BUILD_DIR
6 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
7 | PODS_ROOT = ${SRCROOT}
8 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/FMDB
9 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
10 | SKIP_INSTALL = YES
11 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Pods-WebCrawler/Pods-WebCrawler-acknowledgements.markdown:
--------------------------------------------------------------------------------
1 | # Acknowledgements
2 | This application makes use of the following third party libraries:
3 |
4 | ## FMDB
5 |
6 | If you are using FMDB in your project, I'd love to hear about it. Let Gus know
7 | by sending an email to gus@flyingmeat.com.
8 |
9 | And if you happen to come across either Gus Mueller or Rob Ryan in a bar, you
10 | might consider purchasing a drink of their choosing if FMDB has been useful to
11 | you.
12 |
13 | Finally, and shortly, this is the MIT License.
14 |
15 | Copyright (c) 2008-2014 Flying Meat Inc.
16 |
17 | Permission is hereby granted, free of charge, to any person obtaining a copy
18 | of this software and associated documentation files (the "Software"), to deal
19 | in the Software without restriction, including without limitation the rights
20 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
21 | copies of the Software, and to permit persons to whom the Software is
22 | furnished to do so, subject to the following conditions:
23 |
24 | The above copyright notice and this permission notice shall be included in
25 | all copies or substantial portions of the Software.
26 |
27 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
30 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
32 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
33 | THE SOFTWARE.
34 | Generated by CocoaPods - https://cocoapods.org
35 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Pods-WebCrawler/Pods-WebCrawler-acknowledgements.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreferenceSpecifiers
6 |
7 |
8 | FooterText
9 | This application makes use of the following third party libraries:
10 | Title
11 | Acknowledgements
12 | Type
13 | PSGroupSpecifier
14 |
15 |
16 | FooterText
17 | If you are using FMDB in your project, I'd love to hear about it. Let Gus know
18 | by sending an email to gus@flyingmeat.com.
19 |
20 | And if you happen to come across either Gus Mueller or Rob Ryan in a bar, you
21 | might consider purchasing a drink of their choosing if FMDB has been useful to
22 | you.
23 |
24 | Finally, and shortly, this is the MIT License.
25 |
26 | Copyright (c) 2008-2014 Flying Meat Inc.
27 |
28 | Permission is hereby granted, free of charge, to any person obtaining a copy
29 | of this software and associated documentation files (the "Software"), to deal
30 | in the Software without restriction, including without limitation the rights
31 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
32 | copies of the Software, and to permit persons to whom the Software is
33 | furnished to do so, subject to the following conditions:
34 |
35 | The above copyright notice and this permission notice shall be included in
36 | all copies or substantial portions of the Software.
37 |
38 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
39 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
40 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
41 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
42 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
43 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
44 | THE SOFTWARE.
45 | License
46 | MIT
47 | Title
48 | FMDB
49 | Type
50 | PSGroupSpecifier
51 |
52 |
53 | FooterText
54 | Generated by CocoaPods - https://cocoapods.org
55 | Title
56 |
57 | Type
58 | PSGroupSpecifier
59 |
60 |
61 | StringsTable
62 | Acknowledgements
63 | Title
64 | Acknowledgements
65 |
66 |
67 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Pods-WebCrawler/Pods-WebCrawler-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_Pods_WebCrawler : NSObject
3 | @end
4 | @implementation PodsDummy_Pods_WebCrawler
5 | @end
6 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Pods-WebCrawler/Pods-WebCrawler-frameworks.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 |
4 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
5 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
6 |
7 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}"
8 |
9 | install_framework()
10 | {
11 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then
12 | local source="${BUILT_PRODUCTS_DIR}/$1"
13 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then
14 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")"
15 | elif [ -r "$1" ]; then
16 | local source="$1"
17 | fi
18 |
19 | local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
20 |
21 | if [ -L "${source}" ]; then
22 | echo "Symlinked..."
23 | source="$(readlink "${source}")"
24 | fi
25 |
26 | # use filter instead of exclude so missing patterns dont' throw errors
27 | echo "rsync -av --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\""
28 | rsync -av --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}"
29 |
30 | local basename
31 | basename="$(basename -s .framework "$1")"
32 | binary="${destination}/${basename}.framework/${basename}"
33 | if ! [ -r "$binary" ]; then
34 | binary="${destination}/${basename}"
35 | fi
36 |
37 | # Strip invalid architectures so "fat" simulator / device frameworks work on device
38 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then
39 | strip_invalid_archs "$binary"
40 | fi
41 |
42 | # Resign the code if required by the build settings to avoid unstable apps
43 | code_sign_if_enabled "${destination}/$(basename "$1")"
44 |
45 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7.
46 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then
47 | local swift_runtime_libs
48 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]})
49 | for lib in $swift_runtime_libs; do
50 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\""
51 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}"
52 | code_sign_if_enabled "${destination}/${lib}"
53 | done
54 | fi
55 | }
56 |
57 | # Signs a framework with the provided identity
58 | code_sign_if_enabled() {
59 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
60 | # Use the current code_sign_identitiy
61 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
62 | local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements '$1'"
63 |
64 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
65 | code_sign_cmd="$code_sign_cmd &"
66 | fi
67 | echo "$code_sign_cmd"
68 | eval "$code_sign_cmd"
69 | fi
70 | }
71 |
72 | # Strip invalid architectures
73 | strip_invalid_archs() {
74 | binary="$1"
75 | # Get architectures for current file
76 | archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)"
77 | stripped=""
78 | for arch in $archs; do
79 | if ! [[ "${VALID_ARCHS}" == *"$arch"* ]]; then
80 | # Strip non-valid architectures in-place
81 | lipo -remove "$arch" -output "$binary" "$binary" || exit 1
82 | stripped="$stripped $arch"
83 | fi
84 | done
85 | if [[ "$stripped" ]]; then
86 | echo "Stripped $binary of architectures:$stripped"
87 | fi
88 | }
89 |
90 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
91 | wait
92 | fi
93 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Pods-WebCrawler/Pods-WebCrawler-resources.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 |
4 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
5 |
6 | RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt
7 | > "$RESOURCES_TO_COPY"
8 |
9 | XCASSET_FILES=()
10 |
11 | case "${TARGETED_DEVICE_FAMILY}" in
12 | 1,2)
13 | TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone"
14 | ;;
15 | 1)
16 | TARGET_DEVICE_ARGS="--target-device iphone"
17 | ;;
18 | 2)
19 | TARGET_DEVICE_ARGS="--target-device ipad"
20 | ;;
21 | 3)
22 | TARGET_DEVICE_ARGS="--target-device tv"
23 | ;;
24 | 4)
25 | TARGET_DEVICE_ARGS="--target-device watch"
26 | ;;
27 | *)
28 | TARGET_DEVICE_ARGS="--target-device mac"
29 | ;;
30 | esac
31 |
32 | install_resource()
33 | {
34 | if [[ "$1" = /* ]] ; then
35 | RESOURCE_PATH="$1"
36 | else
37 | RESOURCE_PATH="${PODS_ROOT}/$1"
38 | fi
39 | if [[ ! -e "$RESOURCE_PATH" ]] ; then
40 | cat << EOM
41 | error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script.
42 | EOM
43 | exit 1
44 | fi
45 | case $RESOURCE_PATH in
46 | *.storyboard)
47 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}"
48 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS}
49 | ;;
50 | *.xib)
51 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}"
52 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS}
53 | ;;
54 | *.framework)
55 | echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
56 | mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
57 | echo "rsync -av $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
58 | rsync -av "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
59 | ;;
60 | *.xcdatamodel)
61 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\""
62 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom"
63 | ;;
64 | *.xcdatamodeld)
65 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\""
66 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd"
67 | ;;
68 | *.xcmappingmodel)
69 | echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\""
70 | xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm"
71 | ;;
72 | *.xcassets)
73 | ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH"
74 | XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE")
75 | ;;
76 | *)
77 | echo "$RESOURCE_PATH"
78 | echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY"
79 | ;;
80 | esac
81 | }
82 |
83 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
84 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
85 | if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then
86 | mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
87 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
88 | fi
89 | rm -f "$RESOURCES_TO_COPY"
90 |
91 | if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ]
92 | then
93 | # Find all other xcassets (this unfortunately includes those of path pods and other targets).
94 | OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d)
95 | while read line; do
96 | if [[ $line != "${PODS_ROOT}*" ]]; then
97 | XCASSET_FILES+=("$line")
98 | fi
99 | done <<<"$OTHER_XCASSETS"
100 |
101 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
102 | fi
103 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Pods-WebCrawler/Pods-WebCrawler.debug.xcconfig:
--------------------------------------------------------------------------------
1 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
2 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/FMDB"
3 | LIBRARY_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/FMDB"
4 | OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/FMDB"
5 | OTHER_LDFLAGS = $(inherited) -ObjC -l"FMDB" -l"sqlite3"
6 | PODS_BUILD_DIR = $BUILD_DIR
7 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
8 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
9 | PODS_ROOT = ${SRCROOT}/Pods
10 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Pods-WebCrawler/Pods-WebCrawler.release.xcconfig:
--------------------------------------------------------------------------------
1 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
2 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/FMDB"
3 | LIBRARY_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/FMDB"
4 | OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/FMDB"
5 | OTHER_LDFLAGS = $(inherited) -ObjC -l"FMDB" -l"sqlite3"
6 | PODS_BUILD_DIR = $BUILD_DIR
7 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
8 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
9 | PODS_ROOT = ${SRCROOT}/Pods
10 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # WebCrawler
2 | [](http://www.yangziyao.top)
3 | [](https://weibo.com/5905837515/profile?topnav=1&wvr=6)
4 | [](https://opensource.org/licenses/mit-license.php)
5 | [](https://github.com/CodyCalvin/WebCrawler)
6 |
7 |
8 | 说明
9 | ------
10 | * 铃声多多网站的爬虫脚本,用来抓取铃声多多官网的铃声数据并下载。
11 |
12 | * [我的博客](http://www.yangziyao.top)
13 | -------
14 |
15 |
16 |
17 | 免责声明
18 | ------
19 | * 本项目旨在学习macOS 项目的一点实践,不可使用于商业和个人其他意图。若使用不当,均由个人承担。
20 | * 包含功能:爬取数据
21 | * 若使用中遇到遇到问题, Issue me!
22 |
23 | |Author| CodyCalvin |
24 | | -----|:------------:|
25 | |E-mail| CodyCalvin@163.com|
26 | ------
27 | 安装
28 | ------
29 | 1. 懒人安装
30 |
31 | * 打开 `实用工具-` >`Terminal(终端)`,执行以下命令即可。(需要git支持) `cd ~/Downloads && git https://github.com/CodyCalvin/WebCrawler.git`
32 |
33 | 2. 普通安装
34 |
35 | * 点击`clone or download`下载项目并解压,打开`Terminal(终端)`,打开`WebCrawler.xcodeproj`然后`Command+R`运行工程。
36 |
37 | 3. 重编译安装
38 |
39 | * 点击`clone or download`下载项目,`WebCrawler.xcodeproj`。然后运行工程,如果用户`Xcode`有打印内容,证明成功。
40 |
41 | 更换获取音乐类别
42 | ------
43 |
44 | enum MusicType
45 | {
46 | HottestRingtones = 1, // 最热铃声
47 |
48 | LatestRingtones = 0, // 最新铃声
49 |
50 | AppleHottestlist = 99,// 苹果最热榜
51 |
52 | Downloadatmost = 22, // 最多下载
53 |
54 | PopularSongs = 2, // 流行金曲
55 |
56 | TelevisionAds = 3, // 影视广告
57 |
58 | SMSNotification = 5, // 短信通知
59 |
60 | AnimeGames = 4, // 动漫游戏
61 |
62 | FunnyAlternative = 7 // 另类搞笑
63 | };
64 |
65 | 根据以上枚举替换下边方法的`HottestRingtones`即可
66 | ```java
67 | NSString *urlString = [NSString stringWithFormat:@"http://www.shoujiduoduo.com/home/detail_%d_%zd_30.html",HottestRingtones,i];
68 | ```
69 | -------
70 |
71 | 依赖
72 | ------
73 | * [Mac](https://www.apple.com/cn/mac "悬停显示") [Xcode](https://developer.apple.com/xcode)
74 |
75 | 更新
76 | ------
77 | * 此项目将持续更行,另会增加App版本更方便更快捷
78 |
79 | 最后
80 | ------
81 | * 使用愉快~
82 |
83 | 勾搭下
84 | ------
85 | 
86 |
87 |
--------------------------------------------------------------------------------
/WebCrawler.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 48;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 1560CE461C91DC25C041E819 /* libPods-WebCrawler.a in Frameworks */ = {isa = PBXBuildFile; fileRef = AA3329C0C5C48DC2A8131C78 /* libPods-WebCrawler.a */; };
11 | 188E3A7420521C3900EF8592 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 188E3A7320521C3900EF8592 /* main.m */; };
12 | 188E3A7C20521C9500EF8592 /* NSString+Substring.m in Sources */ = {isa = PBXBuildFile; fileRef = 188E3A7B20521C9500EF8592 /* NSString+Substring.m */; };
13 | /* End PBXBuildFile section */
14 |
15 | /* Begin PBXCopyFilesBuildPhase section */
16 | 188E3A6E20521C3900EF8592 /* CopyFiles */ = {
17 | isa = PBXCopyFilesBuildPhase;
18 | buildActionMask = 2147483647;
19 | dstPath = /usr/share/man/man1/;
20 | dstSubfolderSpec = 0;
21 | files = (
22 | );
23 | runOnlyForDeploymentPostprocessing = 1;
24 | };
25 | /* End PBXCopyFilesBuildPhase section */
26 |
27 | /* Begin PBXFileReference section */
28 | 188E3A7020521C3900EF8592 /* WebCrawler */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = WebCrawler; sourceTree = BUILT_PRODUCTS_DIR; };
29 | 188E3A7320521C3900EF8592 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
30 | 188E3A7A20521C9500EF8592 /* NSString+Substring.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+Substring.h"; sourceTree = ""; };
31 | 188E3A7B20521C9500EF8592 /* NSString+Substring.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+Substring.m"; sourceTree = ""; };
32 | 18CEEB0220528BE5005C1FA3 /* WechatIMG13.jpeg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = WechatIMG13.jpeg; sourceTree = ""; };
33 | 6AF4B13408E185AAE68DF2DE /* Pods-WebCrawler.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WebCrawler.debug.xcconfig"; path = "Pods/Target Support Files/Pods-WebCrawler/Pods-WebCrawler.debug.xcconfig"; sourceTree = ""; };
34 | AA3329C0C5C48DC2A8131C78 /* libPods-WebCrawler.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-WebCrawler.a"; sourceTree = BUILT_PRODUCTS_DIR; };
35 | BA28C4284AA78729CA02BC02 /* Pods-WebCrawler.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WebCrawler.release.xcconfig"; path = "Pods/Target Support Files/Pods-WebCrawler/Pods-WebCrawler.release.xcconfig"; sourceTree = ""; };
36 | /* End PBXFileReference section */
37 |
38 | /* Begin PBXFrameworksBuildPhase section */
39 | 188E3A6D20521C3900EF8592 /* Frameworks */ = {
40 | isa = PBXFrameworksBuildPhase;
41 | buildActionMask = 2147483647;
42 | files = (
43 | 1560CE461C91DC25C041E819 /* libPods-WebCrawler.a in Frameworks */,
44 | );
45 | runOnlyForDeploymentPostprocessing = 0;
46 | };
47 | /* End PBXFrameworksBuildPhase section */
48 |
49 | /* Begin PBXGroup section */
50 | 188E3A6720521C3900EF8592 = {
51 | isa = PBXGroup;
52 | children = (
53 | 188E3A7220521C3900EF8592 /* WebCrawler */,
54 | 188E3A7120521C3900EF8592 /* Products */,
55 | C355585E36C2380F4102054D /* Pods */,
56 | 9DECBE54111367E4ACE1D65E /* Frameworks */,
57 | );
58 | sourceTree = "";
59 | };
60 | 188E3A7120521C3900EF8592 /* Products */ = {
61 | isa = PBXGroup;
62 | children = (
63 | 188E3A7020521C3900EF8592 /* WebCrawler */,
64 | );
65 | name = Products;
66 | sourceTree = "";
67 | };
68 | 188E3A7220521C3900EF8592 /* WebCrawler */ = {
69 | isa = PBXGroup;
70 | children = (
71 | 18CEEB0220528BE5005C1FA3 /* WechatIMG13.jpeg */,
72 | 188E3A7A20521C9500EF8592 /* NSString+Substring.h */,
73 | 188E3A7B20521C9500EF8592 /* NSString+Substring.m */,
74 | 188E3A7320521C3900EF8592 /* main.m */,
75 | );
76 | path = WebCrawler;
77 | sourceTree = "";
78 | };
79 | 9DECBE54111367E4ACE1D65E /* Frameworks */ = {
80 | isa = PBXGroup;
81 | children = (
82 | AA3329C0C5C48DC2A8131C78 /* libPods-WebCrawler.a */,
83 | );
84 | name = Frameworks;
85 | sourceTree = "";
86 | };
87 | C355585E36C2380F4102054D /* Pods */ = {
88 | isa = PBXGroup;
89 | children = (
90 | 6AF4B13408E185AAE68DF2DE /* Pods-WebCrawler.debug.xcconfig */,
91 | BA28C4284AA78729CA02BC02 /* Pods-WebCrawler.release.xcconfig */,
92 | );
93 | name = Pods;
94 | sourceTree = "";
95 | };
96 | /* End PBXGroup section */
97 |
98 | /* Begin PBXNativeTarget section */
99 | 188E3A6F20521C3900EF8592 /* WebCrawler */ = {
100 | isa = PBXNativeTarget;
101 | buildConfigurationList = 188E3A7720521C3900EF8592 /* Build configuration list for PBXNativeTarget "WebCrawler" */;
102 | buildPhases = (
103 | 2F75FAAB5DCA2890449B4A44 /* [CP] Check Pods Manifest.lock */,
104 | 188E3A6C20521C3900EF8592 /* Sources */,
105 | 188E3A6D20521C3900EF8592 /* Frameworks */,
106 | 188E3A6E20521C3900EF8592 /* CopyFiles */,
107 | 296FF6B72F75A6DDA391AD42 /* [CP] Copy Pods Resources */,
108 | );
109 | buildRules = (
110 | );
111 | dependencies = (
112 | );
113 | name = WebCrawler;
114 | productName = WebCrawler;
115 | productReference = 188E3A7020521C3900EF8592 /* WebCrawler */;
116 | productType = "com.apple.product-type.tool";
117 | };
118 | /* End PBXNativeTarget section */
119 |
120 | /* Begin PBXProject section */
121 | 188E3A6820521C3900EF8592 /* Project object */ = {
122 | isa = PBXProject;
123 | attributes = {
124 | LastUpgradeCheck = 0920;
125 | ORGANIZATIONNAME = WebCrawler;
126 | TargetAttributes = {
127 | 188E3A6F20521C3900EF8592 = {
128 | CreatedOnToolsVersion = 9.2;
129 | ProvisioningStyle = Automatic;
130 | };
131 | };
132 | };
133 | buildConfigurationList = 188E3A6B20521C3900EF8592 /* Build configuration list for PBXProject "WebCrawler" */;
134 | compatibilityVersion = "Xcode 8.0";
135 | developmentRegion = en;
136 | hasScannedForEncodings = 0;
137 | knownRegions = (
138 | en,
139 | );
140 | mainGroup = 188E3A6720521C3900EF8592;
141 | productRefGroup = 188E3A7120521C3900EF8592 /* Products */;
142 | projectDirPath = "";
143 | projectRoot = "";
144 | targets = (
145 | 188E3A6F20521C3900EF8592 /* WebCrawler */,
146 | );
147 | };
148 | /* End PBXProject section */
149 |
150 | /* Begin PBXShellScriptBuildPhase section */
151 | 296FF6B72F75A6DDA391AD42 /* [CP] Copy Pods Resources */ = {
152 | isa = PBXShellScriptBuildPhase;
153 | buildActionMask = 2147483647;
154 | files = (
155 | );
156 | inputPaths = (
157 | );
158 | name = "[CP] Copy Pods Resources";
159 | outputPaths = (
160 | );
161 | runOnlyForDeploymentPostprocessing = 0;
162 | shellPath = /bin/sh;
163 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-WebCrawler/Pods-WebCrawler-resources.sh\"\n";
164 | showEnvVarsInLog = 0;
165 | };
166 | 2F75FAAB5DCA2890449B4A44 /* [CP] Check Pods Manifest.lock */ = {
167 | isa = PBXShellScriptBuildPhase;
168 | buildActionMask = 2147483647;
169 | files = (
170 | );
171 | inputPaths = (
172 | );
173 | name = "[CP] Check Pods Manifest.lock";
174 | outputPaths = (
175 | );
176 | runOnlyForDeploymentPostprocessing = 0;
177 | shellPath = /bin/sh;
178 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
179 | showEnvVarsInLog = 0;
180 | };
181 | /* End PBXShellScriptBuildPhase section */
182 |
183 | /* Begin PBXSourcesBuildPhase section */
184 | 188E3A6C20521C3900EF8592 /* Sources */ = {
185 | isa = PBXSourcesBuildPhase;
186 | buildActionMask = 2147483647;
187 | files = (
188 | 188E3A7420521C3900EF8592 /* main.m in Sources */,
189 | 188E3A7C20521C9500EF8592 /* NSString+Substring.m in Sources */,
190 | );
191 | runOnlyForDeploymentPostprocessing = 0;
192 | };
193 | /* End PBXSourcesBuildPhase section */
194 |
195 | /* Begin XCBuildConfiguration section */
196 | 188E3A7520521C3900EF8592 /* Debug */ = {
197 | isa = XCBuildConfiguration;
198 | buildSettings = {
199 | ALWAYS_SEARCH_USER_PATHS = NO;
200 | CLANG_ANALYZER_NONNULL = YES;
201 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
202 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
203 | CLANG_CXX_LIBRARY = "libc++";
204 | CLANG_ENABLE_MODULES = YES;
205 | CLANG_ENABLE_OBJC_ARC = YES;
206 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
207 | CLANG_WARN_BOOL_CONVERSION = YES;
208 | CLANG_WARN_COMMA = YES;
209 | CLANG_WARN_CONSTANT_CONVERSION = YES;
210 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
211 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
212 | CLANG_WARN_EMPTY_BODY = YES;
213 | CLANG_WARN_ENUM_CONVERSION = YES;
214 | CLANG_WARN_INFINITE_RECURSION = YES;
215 | CLANG_WARN_INT_CONVERSION = YES;
216 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
217 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
218 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
219 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
220 | CLANG_WARN_STRICT_PROTOTYPES = YES;
221 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
222 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
223 | CLANG_WARN_UNREACHABLE_CODE = YES;
224 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
225 | CODE_SIGN_IDENTITY = "-";
226 | COPY_PHASE_STRIP = NO;
227 | DEBUG_INFORMATION_FORMAT = dwarf;
228 | ENABLE_STRICT_OBJC_MSGSEND = YES;
229 | ENABLE_TESTABILITY = YES;
230 | GCC_C_LANGUAGE_STANDARD = gnu11;
231 | GCC_DYNAMIC_NO_PIC = NO;
232 | GCC_NO_COMMON_BLOCKS = YES;
233 | GCC_OPTIMIZATION_LEVEL = 0;
234 | GCC_PREPROCESSOR_DEFINITIONS = (
235 | "DEBUG=1",
236 | "$(inherited)",
237 | );
238 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
239 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
240 | GCC_WARN_UNDECLARED_SELECTOR = YES;
241 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
242 | GCC_WARN_UNUSED_FUNCTION = YES;
243 | GCC_WARN_UNUSED_VARIABLE = YES;
244 | MACOSX_DEPLOYMENT_TARGET = 10.12;
245 | MTL_ENABLE_DEBUG_INFO = YES;
246 | ONLY_ACTIVE_ARCH = YES;
247 | SDKROOT = macosx;
248 | };
249 | name = Debug;
250 | };
251 | 188E3A7620521C3900EF8592 /* Release */ = {
252 | isa = XCBuildConfiguration;
253 | buildSettings = {
254 | ALWAYS_SEARCH_USER_PATHS = NO;
255 | CLANG_ANALYZER_NONNULL = YES;
256 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
257 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
258 | CLANG_CXX_LIBRARY = "libc++";
259 | CLANG_ENABLE_MODULES = YES;
260 | CLANG_ENABLE_OBJC_ARC = YES;
261 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
262 | CLANG_WARN_BOOL_CONVERSION = YES;
263 | CLANG_WARN_COMMA = YES;
264 | CLANG_WARN_CONSTANT_CONVERSION = YES;
265 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
266 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
267 | CLANG_WARN_EMPTY_BODY = YES;
268 | CLANG_WARN_ENUM_CONVERSION = YES;
269 | CLANG_WARN_INFINITE_RECURSION = YES;
270 | CLANG_WARN_INT_CONVERSION = YES;
271 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
272 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
273 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
274 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
275 | CLANG_WARN_STRICT_PROTOTYPES = YES;
276 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
277 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
278 | CLANG_WARN_UNREACHABLE_CODE = YES;
279 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
280 | CODE_SIGN_IDENTITY = "-";
281 | COPY_PHASE_STRIP = NO;
282 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
283 | ENABLE_NS_ASSERTIONS = NO;
284 | ENABLE_STRICT_OBJC_MSGSEND = YES;
285 | GCC_C_LANGUAGE_STANDARD = gnu11;
286 | GCC_NO_COMMON_BLOCKS = YES;
287 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
288 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
289 | GCC_WARN_UNDECLARED_SELECTOR = YES;
290 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
291 | GCC_WARN_UNUSED_FUNCTION = YES;
292 | GCC_WARN_UNUSED_VARIABLE = YES;
293 | MACOSX_DEPLOYMENT_TARGET = 10.12;
294 | MTL_ENABLE_DEBUG_INFO = NO;
295 | SDKROOT = macosx;
296 | };
297 | name = Release;
298 | };
299 | 188E3A7820521C3900EF8592 /* Debug */ = {
300 | isa = XCBuildConfiguration;
301 | baseConfigurationReference = 6AF4B13408E185AAE68DF2DE /* Pods-WebCrawler.debug.xcconfig */;
302 | buildSettings = {
303 | CODE_SIGN_STYLE = Automatic;
304 | PRODUCT_NAME = "$(TARGET_NAME)";
305 | };
306 | name = Debug;
307 | };
308 | 188E3A7920521C3900EF8592 /* Release */ = {
309 | isa = XCBuildConfiguration;
310 | baseConfigurationReference = BA28C4284AA78729CA02BC02 /* Pods-WebCrawler.release.xcconfig */;
311 | buildSettings = {
312 | CODE_SIGN_STYLE = Automatic;
313 | PRODUCT_NAME = "$(TARGET_NAME)";
314 | };
315 | name = Release;
316 | };
317 | /* End XCBuildConfiguration section */
318 |
319 | /* Begin XCConfigurationList section */
320 | 188E3A6B20521C3900EF8592 /* Build configuration list for PBXProject "WebCrawler" */ = {
321 | isa = XCConfigurationList;
322 | buildConfigurations = (
323 | 188E3A7520521C3900EF8592 /* Debug */,
324 | 188E3A7620521C3900EF8592 /* Release */,
325 | );
326 | defaultConfigurationIsVisible = 0;
327 | defaultConfigurationName = Release;
328 | };
329 | 188E3A7720521C3900EF8592 /* Build configuration list for PBXNativeTarget "WebCrawler" */ = {
330 | isa = XCConfigurationList;
331 | buildConfigurations = (
332 | 188E3A7820521C3900EF8592 /* Debug */,
333 | 188E3A7920521C3900EF8592 /* Release */,
334 | );
335 | defaultConfigurationIsVisible = 0;
336 | defaultConfigurationName = Release;
337 | };
338 | /* End XCConfigurationList section */
339 | };
340 | rootObject = 188E3A6820521C3900EF8592 /* Project object */;
341 | }
342 |
--------------------------------------------------------------------------------
/WebCrawler.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/WebCrawler.xcodeproj/project.xcworkspace/xcuserdata/apple.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YangsCalvin/WebCrawler/2395c12ca9bec30fb396412fc1745009b8828daa/WebCrawler.xcodeproj/project.xcworkspace/xcuserdata/apple.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/WebCrawler.xcodeproj/xcuserdata/apple.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | WebCrawler.xcscheme
8 |
9 | orderHint
10 | 2
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/WebCrawler.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/WebCrawler.xcworkspace/xcuserdata/apple.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YangsCalvin/WebCrawler/2395c12ca9bec30fb396412fc1745009b8828daa/WebCrawler.xcworkspace/xcuserdata/apple.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/WebCrawler.xcworkspace/xcuserdata/apple.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
8 |
20 |
21 |
35 |
36 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/WebCrawler/NSString+Substring.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSString+Substring.h
3 | // CommonFramework
4 | //
5 | // Created by zhuwei on 15/2/7.
6 | // Copyright (c) 2018年 yangziyao. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface NSString (Substring)
12 | /**
13 | 获得特定字符串的中字符串
14 |
15 | @param strLeft 左边匹配字符串
16 |
17 | @param strRight 右边匹配的字符串
18 |
19 | @return NSString类型
20 | */
21 | - (NSString*)substringWithinBoundsLeft:(NSString*)strLeft right:(NSString*)strRight;
22 | @end
23 |
--------------------------------------------------------------------------------
/WebCrawler/NSString+Substring.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSString+Substring.m
3 | // CommonFramework
4 | //
5 | // Created by zhuwei on 15/2/7.
6 | // Copyright (c) 2015年 zhuwei. All rights reserved.
7 | //
8 |
9 | #import "NSString+Substring.h"
10 |
11 | @implementation NSString (Substring)
12 | /**
13 | 获得特定字符串的中字符串
14 |
15 | @param strLeft: 左边匹配字符串
16 |
17 | @param strRight: 右边匹配的字符串
18 |
19 | @return NSString类型
20 | */
21 | - (NSString*)substringWithinBoundsLeft:(NSString*)strLeft right:(NSString*)strRight
22 | {
23 | NSRange rangeSub;
24 | NSString *strSub;
25 |
26 | NSRange range;
27 | range = [self rangeOfString:strLeft options:0];
28 |
29 | if (range.location == NSNotFound) {
30 | return nil;
31 | }
32 |
33 | rangeSub.location = range.location + range.length;
34 |
35 | range.location = rangeSub.location;
36 | range.length = [self length] - range.location;
37 | range = [self rangeOfString:strRight options:0 range:range];
38 |
39 | if (range.location == NSNotFound) {
40 | return nil;
41 | }
42 |
43 | rangeSub.length = range.location - rangeSub.location;
44 | strSub = [[self substringWithRange:rangeSub] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
45 |
46 | return strSub;
47 | }
48 | @end
49 |
--------------------------------------------------------------------------------
/WebCrawler/WechatIMG13.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YangsCalvin/WebCrawler/2395c12ca9bec30fb396412fc1745009b8828daa/WebCrawler/WechatIMG13.jpeg
--------------------------------------------------------------------------------
/WebCrawler/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // WebCrawler
4 | //
5 | // Created by apple on 2018/3/9.
6 | // Copyright © 2018年 WebCrawler. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "NSString+Substring.h"
11 | #import
12 | /**
13 |
14 | 铃声多多官网地址:http://www.shoujiduoduo.com/home/detail_1_1_30.html
15 |
16 | */
17 | enum MusicType
18 | {
19 | HottestRingtones = 1, // 最热铃声
20 |
21 | LatestRingtones = 0, // 最新铃声
22 |
23 | AppleHottestlist = 99,//苹果最热榜
24 |
25 | Downloadatmost = 22, // 最多下载
26 |
27 | PopularSongs = 2, // 流行金曲
28 |
29 | TelevisionAds = 3, // 影视广告
30 |
31 | SMSNotification = 5, // 短信通知
32 |
33 | AnimeGames = 4, // 动漫游戏
34 |
35 | FunnyAlternative = 7 // 另类搞笑
36 | };
37 |
38 | int main(int argc, const char * argv[]) {
39 | @autoreleasepool {
40 |
41 | NSLog(@"Hello, World!");
42 |
43 | FMDatabase *db = [[FMDatabase alloc] initWithPath:@"/Users/apple/Desktop/peoms.sqlite"];
44 |
45 | [db open];
46 |
47 | int index = 1;
48 |
49 | for (int i = 10000; i<600000; i++) {
50 |
51 | // 如果想要获取别的类目请把 "HottestRingtones" 替换别的类目就可以了
52 | NSString *urlString = [NSString stringWithFormat:@"http://www.shoujiduoduo.com/home/detail_%d_%zd_30.html",HottestRingtones,i];
53 |
54 | #pragma clang diagnostic push
55 | #pragma clang diagnostic ignored "-Wdeprecated-declarations"
56 |
57 | NSData *htmlData = [NSURLConnection sendSynchronousRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:urlString]] returningResponse:nil error:nil];
58 |
59 | #pragma clang diagnostic pop
60 |
61 | NSString *html = [[NSString alloc] initWithData:htmlData encoding:NSUTF8StringEncoding];
62 |
63 | for (int l = index; l<=i * 30; l++) {
64 |
65 | NSString *strs = [NSString string];
66 |
67 | NSString *leftString = [NSString string];
68 | if(index < 4){
69 |
70 | strs = [NSString stringWithFormat:@"%zd%zd",Rid];
83 |
84 | NSString *musicname = [html substringWithinBoundsLeft:string right:@""];
85 |
86 | NSString *rangeStr = [html substringWithinBoundsLeft:leftString right:@"听过"];
87 |
88 | NSString *authorName = [rangeStr substringWithinBoundsLeft:@"" right:@"" right:@""];
91 |
92 | NSString *palyCount = [rangeStr substringWithinBoundsLeft:@"" right:@"人"];
93 |
94 | NSLog(@"\n歌曲标识:%@\n歌曲名字:%@\n作者名字:%@\n歌曲时长:%@\n播放数量:%@\n",Rid,musicname,authorName,musicTime,palyCount);
95 |
96 |
97 | //想用数据库储存的话可以打开下面这句话
98 |
99 | /**
100 | NSString *sql = @"INSERT INTO peoms(Rid,musicname,rangeStr,musicTime,palyCount) VALUES(?,?,?,?)";
101 |
102 | [db executeUpdate:sql,title,dynasty,author,content];
103 |
104 | */
105 |
106 | index++;
107 | }
108 |
109 | }
110 |
111 | [db close];
112 |
113 | }
114 | return 0;
115 | }
116 |
--------------------------------------------------------------------------------