Compare commits

...

1413 Commits
1.X ... master

Author SHA1 Message Date
Robbie Hanson
772efef2ed Incrementing podspec version. 2018-07-22 12:59:03 -04:00
Robbie Hanson
e8c4021aa1
Merge pull request #458 from wjmelements/ydcu-import-foundation
Add missing foundation import
2018-07-12 12:00:58 -04:00
William Morriss
5fa11c84d3 <> 2018-07-04 02:21:55 -07:00
William Morriss
190cbb6c98 add foundation import 2018-07-03 14:42:09 -07:00
Robbie Hanson
31475d08ff Bug fix for previous commit. 2018-06-28 16:05:50 -04:00
Robbie Hanson
81c2f830d4 Adding new insertedKeys set to YapDatabaseModifiedNotification. 2018-06-28 12:36:44 -04:00
Robbie Hanson
a2fa29e545 Merge branch 'master' of https://github.com/yapstudios/YapDatabase 2018-06-20 15:18:31 -04:00
Robbie Hanson
4e59aff974 Adding convenience method to detect when all previous asyncRegisterExtension requests have completed. 2018-06-20 15:18:25 -04:00
Robbie Hanson
cf9692ebea
Update README.md 2018-06-15 09:54:51 -04:00
Robbie Hanson
7e0919da7c Incrementing podspec version. 2018-06-14 22:18:28 -04:00
Robbie Hanson
fcfda4e5f0 Improving documentation in ConnectionProxy, and adding another reset-like method. 2018-05-23 19:09:49 -04:00
Robbie Hanson
5f480844db Fixing more compiler warnings for issue #444 2018-05-23 19:07:34 -04:00
Robbie Hanson
b5c42db8c6 Minor changes recommended by analyzer. 2018-05-23 17:31:07 -04:00
Robbie Hanson
ca0cb15154 Fix for issue #444 - Compiler warnings in Xcode 9 2018-05-23 17:30:28 -04:00
Robbie Hanson
5d3ea2e97b Adding NS_ASSUME_NONNULL header/footer to YapManyToManyCache.h, and fixing some nullability annotations. Also removing the nullability annotations from private header files, as the compiler throws a fit about all the other missing annotations within the file. (And because the private header files are only used by Obj-C.) 2018-04-05 10:17:37 -07:00
Denis Zubkov
4a207244ae Added __nullable to metadata in headers to make sure Swift 4.1 doesn't throw EXC_BAD_ACCESS 2018-04-05 15:25:14 +10:00
Robbie Hanson
cc678addef Updating YDBRelationship delete rules for files, to match recent changes for delete rules for nodes. Addresses issue #148 2018-04-04 10:56:58 -07:00
Robbie Hanson
88adbb028f
Merge pull request #447 from EnvionSoftwareMobile/master
Edges processing updated to fix #148
2018-04-03 18:20:52 -07:00
Artem Kirienko
66568fedc2 CocoaLumberjack pod updated 2018-03-28 21:41:17 +03:00
Artem Kirienko
fc3b157c0e Travis CI config updated 2018-03-28 21:37:16 +03:00
Artem Kirienko
9bf0ddf311 Edges processing updated to fix #148
Edge count query doesn't include edge name anymore.
2018-03-28 20:08:42 +03:00
Robbie Hanson
2947fda783 Potential bug fix for issues #437 and #441 2018-03-27 11:18:11 -07:00
Robbie Hanson
5b3f5030e7 Adding hook to additionally configure newly created connections in a connection pool. This is useful for configuring things such as permittedTransactions. 2018-03-19 15:00:56 -06:00
Robbie Hanson
b9d9fe42f6 Adding ConnectionPool to CocoaPods & Carthage. 2018-03-19 14:01:44 -06:00
Robbie Hanson
e26639737d New utility class: YapDatabaseConnectionPool. A simple load balancer designed for background (non-main-thread) tasks that perform read-only transactions. 2018-03-19 13:30:56 -06:00
Robbie Hanson
e59d5fb5f9 Adding new property on YapDatabaseConnection: pendingTransactionCount 2018-03-19 12:02:11 -06:00
Robbie Hanson
27b32aa3ea Minor optimization - check completionBlock for NULL once, instead of twice. 2018-03-19 12:00:12 -06:00
Robbie Hanson
30b053c000 Explicitly marking dynamic properties dynamic. This makes it easier to find spelling mistakes in function names. 2018-03-19 11:57:56 -06:00
Robbie Hanson
114d371b7a Adding ability to create a databaseConnection with a pre-configured set of configuration options. 2018-03-19 11:56:41 -06:00
Robbie Hanson
102a3436b9 Deprecating the defaultX properties in YapDatabase, in favor of the new(ish) YapDatabaseConnectionConfig class. 2018-03-18 13:41:13 -06:00
Robbie Hanson
05a3bbf01d Updating unit test project via 'pod install'. 2018-03-18 12:44:31 -06:00
Robbie Hanson
5969174262 Updating macOS deployment target from 10.9 to 10.10. The primary motivation for this is to silence the hundreds of compiler warnings about CloudKit not being available in 10.9. 2018-03-18 12:43:42 -06:00
Robbie Hanson
5df37ee440 Fixing compiler warning & bug in YDBCloudCore. 2018-03-18 12:28:46 -06:00
Robbie Hanson
ec857d7021
Merge pull request #439 from signalapp/charlesmchen/unencryptedHeaders
Charlesmchen/unencrypted headers
2018-03-18 12:18:59 -06:00
Robbie Hanson
d07f12b50d
Merge pull request #443 from mathieualvado/fix_nullability_annotations
Fix missing nullability annotation in backup methods
2018-03-15 14:07:56 -06:00
Mathieu Alvado
3174f45e67 Fix missing nullability annotation in backup methods
Missing annotations were causing a crash in Swift when accessing error argument.
2018-03-09 01:17:13 -05:00
Robbie Hanson
9f97fed893 Bug fix: enumeration code was skipping inserted operations in the last commit. 2018-03-08 15:38:10 -07:00
Robbie Hanson
f91e7a191e Adding a few convenience methods to YapDatabaseCloudCoreTransaction. 2018-03-08 15:35:51 -07:00
Robbie Hanson
a19f0d29e4 Fixing a crash that was described in issue #399 but this time with protocolEdges instead of manualEdges. Added corresponding unit test as well. 2018-03-08 15:32:14 -07:00
Robbie Hanson
9ac1bce51a
Merge pull request #440 from rupertdaniel/fts-add-transaction-to-handler-block
Fts add transaction to handler blocks
2018-03-08 17:43:55 -03:00
Robbie Hanson
15c3145e21
Merge pull request #442 from marcpalmer/marcpalmer-patch-1
Fix for _enumerateRowidsForKeys only working for 1 key
2018-03-08 17:38:16 -03:00
Marc Palmer
d9199ca084
Fix for _enumerateRowidsForKeys only working for 1 key
If the fast path for 1 key lookup is not taken because there are > 1 keys, the `keyIndexDict` is never allocated a value due to a logic bug. Objective-C then conspired to hide this problem from us thanks to messaging of nil.
2018-03-08 14:45:54 +00:00
Matthew Chen
373f0d4de7 Clean up ahead of PR. 2018-01-25 10:56:59 -05:00
Matthew Chen
3ed77a8f38 Clean up ahead of PR. 2018-01-25 10:43:33 -05:00
Matthew Chen
fcc56870be Clean up ahead of PR. 2018-01-25 10:22:08 -05:00
Matthew Chen
a57b0c1adb Add database conversion class. 2018-01-24 17:10:59 -05:00
Matthew Chen
40ab4d2fe2 Add support for key specs. 2018-01-24 16:05:18 -05:00
Matthew Chen
302a1c86e4 Fix tests broken on device. 2018-01-24 10:00:42 -05:00
Rupert Daniel
db05d876f7 Updated FTS unit tests. 2018-01-24 11:29:57 +00:00
Rupert Daniel
1aac5034f8 Pass the database transaction as a parameter to FTS extension handler
blocks.
2018-01-24 11:21:45 +00:00
Matthew Chen
9ef73cbc91 Clean up ahead of PR. 2018-01-23 17:11:40 -05:00
Matthew Chen
27019b5260 Clean up ahead of PR. 2018-01-23 16:57:10 -05:00
Matthew Chen
91cb9f50c1 Modify YapDatabase to read converted database. 2018-01-23 16:40:35 -05:00
Matthew Chen
3941d566a6 Modify YapDatabase to read converted database. 2018-01-23 09:49:16 -05:00
Matthew Chen
72e05df4cd Support unencrypted headers and manual salts. 2018-01-19 18:15:55 -05:00
Robbie Hanson
6dce343afb Bug fix for issue #433 - Initialisers are marked non-nullable in header, but can return nil 2018-01-02 13:10:47 -05:00
Robbie Hanson
65cb53830f Bug fix for issue #437 - Possible deadlock in [YapDatabaseConnection dealloc] 2018-01-02 12:57:50 -05:00
Robbie Hanson
cc73216ebf
Merge pull request #435 from ksuther/fts-upgrade
Fixed FTS extension repeatedly reindexing
2018-01-02 12:34:24 -05:00
Robbie Hanson
f0016bcc0a
Merge pull request #438 from ksuther/remove-crossprocess-logs
Adjusted logging in CrossProcessNotification extension
2018-01-02 12:32:04 -05:00
Robbie Hanson
8714d467ef Decreasing default log level for YDBActionManager. 2018-01-02 12:28:26 -05:00
Kent Sutherland
66dfd5d809 Adjusted logging in CrossProcessNotification extension
Remove NSLogging when creating and destroying the cross process notification extension.
Changed cross-process notification log to use YDBLog.
2017-12-23 14:44:24 -05:00
Kent Sutherland
ae814eaa89 Fixed FTS extension repeatedly reindexing if the original database was created with the version of the extension that didn't save ftsVersion to the database. 2017-12-05 17:01:02 -06:00
Robbie Hanson
ce9c8dbcee Bug fix for issue #426 2017-11-24 20:10:24 -05:00
Robbie Hanson
9cbc4a0132 Adding unit test for issue #399 & simplifying code 2017-11-24 19:15:22 -05:00
Robbie Hanson
b142d8b69d Adding unit test for issue #426 2017-11-24 18:16:20 -05:00
Robbie Hanson
690cb2de14 Fixing Xcode project for unit tests (desktop) 2017-11-24 18:15:52 -05:00
Robbie Hanson
6324181181 Bug fix for issue #427 - CloudCore extension wasn't registering properly (if not subclassed). 2017-11-04 16:54:27 -05:00
Robbie Hanson
03baeb1336 Updating CocoaLumberjack version in Carthage to fix compiler warnings. 2017-11-04 15:52:51 -05:00
Robbie Hanson
0cd8bf6c8e Adding YapDatabaseCloudCore to Carthage builds. 2017-11-04 10:25:11 -05:00
Robbie Hanson
bf499db56a Fixing swift annotations in YDBCloudKit extension. 2017-10-30 10:51:01 -04:00
Robbie Hanson
4d83a42a11 Bumping podspec version 2017-10-30 10:50:32 -04:00
Robbie Hanson
876e085aa8 Decreasing log levels for YDBCloudKit extension. 2017-10-07 09:42:36 -04:00
Robbie Hanson
15f8dfb048 Updated CloudKitTodo - updated from deprecated CloudKit API's 2017-09-16 17:56:50 -04:00
Robbie Hanson
25f0966d2f Fixing lots of compiler warnings for CloudKitTodo example application. 2017-09-16 13:44:49 -04:00
Robbie Hanson
04ef18a48f Fixing a few minor bugs in YDBCloudCore. Thanks new compiler. 2017-09-16 12:31:55 -04:00
Robbie Hanson
6b6f3785ea Fixing CloudKitTodo sample project via 'pod install'. 2017-09-16 12:23:21 -04:00
Robbie Hanson
dcf12ff94c Fixing Carthage build. 2017-09-16 11:55:24 -04:00
Robbie Hanson
97adeabfe8 Merge branch 'master' of https://github.com/yapstudios/YapDatabase
* 'master' of https://github.com/yapstudios/YapDatabase:
  Xcode 9 warnings
2017-09-06 15:23:07 -04:00
Robbie Hanson
2329a34c1c Adding general status notification for YDBCloudCorePipeline. Helpful in determining if there are any active uploads. 2017-09-06 15:23:02 -04:00
Robbie Hanson
34cd022c82 Adding reverse reference from YDBCloudCorePipeline to YDBCloudCore. This is helpful when receiving notifications from the pipeline. 2017-09-06 15:22:15 -04:00
Robbie Hanson
6c6a941a6e Merge pull request #421 from adamwulf/xcode9-warnings
Xcode 9 warnings
2017-09-06 15:16:52 -04:00
Robbie Hanson
4105aaaf9e Multiple bug fixes for YapDatabaseCloudCore. 2017-08-21 17:35:32 -07:00
Adam Wulf
c1708752f7 Xcode 9 warnings 2017-08-05 21:21:05 -05:00
Robbie Hanson
462c2b5ea4 Bumping podspec 2017-07-18 17:30:57 -07:00
Robbie Hanson
60d9471c7f New method: [YapDatabaseReadWriteTransaction addCompletionQueue:completionBlock:] 2017-07-18 17:26:45 -07:00
Robbie Hanson
8e455fe858 Fixing unit test projects via pod install. 2017-07-18 16:28:01 -07:00
Robbie Hanson
6e863cbe33 Fixing deadlock issue when passing custom connections during extension registration. This is no longer supported. In its place is a way of passing a connection 'config', which allows one to tweak the memory options of the internal database connection. This was the original motivation for the functionality (performance optimizations). Fixes issue #371 2017-07-18 16:26:31 -07:00
Robbie Hanson
b0f9ea9e25 Fixing compiler warning about unused variable. 2017-07-18 15:36:01 -07:00
Robbie Hanson
f8c2f2211c Fixing a bunch of compiler warnings about documentation. 2017-07-18 15:35:43 -07:00
Robbie Hanson
2e9ec5fb6d Trying to fix Travis build. (Switching from xctool to xcodebuild) 2017-07-18 15:16:00 -07:00
Robbie Hanson
05bba703d7 Merge pull request #414 from fabiankr/reachability
Make -initWithReachabilityRef: retain the ref argument, fixing a Clang analyzer warning.
2017-07-18 14:45:33 -07:00
Robbie Hanson
82ca5253b8 Merge branch 'fabiankr-shadow' 2017-07-18 14:36:28 -07:00
Robbie Hanson
fc778139f5 Merge branch 'shadow' of https://github.com/fabiankr/YapDatabase into fabiankr-shadow 2017-07-18 14:17:05 -07:00
Robbie Hanson
cc69137d22 Merge pull request #412 from fabiankr/cast
Add some explicit casts when implicitly converting types.
2017-07-18 14:11:51 -07:00
Robbie Hanson
aed881421a Merge pull request #411 from fabiankr/prefix
Add prefix for NSDate category methods.
2017-07-18 14:09:30 -07:00
Robbie Hanson
361eecf215 Fixing unit test projects via pod install. 2017-07-18 14:08:27 -07:00
Robbie Hanson
86c565e961 Merge branch 'fabiankr-lock' 2017-07-18 13:57:29 -07:00
Fabian Kreiser
ffd8d692c6 -initWithReachabilityRef: now retains the ref argument.
Without this Clang shows an analyzer warning that after calling -initWithReachabilityRef: the ref should be released. Because -initWithReachabilityRef: doesn’t retain the argument, this would result in a dangling pointer.

Warning: This change fixes the issue in YapDatabase internally, but it introduces a memory leak for consumers that are currently using -initWithReachabilityRef without releasing the ref.
2017-07-10 20:38:42 +02:00
Fabian Kreiser
04eb3b9fc0 Replace OSSpinLock with os_unfair_lock when building for macOS 10.12, iOS 10.0, watchOS 3.0 or tvOS 10.0.
OSSpinLock is deprecated and should be replaced by os_unfair_lock. However, os_unfair_lock is not available prior to the aforementioned platforms. Added some defined to seamlessly map between OSSpinLock and os_unfair_lock in YapDatabaseAtomic.h.

YapDatabase deploys to earlier versions so OSSpinLock is still used by default. But if consumers of the framework decide to rebuild it for more modern platforms, os_unfair_lock will be used.
2017-07-10 20:10:56 +02:00
Fabian Kreiser
7354c0b7d0 Add some explicit casts when implicitly converting types.
Very cosmetic change.
2017-07-10 20:10:43 +02:00
Fabian Kreiser
2e299370d7 Add prefix for NSDate category methods.
The NSDictionary category does this already. Without prefixing the method names might clash with consumer code.
2017-07-10 20:10:18 +02:00
Fabian Kreiser
c568675ef3 Fixed shadowing of local variables by renaming them.
While the „Hidden Local Variables“ setting is turned off by default it’s better to give the variables slightly more descriptive names.
2017-07-10 20:10:01 +02:00
Robbie Hanson
4b6f2bb546 Merge pull request #409 from vkovtash/fts5
FTS5 with bm25 ranking queries
2017-06-28 08:52:04 -07:00
Robbie Hanson
227c09a4fb Merge pull request #408 from vkovtash/fix_crossprocess_notifications
Cross process notifications about all db events
2017-06-28 08:46:34 -07:00
Vlad Kovtash
c6ab78abf0 Fixing tests 2017-06-28 12:25:52 +03:00
Vlad Kovtash
8b52eced7d Fixing tests 2017-06-28 12:24:38 +03:00
Vlad Kovtash
e8371ad93d FTS5 with bm25 ranking queries 2017-06-28 11:56:48 +03:00
Vlad Kovtash
bc556eb381 Cross process notifications about all db events 2017-06-28 11:34:04 +03:00
Robbie Hanson
f0b92487a9 Merge pull request #407 from emoryalimam/feature/ReadMeLogo
Add refreshed YapDatabase logo to Readme.
2017-06-27 17:56:47 -07:00
Emory Al-Imam
eaf8358870 Add refreshed YapDatabase logo to Readme. 2017-06-27 14:39:58 -07:00
Robbie Hanson
d6326587cb Removing debug logging leftover from testing. 2017-06-23 16:45:46 -07:00
Robbie Hanson
83dadd4897 Increasing default aggressiveWALTruncationSize. 2017-06-23 16:26:56 -07:00
Robbie Hanson
99ec47fce6 Re-thinking aggressive checkpointing architecture. 2017-06-23 16:22:02 -07:00
Robbie Hanson
e0f0dfc746 Checkpoint optimization: don't queue additional checkpoint operations if there are still pending operations. 2017-06-22 16:00:59 -07:00
Robbie Hanson
e55b8f2693 Fixing iOS compiler issues. 2017-06-22 11:16:01 -07:00
Robbie Hanson
aa50e06cd8 Updating CocoaLumberjack to v3 in Carthage build. 2017-06-22 11:15:37 -07:00
Robbie Hanson
3c8732a674 Fixing Carthage references in Xcode. 2017-06-22 11:15:16 -07:00
Robbie Hanson
2ed41442a4 Merge pull request #404 from ksuther/project-fixes
Fixed build errors and bad project references
2017-06-22 10:42:07 -07:00
Robbie Hanson
d51665ab59 Merge pull request #401 from vkovtash/fix_multipricess_dealloc
Flushing beginImmediateTransactionStatement
2017-06-22 09:59:01 -07:00
Kent Sutherland
6c8eb031d8 Fixed build errors and bad project references
Some of the Xcode group folders were misnamed.
YapDatabaseAutoView wasn't added to the xcodeproj.
Updated modulemaps to include YapDatabaseAutoView.
2017-06-14 10:30:44 -05:00
Robbie Hanson
5de44c5c5d Working on fixing Travis build. 2017-06-12 17:49:25 -07:00
Robbie Hanson
ea55dc3b9e Merge pull request #403 from ksuther/fix-warnings
Fix warnings
2017-06-12 17:43:50 -07:00
Kent Sutherland
c7edd1a146 Silence shadowed variable warning 2017-06-08 11:35:11 -05:00
Kent Sutherland
851645a85a A bitwise & should be a &&
Silences a warning in Xcode 9.
2017-06-08 11:35:04 -05:00
Vlad Kovtash
0ec0f64f83 Flushing beginImmediateTransactionStatement 2017-06-05 16:20:49 +03:00
Robbie Hanson
d8539e1f10 Fixing more podspec issues. 2017-05-17 17:25:21 -07:00
Robbie Hanson
1dbc8722bc Fixing podspec issue. 2017-05-17 14:20:23 -07:00
Robbie Hanson
d90754e9e9 Fixing podspec issue. 2017-05-17 13:23:59 -07:00
Robbie Hanson
2c50c4fbd0 Adding CloudCore extension to podspec. 2017-05-17 10:26:27 -07:00
Robbie Hanson
75a99a1e24 Fixing several bugs in CloudCore extension. 2017-05-17 10:18:40 -07:00
Robbie Hanson
8acad8a661 Fixing crasher in ActionManager extension. And updating other View subclasses to match latest naming conventions. 2017-05-17 10:04:42 -07:00
Robbie Hanson
79339dc4dd Incrementing podspec version. 2017-05-16 14:54:17 -07:00
Robbie Hanson
237fbd6d2f Merge branch 'wikimedia-master' into v3.0 2017-05-16 14:46:32 -07:00
Robbie Hanson
c6c805162b Merge branch 'JimRoepcke-master' into v3.0 2017-05-16 14:25:25 -07:00
Robbie Hanson
efd7cc7a2d Fixing failing unit test. Restoring ‘unpackingOffset’ variable. 2017-05-16 14:18:42 -07:00
Robbie Hanson
d09751b2df Merge branch 'ooopscc-fix_expand_error' into v3.0 2017-05-16 14:14:52 -07:00
Robbie Hanson
1e43966d13 Merge branch 'AntonPalich-yapdatabaseviewtransaction_nullability_fix' into v3.0 2017-05-16 13:57:03 -07:00
Robbie Hanson
cba0f45b58 Merge branch 'MythicLionMan-master' into v3.0 2017-05-16 13:47:24 -07:00
Robbie Hanson
f693e74955 Merge branch 'JamieWhite-ConnectionLog' into v3.0 2017-05-16 13:44:12 -07:00
Robbie Hanson
d8a85ee7b4 Merge branch 'ConnectionLog' of https://github.com/JamieWhite/YapDatabase into JamieWhite-ConnectionLog 2017-05-16 13:43:50 -07:00
Robbie Hanson
ef86b6643e Merge branch '3.0-nullable' of https://github.com/gbrhaz/YapDatabase into gbrhaz-3.0-nullable
# Conflicts:
#	YapDatabase.podspec
2017-05-16 13:39:52 -07:00
Robbie Hanson
1b612ace26 Updating CocoaLumberjack to v3.x in unit test projects. 2017-05-16 13:35:42 -07:00
Robbie Hanson
8526c1e16b Merge branch 'ChatSecure-cocoalumberjack3' into v3.0 2017-05-16 13:21:26 -07:00
Robbie Hanson
e1f0c5cf2e Fixing several new compiler warnings. 2017-05-16 13:20:18 -07:00
Jim Roepcke
fbc688d620 fix: column offsets were wrong 2017-04-27 17:23:58 -07:00
Jim Roepcke
419d9f2157 Bumping podspec version. 2017-04-27 11:56:51 -07:00
Jim Roepcke
a9c46277eb fix: add missing cache lookup 2017-04-27 11:55:49 -07:00
Jim Roepcke
3df0a1abe2 fix: ensure EdgeNotInDatabase flag is set where appropriate to avoid assertion in -deleteEdge: (this only addresses manual edges, protocol edges were not audited) 2017-04-27 11:55:49 -07:00
Robbie Hanson
7f4f95bd34 Minor bug fix for YapDatabaseRelationship extension: rowids are signed, not unsigned. 2017-04-27 11:50:00 -07:00
Harry Richardson
0635ef65a1 Specify nullable for indexPath and newIndexPath 2017-04-19 08:49:40 +01:00
Harry
44c91d72a8 Update YapDatabase.podspec
CocoaLumberjack is now version 3
2017-04-13 15:18:18 +01:00
Chris Ballinger
c256843045 Relax CocoaLumberjack version to ease 2->3 transition
CocoaLumberjack 3 contains breaking changes that only affect Swift 2->3. Although people should update to Swift 3 ASAP, it puts library authors in a weird place to simultaneously support non-pinned versions.
2017-04-04 15:56:37 -07:00
Anton Schukin
5bc0c05a11 Fixed nullability identifiers for some methods in YapDatabaseViewTransaction 2017-02-27 17:08:01 +00:00
Patrick Rogers
c0c79975a6 Added nullability specifier to the return value of rangeOptionsForGroup: to reflect what happens when the group has no range options.
This makes it possible to test for a nil return from swift.
2017-02-02 13:51:47 -05:00
Robbie Hanson
f3fa463944 Updating Xcode projects with Xcode’s latest recommended settings. 2017-01-06 17:57:18 -08:00
Robbie Hanson
1ecb1b861e Merge branch 'master' into v3.0 2017-01-06 17:51:07 -08:00
joewalsh
ede57ea65b didRegisterWithDatabase: --> didRegisterExtension
didRegisterWithDatabase: is never called - it seems it was replaced with didRegisterExtension
2016-11-14 15:56:40 -05:00
ooopscc
1734063300 Fix queryString's expansion error for array parameter in the queryParameter list 2016-11-01 00:42:36 +08:00
Robbie Hanson
5e86c2d95c New version of YapDatabaseCloudCore (still in beta). This version simplifies many things. 2016-10-26 10:46:42 -07:00
Robbie Hanson
8ea3b2f216 Updating deployment targets so we can use a modern version of SQLCipher (and in turn, a modern version of SQLite via SQLCipher). 2016-10-10 10:46:50 -07:00
Robbie Hanson
719133d35a Bumping podspec version. 2016-10-10 09:34:41 -07:00
Robbie Hanson
aaf17f1c27 Merge pull request #352 from samsonjs/change-file-path-to-url
Update comments and docs referring to file paths
2016-09-08 15:36:55 -07:00
Sami Samhuri
9322d0a759 fix a typo 2016-09-08 15:33:35 -07:00
Robbie Hanson
188eb8cade Fixing subtle timing bug in new ActionManager suspend/resume code. 2016-09-08 14:53:23 -07:00
Robbie Hanson
885825e2a3 Fixing some naming conflicts with official Reachability pod. 2016-09-08 14:34:16 -07:00
Robbie Hanson
d710dae131 Bug fix for issue #335 2016-09-08 14:18:09 -07:00
Robbie Hanson
59e4be80ad Replacing 'Reachability' dependency with embedded 'YapReachability' class. This allows the ActionManager to run on tvOS & watchOS. 2016-09-08 11:24:45 -07:00
Robbie Hanson
400261e0fb Merge pull request #361 from siuying/fix-nullable
Fix [YapcollectionKey isEqual:] nullability
2016-09-08 08:23:03 -07:00
Robbie Hanson
996e0e0d8d More problems with CocoaPods. 2016-09-07 21:06:47 -07:00
Robbie Hanson
a4f2b9f14c Fixing Xcode projects (due to filename change in previous commit). 2016-09-07 17:49:17 -07:00
Robbie Hanson
de9e00a086 Workaround for CocoaPods v1 bug. Fixes issue #322. 2016-09-07 17:46:48 -07:00
Robbie Hanson
a2eb9e89d9 Adding watchOS build for Carthage. 2016-09-07 16:28:55 -07:00
Robbie Hanson
bdb704ccc9 Updating Unit Test projects to use latest podspec. 2016-09-07 15:14:12 -07:00
Robbie Hanson
7b6b5c30cc Fixing podspec to work with CocoaPods v1. It wouldn't "lint" in it's previous form, and thus couldn't be pushed. 2016-09-07 15:13:19 -07:00
Francis Chong
ed5e42db90 fix nullability 2016-09-06 17:35:26 +08:00
Robbie Hanson
887f92b64d Fixes for watchOS build. 2016-09-01 15:27:24 -07:00
Robbie Hanson
0374159e92 Adding missing extension (cross process notification) to tvOS build. 2016-09-01 15:25:26 -07:00
Robbie Hanson
ebbe36afc1 Incrementing podspec version. 2016-09-01 14:25:50 -07:00
Robbie Hanson
695e7df2eb Fixing typo in Podspec. 2016-09-01 14:22:38 -07:00
Robbie Hanson
3b452b0929 Fixing tvOS build for Carthage & CocoaPods+Swift. 2016-09-01 14:10:32 -07:00
Sami Samhuri
68ba99fdb1 update comments and docs referring to file URLs 2016-08-06 13:11:56 -07:00
Robbie Hanson
e05584ad54 Merge branch 'accatyyc-master' 2016-07-21 11:16:33 -07:00
Robbie Hanson
fe04b8434f Adding Xcode-watch project for unit testing. Encountered a bug with CocoaPods. Awaiting CocoaPods pull request 5608 to be merged. 2016-07-21 11:16:09 -07:00
Robbie Hanson
aff027d6d0 Re-adding support for TARGET_OS_TV in a few places. 2016-07-21 10:41:48 -07:00
Robbie Hanson
0d33ad7e30 Bug fix for issue #345 - Cast issue in hashRecordID:databaseIdentifier: 2016-07-21 09:37:24 -07:00
Robbie Hanson
34311a2f2a Bug fix for issue #345 - Cast issue in hashRecordID:databaseIdentifier: 2016-07-21 09:35:44 -07:00
Robbie Hanson
bce88f7bc6 Merge pull request #346 from siuying/swift-compatability
Fix a nullable parameter
2016-07-21 09:24:26 -07:00
Robbie Hanson
ca5269579b Merge pull request #347 from samsonjs/samsonjs-typo
fix a typo in MyDatabaseObject example
2016-07-20 08:08:17 -07:00
Sami Samhuri
fcdd5d76dd fix a typo in MyDatabaseObject example 2016-07-16 20:53:16 -07:00
Francis Chong
2374472cf7 Fix getRecordChangeTag:hasPendingModifications:hasPendingDelete:forRecordID:, first parameter should be nullable 2016-07-08 18:08:35 +08:00
Robbie Hanson
10604d4069 Adding YapDatabaseCloudCore extension. This extension is in beta. 2016-07-07 14:46:43 -07:00
Robbie Hanson
d15089871b Added ManualViewExample project. 2016-06-21 15:17:10 -07:00
Robbie Hanson
e85771f7cc Fixing SearchResultsExample project. 2016-06-18 17:40:28 -07:00
Robbie Hanson
3aa0422ac4 Minor bug fix for YapDatabaseRelationship extension: rowids are signed, not unsigned. 2016-06-18 15:31:08 -07:00
Robbie Hanson
d288b2f3bf Working on YapDatabaseManualView extension. 2016-06-18 15:30:21 -07:00
Robbie Hanson
6013595e79 Fixing missing dependency in podspec 2016-06-17 11:23:49 -07:00
Robbie Hanson
aaf9941287 Renaming YapDatabaseExtension hook methods to match standard naming conventions. 2016-06-17 11:20:22 -07:00
Robbie Hanson
2e540c2a2c Fixing Xcode-desktop project. 2016-06-17 10:36:35 -07:00
Robbie Hanson
544bc845da Renaming folder: "SearchResults" -> "SearchResultsView" 2016-06-17 10:35:31 -07:00
Robbie Hanson
6290e0d2a3 Renaming folder: "FilteredViews" -> "FilteredView" 2016-06-17 10:32:01 -07:00
Robbie Hanson
c19cef115f Refactoring YapDatabaseView code: Now the core underlying architecture is split into its own abstract base class. This will allow other view-based classes to be created easier. 2016-06-16 17:53:24 -07:00
Joel Ekström
ce4c8fa6e0 Use TARGET_OS_IOS instead of TARGET_OS_IPHONE
TARGET_OS_IPHONE is 1 when compiling for watchOS for some reason.
This has some problems since it doesn't exclude incompatible code
when compiling for watchOS (TARGET_OS_WATCH is 1 as well).

TARGET_OS_IOS solves this problem and will be 0 if
TARGET_OS_WATCHOS is 1.
2016-06-10 13:31:31 +02:00
Joel Ekström
d913185556 Add watchos deployment target to podspec 2016-06-10 10:57:16 +02:00
Robbie Hanson
dfb6d88c74 Merge pull request #334 from skeeet/YapActionManager_dealloc_fix
fix: YapActionmanager properly deallocating internal timer.
2016-06-08 09:52:59 -07:00
Aleksei Shevchenko
e514b4d67e fix: YapActionmanager properly deallocating internal timer.
See #332
2016-06-08 03:49:33 -07:00
Jamie White
c35a268897 Improving the connection logging 2016-05-19 15:37:42 +01:00
Robbie Hanson
164202278b Incrementing podspec version. 2016-05-07 09:15:10 -07:00
Robbie Hanson
dfb5d29ec6 Bug fix for issue #318 - YapDatabaseRelationshipTransaction.sourceNodeForEdge should return nullable type 2016-04-28 09:17:46 -07:00
Robbie Hanson
e41924eabe Merge branch 'master' of https://github.com/yapstudios/YapDatabase 2016-04-23 10:30:33 -07:00
Robbie Hanson
f97c9d89fe Fixing CloudKitTodo sample Xcode project. 2016-04-23 10:30:26 -07:00
Robbie Hanson
f0ad425d50 Merge pull request #315 from davidchiles/fix-reachability
Moved Reachability import to .m file. Fixes #308
2016-04-20 16:29:06 -07:00
David Chiles
dfc2c26b5e Moved Reachability import to .m file. Fixes #308 2016-04-20 16:20:28 -07:00
Robbie Hanson
7592da0ae4 Fixing podspec for tvos. (take 2) 2016-04-12 14:45:44 -07:00
Robbie Hanson
e1b94efc0c Fixing podspec for tvos. 2016-04-12 12:38:03 -07:00
Robbie Hanson
8f5354b476 Incrementing podspec version. 2016-04-12 12:20:22 -07:00
Robbie Hanson
abcd9d0aa2 Adding a "flushTransactions" method to YapDatabaseConnection. Makes it a little easier to find out when all previously queued transactions on a connection have completed. 2016-04-06 15:34:23 -07:00
Robbie Hanson
ea909cc702 Critical bug fix: recent changes created a situation where the database system may incorrectly think extensions have been orphaned, and automatically delete their database tables during the first readWriteTransaction. 2016-04-06 11:50:00 -07:00
Robbie Hanson
62f4af83c2 Incrementing version number in framework build. 2016-04-05 18:38:40 -07:00
Robbie Hanson
17ef076a6b Merge branch 'weak-cloudkit' of https://github.com/pcsm/YapDatabase into pcsm-weak-cloudkit 2016-04-05 18:24:00 -07:00
Robbie Hanson
0fa554cb03 Merge branch 'master' into v2.9 2016-04-05 17:27:07 -07:00
Robbie Hanson
d648c078b2 Fixing bug introduced in commit from earlier today (6f1a844) 2016-04-05 17:12:45 -07:00
Robbie Hanson
33a1806f4f Adding more helpful compiler flags to unit test projects. 2016-04-05 17:08:15 -07:00
Robbie Hanson
cf2d0b9781 Fixing bug in YapBidirectionalCache. 2016-04-05 17:03:15 -07:00
Robbie Hanson
8d9ddbeffd Fixing compiler warnings (-Wincompatible-pointer-types) 2016-04-05 17:02:20 -07:00
Robbie Hanson
964de0e83f Fixing compiler warning: "used uninitialized" variable (-Wsometimes-uninitialized) 2016-04-05 17:01:45 -07:00
Robbie Hanson
02848bcdb1 Adding a few helpful compiler flags to unit test projects. 2016-04-05 17:00:49 -07:00
Robbie Hanson
6f1a844d6c Bug fix for issue #307 - Memory corruption 2016-04-05 15:12:54 -07:00
Robbie Hanson
8688746cc6 Bug fix for issue #303 - Memory corruption 2016-04-04 16:32:13 -07:00
Robbie Hanson
49a525bd59 Update README.md 2016-04-02 09:34:15 -07:00
Robbie Hanson
dea8856405 Minor code cleanup. 2016-04-01 18:07:29 -07:00
Robbie Hanson
b8480696a0 Explicitly copying blocks as a safety precaution. 2016-04-01 17:39:09 -07:00
Robbie Hanson
a22ecb9854 Removing some dead code. 2016-04-01 17:28:28 -07:00
Robbie Hanson
7322c2e8f5 Fixing bug that was introduced in a recent performance improvement (commit 7e4e3a9). 2016-03-31 15:37:46 -07:00
Robbie Hanson
d701237862 Performance improvements for YapBidirectionalCache. 2016-03-30 11:36:45 -07:00
Robbie Hanson
98a983e03d Performance improvements for YapCache. 2016-03-30 11:35:45 -07:00
Robbie Hanson
e88a036c00 Enabling callback optimizations for keyCache. 2016-03-30 10:05:56 -07:00
Robbie Hanson
191a5807d3 Fixing assertion error 2016-03-29 13:21:48 -07:00
Robbie Hanson
2fc2910962 Adding new extensions to Carthage build project. 2016-03-29 11:22:56 -07:00
Robbie Hanson
1043543a59 Adding new extensions to modulemap. 2016-03-29 11:22:11 -07:00
Robbie Hanson
b0f07a2613 Fixing compiler warning in CloudKit extension. 2016-03-29 10:25:26 -07:00
Robbie Hanson
4240f0a87b Fixing Carthage build project. 2016-03-29 10:25:09 -07:00
Robbie Hanson
98b6cce1fe Merge branch 'master' into v2.9 2016-03-29 10:11:11 -07:00
Robbie Hanson
94c56ecf72 Merge pull request #302 from JamieWhite/AppExtensionAPIOnly
Toggling on App Extension API Only
2016-03-29 10:09:11 -07:00
Robbie Hanson
71b14a6f75 Performance improvement: converting keyCache to a bidirectional-cache. This allows us to skip the index sometimes, and directly use rowid lookups. 2016-03-28 11:32:25 -07:00
Robbie Hanson
7d7891347c Updating unit test projects via 'pod update'. 2016-03-28 11:30:20 -07:00
Robbie Hanson
1c1c7b5136 Adding "obj per sec" output to benchmarks. 2016-03-28 10:29:44 -07:00
Robbie Hanson
7396fd924b Bug fix: internal method for fetching metadata may have returned YapNull (instead of nil) 2016-03-28 10:27:04 -07:00
Robbie Hanson
ba41cce909 Bug fix for YapBidirectionalCache 2016-03-28 10:17:59 -07:00
Robbie Hanson
1f8e484a0c Minor performance improvement: internal hasRowid method now makes use of the cache. 2016-03-27 17:11:16 -07:00
Robbie Hanson
74198971e2 Minor bug fix: error logs were naming incorrect statements. 2016-03-27 17:09:05 -07:00
Robbie Hanson
7e4e3a92d3 Minor performance optimization: process the change-sets outside the snapshotQueue. This decreases contention on the queue between connections. 2016-03-27 16:40:48 -07:00
Robbie Hanson
c14327e238 Minor performance optimization: cache the 'enableMultiProcessSupport' variable to avoid method invocations every time. 2016-03-27 15:24:24 -07:00
Robbie Hanson
d648243d61 Bug fix for multiProcess mode: Adding another FlushMemoryFlags option in order to notify extensions that they should flush any "state" that they loaded directly from the database. 2016-03-27 15:07:17 -07:00
Robbie Hanson
27e4627eed Merge branch 'master' into v2.9 2016-03-27 14:21:44 -07:00
Robbie Hanson
ae7b9a8217 Fixing "Xcode-desktop" project via 'pod update'. 2016-03-27 14:20:29 -07:00
Robbie Hanson
5496becb36 Adding defaultCallBacks struct for YapBidirectionalCache. 2016-03-17 10:43:10 -07:00
Robbie Hanson
51a9ff0177 Merge pull request #305 from nolanw/connectionproxy-header-doc-fix
Fix minor header documentation typos in YapDatabaseConnectionProxy.h
2016-03-17 09:24:17 -07:00
Nolan Waite
86094c4336 Fix documentation typos in YapDatabaseConnectionProxy.h. 2016-03-17 10:28:39 -03:00
Robbie Hanson
54cdf55aca Adding a bidirectional cache. 2016-03-16 17:56:09 -07:00
Robbie Hanson
f2c3f6a172 Merge pull request #304 from nolanw/crash-missing-metadata-postsanitizer
Fix test for metadata post sanitizer before calling it.
2016-03-16 12:28:02 -07:00
Robbie Hanson
960c5eb657 Exposing YapCollectionKey's C-style hash function. 2016-03-16 12:26:14 -07:00
Robbie Hanson
5f4e1cee4e Standardizing the name of an internal define for toggling statistics in YapCache. 2016-03-16 12:25:33 -07:00
Nolan Waite
31bfb73b2b Fix test for metadata post sanitizer before calling it. 2016-03-16 10:56:20 -03:00
Robbie Hanson
e87080c167 Fixing compiler warnings in unit test code. 2016-03-15 16:20:30 -07:00
Robbie Hanson
2fd547ba59 Minor performance optimization for processing change-sets. 2016-03-15 15:58:25 -07:00
Robbie Hanson
4724e5249c Merge branch 'master' into v2.9 2016-03-14 16:15:23 -07:00
Robbie Hanson
91f6264bfa Possible bug fix for issue #303 2016-03-14 15:51:47 -07:00
Robbie Hanson
eb2ad3aeb2 Merge pull request #298 from nolanw/mappings-nullable
Mark view parameter as nonnull in view mappings initializers.
2016-03-14 10:02:08 -07:00
Jamie White
d6f812d36b Toggling on App Extension API Only
This silences any warnings when using from an extension
2016-03-14 16:51:52 +00:00
Robbie Hanson
7f11b871f5 Merge pull request #301 from ReadmeCritic/master
Update README URLs based on HTTP redirects
2016-03-14 09:38:57 -07:00
ReadmeCritic
67a63d865c Update README URLs based on HTTP redirects 2016-03-14 07:25:02 -07:00
Robbie Hanson
7387530f47 Bug fix: URL comparisons weren't working properly in all cases. 2016-03-10 17:02:40 -08:00
Robbie Hanson
5dab8cc767 Adding count property to YapSet. 2016-03-10 13:40:47 -08:00
Nolan Waite
bddda8aac8 Mark view parameter as nonnull in view mappings initializers. 2016-03-10 11:54:37 -04:00
Robbie Hanson
65051543ee Bug fix for issue #294 - Logging w/ NSLog fails 2016-03-06 11:53:29 -08:00
Robbie Hanson
de4e71d43a Fixing compiler warning: missing format parameters 2016-03-06 11:39:45 -08:00
Robbie Hanson
63bd5d0258 Updating CrossProcessNotification extension to use the new 'didRegisterWithDatabase' hook. 2016-03-06 11:35:44 -08:00
Robbie Hanson
7acc3f0ee3 Fixing compiler warning: missing explicit cast 2016-03-06 11:34:53 -08:00
Robbie Hanson
3e1f6da5ea Fixing compiler warning: missing include statement 2016-03-06 11:34:33 -08:00
Robbie Hanson
4c32bdf392 Fixing "Xcode-desktop" project via 'pod update'. 2016-03-06 11:22:22 -08:00
Robbie Hanson
2806e2e78c Merge branch 'experimental/action-manager' into v2.9 2016-03-06 11:12:46 -08:00
Robbie Hanson
a55a6cf027 Adding optional queue parameter to YapActionItem. 2016-03-04 11:45:30 -08:00
Robbie Hanson
abe4b5546f Fixing nullability annotations for ActionManager. 2016-03-04 11:06:58 -08:00
Jason Grlicky
6dacf29f5e Set minimum deployment target for OS X to 10.8 and linked CloudKit framework weakly 2016-03-03 16:59:58 -08:00
Robbie Hanson
890cb2e6f0 Addressing questions for me marked with "@robbie". 2016-03-03 14:54:03 -08:00
Robbie Hanson
80ba6a04d5 Merge branch 'snipsco-task/multiprocess' into v2.9 2016-03-03 11:38:40 -08:00
Jason Grlicky
41ffe6c9ea Merge pull request #1 from yapstudios/master
Updating from master
2016-03-03 11:36:33 -08:00
Robbie Hanson
354f992762 Bumping podspec version. 2016-03-03 11:19:33 -08:00
maelp
3d6f1f4bb3 trim lines 2016-02-27 21:00:51 +01:00
maelp
09d559e21c Increase delay 2016-02-27 20:59:49 +01:00
maelp
d10394fe3d Rename 2016-02-27 20:59:34 +01:00
maelp
c288c81ca7 Output 2016-02-27 20:59:07 +01:00
maelp
8d5bb7e82b Update script 2016-02-27 20:57:47 +01:00
maelp
80c965b942 Change log 2016-02-27 20:39:10 +01:00
maelp
50aeb365ae Update script 2016-02-27 20:38:34 +01:00
maelp
c8a6a31eed Update script 2016-02-27 20:27:49 +01:00
maelp
e96224e8eb Update script 2016-02-27 20:12:58 +01:00
maelp
ed5870f170 Add interface 2016-02-27 20:09:10 +01:00
maelp
de39b53c94 Add specialBehavior flag 2016-02-27 20:07:43 +01:00
Robbie Hanson
7179e3a737 Merge branch 'master' of https://github.com/yapstudios/YapDatabase 2016-02-26 10:51:31 -08:00
Robbie Hanson
e7326e4bf9 Bug fix for issue #289 - Incorrect nullability annotation & incomplete documentation. 2016-02-26 10:51:22 -08:00
Robbie Hanson
9d302cba3e Merge pull request #290 from aranasaurus/master
Add tests for #288 - YapDatabaseHooks extension doesn't seem to be respecting the allowedCollections property when specified
2016-02-26 09:43:08 -08:00
Ryan Arana
7f8bb1bd55 Add tests for #288 - YapDatabaseHooks extension doesn't seem to be respecting the allowedCollections property when specified 2016-02-26 09:39:28 -08:00
Robbie Hanson
1a9b67cedb Bug fix for issue #288 - YapDatabaseHooks extension doesn't seem to be respecting the allowedCollections property when specified 2016-02-26 09:04:59 -08:00
Robbie Hanson
12052e7e43 Bug fix for ActionManager. 2016-02-18 12:27:03 -08:00
Robbie Hanson
810a48a90f Improving performance of ActionManager by caching actionItems responses for objects. 2016-02-18 12:18:15 -08:00
Robbie Hanson
178d615947 Refactoring ActionManager extension to work more like a traditional extension. Also improving the public API to make it easier to use. 2016-02-18 11:18:53 -08:00
Robbie Hanson
fcad275ccd Minor API tweaks to YapDatabaseExtension class concerning registration checks. 2016-02-18 11:12:14 -08:00
Robbie Hanson
550736661d Adding didRegisterWithDatabase hook method for extensions. 2016-02-17 19:11:10 -08:00
Robbie Hanson
108da73757 Adding ability for extensions to see the global changeset, rather than only their local changeset. (part 2) 2016-02-17 19:10:15 -08:00
Robbie Hanson
717495828e Adding ability for extensions to see the global changeset, rather than only their local changeset. 2016-02-17 17:21:00 -08:00
Robbie Hanson
6fb4e15c1d Adding YapDatabaseActionManager to Xcode-desktop testing project. 2016-02-17 16:52:52 -08:00
Robbie Hanson
bcd4b8f360 Merge branch 'master' into experimental/action-manager 2016-02-17 16:01:26 -08:00
maelp
67e12ef206 Update comment 2016-02-17 23:58:30 +01:00
maelp
7b1f186cff Test extension 2016-02-17 23:51:04 +01:00
maelp
f9ef18818a Remove log 2016-02-17 23:24:08 +01:00
maelp
bc05bafeed Remove log 2016-02-17 23:22:20 +01:00
maelp
48e21f1de5 Update code 2016-02-17 22:33:32 +01:00
maelp
0100aae30b Add trace 2016-02-17 13:52:12 +01:00
maelp
233a9180b1 Set Lumberjack 2016-02-17 13:49:00 +01:00
maelp
5950338160 Add comments 2016-02-17 13:48:19 +01:00
maelp
5f81e4edcf Add comment 2016-02-17 13:42:55 +01:00
maelp
89f57c4c73 Add comment 2016-02-17 13:36:54 +01:00
maelp
11b70530b5 Add description 2016-02-16 18:41:03 +01:00
maelp
eb918874ed Remove comment 2016-02-16 18:40:01 +01:00
jeremiegirault
2ed6f14a8c CrossProcessNotifications now skips modification in same process (handled by changesets) 2016-02-16 15:25:07 +01:00
jeremiegirault
47dce53fc9 updated pods / added crossprocessnotification extension 2016-02-16 14:42:34 +01:00
jeremiegirault
5bedef007f removed comment 2016-02-16 11:13:35 +01:00
maelp
72774d2094 Add busy_handler 2016-02-16 11:05:46 +01:00
maelp
cb5df161c8 Use milisecond sleep method 2016-02-15 23:09:42 +01:00
maelp
36092a6604 Add logs 2016-02-15 23:07:34 +01:00
Robbie Hanson
d23d053513 Added another internal (rowid) method which seemed to be missing. 2016-02-15 10:50:30 -08:00
maelp
8b6d5f59d4 Update comments 2016-02-15 19:12:38 +01:00
maelp
231329ab7e Update comment 2016-02-15 18:54:55 +01:00
jeremiegirault
689ad496aa current update 2016-02-15 18:27:34 +01:00
jeremiegirault
c7eb5b27f0 some changes to handle external changes 2016-02-15 17:40:41 +01:00
jeremiegirault
335a007d86 added options start with multiprocess support / added tests 2016-02-15 11:30:11 +01:00
Robbie Hanson
002fb50a1b Merge branch 'master' of https://github.com/yapstudios/YapDatabase 2016-02-08 11:06:22 -08:00
Robbie Hanson
4ff33cf6aa Bug fix for issue #278 - compiler isn't warning about improper parameter type 2016-02-08 11:06:02 -08:00
Robbie Hanson
95ef75fca1 Merge pull request #277 from ksuther/shadowed-variable
Silence a shadowed variable declaration warning
2016-02-04 09:33:37 -08:00
Kent Sutherland
d6845505fe Renamed data to plistData to avoid a shadowed variable declaration warning.
Renamed comp to plistComp so it matches plistData.
2016-02-04 11:58:40 -05:00
Robbie Hanson
180edc8b43 Bumping podspec version. 2016-02-03 12:08:38 -08:00
Robbie Hanson
716b0ed14d Improved default URL serialization: If the file doesn't exist, the serializer will find a parent directory that does exist, generate a bookmark for that, and then serialize the bookmark along with the relative path of the non-existent file. This allows for proper serialization of files that don't yet exist (file created after database edge). 2016-01-26 16:51:55 -08:00
Robbie Hanson
006069baed Adding another asyncUnregisterExtension method for convenience. 2016-01-25 10:06:27 -08:00
Robbie Hanson
947225aede Bug fixes for enumerating changed keys from notifications. Code did not take into account deleted rows. 2016-01-25 09:57:49 -08:00
Robbie Hanson
f11608ff08 Bug fix for didClearCollection:inNotifications. Code did not take into account if [transaction removeAllObjectsInAllCollections] was invoked. 2016-01-25 09:56:34 -08:00
Robbie Hanson
dd93e5d7d2 Merge pull request #270 from ainopara/fix-use-mutable-copy-for-deleted-recordID
use mutableCopy for assign deletedRecordIDs.
2016-01-25 09:04:37 -08:00
Robbie Hanson
2cd6af01e1 Merge pull request #271 from Amosel/master
keysToRestore should be nullable
2016-01-25 08:57:42 -08:00
Amos Elmaliah
594fc5bf3c keysToRestore should be nullable 2016-01-25 11:53:28 -05:00
ainopara
353a939380 use mutableCopy for assign deletedRecordIDs. 2016-01-24 21:54:25 +08:00
Robbie Hanson
e3ba0cc88b Adding another asyncRegisterExtension method for convenience. 2016-01-22 18:00:44 -08:00
Robbie Hanson
25d924c590 More nullability annotation fixes. 2016-01-22 17:38:20 -08:00
Robbie Hanson
097d3880ef Bug fix for issue #266 - Bug in repopulateTables in YapDatabaseCloudKitTransaction 2016-01-19 10:07:09 -08:00
Robbie Hanson
8e63cd9e41 Merge pull request #265 from SofteqDG/secondary-index-read-transaction
Read transaction in YapDatabaseSecondaryIndexHandler
2016-01-19 09:58:55 -08:00
SofteqDG
d496946631 YapDatabaseSecondaryIndex tests fix. 2016-01-19 16:32:18 +03:00
SofteqDG
44f52f300d Read transaction in YapDatabaseSecondaryIndexHandler 2016-01-19 15:49:04 +03:00
Robbie Hanson
48244c266b Adding some missing nullable attributes. 2016-01-15 14:59:57 -08:00
Robbie Hanson
5177f8acda Bumping podspec version 2016-01-14 16:11:55 -08:00
Robbie Hanson
47a65a11dc Fixing modulemap (didn't include YapDatabaseConnectionProxy) 2016-01-14 16:08:50 -08:00
Robbie Hanson
c3d1495bfc Bumping podspec version 2016-01-12 14:59:49 -08:00
Robbie Hanson
f4b205e76b Merge branch 'master' into v2.8 2016-01-12 14:50:41 -08:00
Robbie Hanson
64fe9d8919 Updating UnitTest project/workspace via "pod update" 2016-01-12 14:44:16 -08:00
Robbie Hanson
7a373a7e5f Updating UnitTest project/workspace via "pod update" 2016-01-12 14:39:39 -08:00
Robbie Hanson
6f26aaf9fe Switching from YapEnumerateStatement idea to something faster. 2016-01-12 14:26:02 -08:00
Robbie Hanson
3693a61f8f Adding test code for YapDatabaseRelationship version migration. 2016-01-12 11:43:47 -08:00
Robbie Hanson
f2c033dd33 Updating UnitTest project/workspace via "pod update" 2016-01-12 11:16:03 -08:00
Robbie Hanson
0b1dba8ca8 YapDatabaseRelationship now uses NSURL-based file references. 2016-01-12 10:37:04 -08:00
Robbie Hanson
b6513b92a4 Merge pull request #263 from jmnavarro/check-sqlcipher-and-standard
Check if the user has included both the standard and SQLCipher pods
2016-01-07 10:06:10 -08:00
JM
7b650c9bdc Check if the user has included both the standard and SQLCipher pods 2016-01-07 17:37:47 +01:00
Robbie Hanson
3e72cce737 Merge pull request #258 from heiberg/search_results_example_compilation_fix
Fix compilation error in SearchResultsExample
2016-01-05 14:24:45 -08:00
Morten Heiberg
1c3e4f7bc3 Updated Yap pod in search example to fix missing yap_vfs_shim files. 2016-01-03 19:24:56 +01:00
Robbie Hanson
1f3b4f17d0 Bug fix for issue #216 2015-12-30 11:23:41 -08:00
Robbie Hanson
99e0920033 Fixing compiler warning about missing nullability annotations. 2015-12-30 11:21:22 -08:00
Robbie Hanson
408eade6cc Merge branch 'master' into v2.8 2015-12-30 10:40:30 -08:00
Robbie Hanson
add7384334 Merge branch 'master' of https://github.com/yapstudios/YapDatabase 2015-12-30 10:38:26 -08:00
Robbie Hanson
1449cfb80d Bug fix for issue #256 2015-12-30 10:36:23 -08:00
Robbie Hanson
d0432e1971 Merge pull request #257 from ngocluu/nullable-metadata
Mark metadata as optional.
2015-12-30 09:51:56 -08:00
Ngoc Luu
f5ec49d17f Mark metadata as optional. 2015-12-30 10:55:40 +07:00
Robbie Hanson
0751bfda14 Fixing enumeration within enumeration bug. Issue #255 2015-12-28 17:56:50 -08:00
Robbie Hanson
2c16b53d32 Adding ConnectionProxy to podspec 2015-12-26 17:30:24 -08:00
Robbie Hanson
8bf6e59037 Merge branch 'experimental/connection-proxy' into v2.8 2015-12-26 16:44:35 -08:00
Robbie Hanson
2cd013b0d7 Merge branch 'master' into v2.8 2015-12-26 16:35:46 -08:00
Robbie Hanson
81edc45187 Improving fix for issue #252 2015-12-26 16:34:58 -08:00
Robbie Hanson
7f4b59b011 Adding deadlock detection for executing a transaction within a transaction. Issue #252 2015-12-23 12:02:05 -08:00
Robbie Hanson
4a6a44e515 Improving nullable annotations. Fixes issue #253 2015-12-23 09:56:53 -08:00
Robbie Hanson
c3a794c88f Bug fix for connectionProxy 2015-12-17 15:01:50 -08:00
Robbie Hanson
3f38cca365 Improvements for connectionProxy architecture. 2015-12-17 11:51:35 -08:00
Robbie Hanson
4665e9c52f Adding support for metadata to connectionProxy. 2015-12-15 14:52:31 -08:00
Robbie Hanson
3fa17af841 Updated Hooks extension to include TouchedObject & TouchedMetadata. 2015-12-13 11:18:44 -08:00
Robbie Hanson
9d273ac111 Minor documentation tweak. 2015-12-13 11:02:45 -08:00
Robbie Hanson
4152dc9396 Merge branch 'master' into v2.8 2015-12-09 10:46:34 -08:00
Robbie Hanson
58b4e364fc Touching XIB with latest Xcode. 2015-12-09 10:43:33 -08:00
Robbie Hanson
823c5546b3 Minor documentation fix 2015-12-09 10:43:15 -08:00
Robbie Hanson
d8e045711b Bumping podspec version to 2.7.7 2015-12-05 17:52:07 -08:00
Robbie Hanson
b5edcb84c0 Adding tvOS support to podspec, and adding tvOS project for unit testing. 2015-12-05 17:34:46 -08:00
Robbie Hanson
2aaa26b342 Added missing nullable attribute. 2015-12-05 16:37:04 -08:00
Robbie Hanson
af0f719688 New podspec layout to allow installation of specific extensions. 2015-12-05 16:19:26 -08:00
Robbie Hanson
e192db358a Minor bug fix & code cleanup for ConnectionProxy. 2015-12-05 16:09:16 -08:00
Robbie Hanson
130fc6006d Adding Reachability to SQLCipher podspec 2015-12-02 09:40:33 -08:00
Robbie Hanson
5942910431 Bug fix for ActionManager extension: forgot to start the reachability notifier 2015-12-02 09:39:38 -08:00
Robbie Hanson
c78701a264 Merge pull request #248 from davidchiles/patch-1
Added dependency on Reachability to Podspec #235
2015-11-25 11:43:50 -08:00
David Chiles
5eb4e050d1 Added dependency on Reachability to Podspec #235 2015-11-25 11:41:08 -08:00
Robbie Hanson
e9f6fcb0d5 Bug fix for YapDatabaseActionManager. Issue #235 2015-11-24 11:05:33 -08:00
Robbie Hanson
6e9e89b56e CloudKitTodo example: I've noticed a few times where operations seem to be disabled when not on WiFi (even though allowsCellularAccess theoretically defaults to YES) 2015-11-23 18:55:18 -08:00
Robbie Hanson
b05ebaa97b CloudKitTodo example: automatically bring up the keyboard when going into TodoItem editing screen. 2015-11-23 18:54:06 -08:00
Robbie Hanson
f42af3200a Another performance improvement for issue #246 - [CKRecord copy] bug has been fixed by Apple. 2015-11-23 16:08:22 -08:00
Robbie Hanson
b0229d49ea Performance improvement for issue #246 2015-11-23 10:46:13 -08:00
Robbie Hanson
3604160117 Removing unnecessary description from XCTAssert statements. 2015-11-23 10:38:14 -08:00
Robbie Hanson
9e75cae54e Fixing CloudKitTodo project. 2015-11-23 10:37:40 -08:00
Robbie Hanson
4a9b41090c Working on connection-proxy idea. 2015-11-23 10:30:52 -08:00
Robbie Hanson
21dd704953 Bumping podspec to v2.7.6 2015-11-13 11:21:20 -08:00
Robbie Hanson
3d67b0eae5 Critical bug fix for issue #245 - deadlock condition in YapDatabaseConnection 2015-11-13 10:47:03 -08:00
Robbie Hanson
d93d4d2eda Bumping podspec to v2.7.5 2015-11-12 09:35:26 -08:00
Robbie Hanson
56292f0380 Adding YapDatabaseActionManager extension/utility 2015-11-11 17:04:37 -08:00
Robbie Hanson
1d71f8388a Merge pull request #244 from danthorpe/YAP-244_add_nullable_attribute_to_property_which_defaults_nil
[YAP-244]: Adds nullable attribute to properties consistently.
2015-11-11 10:05:12 -08:00
Robbie Hanson
640875ac7c Merge pull request #243 from danthorpe/YAP-243_add_missing_files_to_project
[YAP-243]: Adds missing yap_vfs_shim source files.
2015-11-11 09:59:25 -08:00
Daniel Thorpe
7b5ec3b988 [YAP-244]: Adds nullable attribute to properties consistently. 2015-11-11 17:10:29 +00:00
Daniel Thorpe
36e51aa719 Merge branch 'master' of https://github.com/yapstudios/YapDatabase into YAP-243_add_missing_files_to_project 2015-11-11 16:58:06 +00:00
Daniel Thorpe
6ed424beb0 [YAP-243]: Adds missing yap_vfs_shim source files.
This was preventing building YapDatabase from Xcode (includes Carthage), but wouldn't affect the unit tests which are performed in projects created with CocoaPods.
2015-11-11 12:24:01 +00:00
Robbie Hanson
b35beb6aae Merge pull request #242 from ReadmeCritic/master
Update Readme
2015-11-10 10:36:52 -08:00
Robbie Hanson
0a0acd88af Merge pull request #241 from danthorpe/YAP-241_view_options_nullable_allowed_collections
[YAP-241]: Adds nullable attribute to a property which defaults to nil
2015-11-10 10:34:00 -08:00
ReadmeCritic
e7b43a7685 Readme: Update redirects 2015-11-10 08:16:45 -08:00
Daniel Thorpe
0d03e33c8c [YAP-241]: Adds nullable attribute to a property which defaults to nil 2015-11-09 13:29:23 +00:00
Robbie Hanson
d7648dae8e A bit of code cleanup for the VFS shim. 2015-11-05 12:06:26 -08:00
Robbie Hanson
def40c2723 The "markSqlLevelSharedReadLockAcquired" stuff is no longer needed thanks to the new yap_vfs_shim. 2015-11-04 19:14:10 -08:00
Robbie Hanson
aa6da6655a Merge pull request #236 from sbooth/indexed-value-retrieval
Added -enumerateIndexedValuesInColumn:matchingQuery:usingBlock:
2015-11-04 19:05:59 -08:00
Robbie Hanson
588449794c Merge branch 'vfs_shim' 2015-11-04 19:02:53 -08:00
Robbie Hanson
8f627ba805 Added a VFS shim in order to add a notification for when the sql-level lock has been taken. This allows us to consolidate all the "markSqlLevelSharedReadLock" code into one place. And we also automatically get support for this in extensions, something that was missing before. 2015-11-04 18:41:15 -08:00
Stephen F. Booth
f08371a23b Added -enumerateIndexedValuesInColumn:matchingQuery:usingBlock: 2015-11-04 18:53:00 -05:00
Robbie Hanson
8bd619884a Merge branch 'master' of https://github.com/yapstudios/YapDatabase 2015-11-03 16:54:55 -08:00
Robbie Hanson
e1f1392e63 Fixing modulemap & Carthage issues. Addresses issue #192 2015-11-03 16:54:46 -08:00
Robbie Hanson
58320a2b40 Update README.md 2015-11-03 16:41:29 -08:00
Robbie Hanson
57b269d70e Update README.md 2015-11-03 16:40:14 -08:00
Robbie Hanson
9d8900b85f Update README.md 2015-11-03 16:34:53 -08:00
Robbie Hanson
bc271a2a71 Fixing modulemap path in podspec. 2015-11-03 16:28:37 -08:00
Robbie Hanson
6bc7983eca Bumping podspec to v2.7.4 2015-11-03 16:19:15 -08:00
Robbie Hanson
998b17f21d Fixing Xcode projects. 2015-11-03 16:13:43 -08:00
Robbie Hanson
7688f270af Merge branch 'carthage' 2015-11-03 12:55:21 -08:00
Robbie Hanson
6c4a626d05 Fixing modulemap problems & adding test targets. 2015-11-03 12:41:46 -08:00
Robbie Hanson
a15948348d Merge pull request #233 from Starscream27/sqlcipher.options
Added more options to using YapDatabase with SQLCipher
2015-11-03 09:52:12 -08:00
Robbie Hanson
d81e6847fe Fixing compiler warning about missing attribute. 2015-11-02 10:00:46 -08:00
Mathieu Meylan
9e97ee0860 Added more options to using YapDatabase with SQLCipher
- Added cipherPageSize property to YapDatabaseOptions allowing to customise the encrypted database page size
- Added kdfIterNumber and cipherDefaultkdfIterNumber allowing to customise the PBKDF2 iteration number for database key derivation.
2015-11-02 11:14:49 +01:00
Robbie Hanson
5d6a05648b Changing some internal language to use the modern "changeset" terminology. 2015-10-29 10:31:07 -07:00
Robbie Hanson
2c938c7e19 Adding ability to fetch a list of rowids, for secondary-index extensions. Addresses issue #230 2015-10-27 17:57:12 -07:00
Robbie Hanson
f1078e5da2 Minor performance improvement when enumerating a very large set of keys. 2015-10-27 17:56:21 -07:00
Robbie Hanson
2463450a21 Updating Xcode-mobile project to use latest CocoaLumberjack version. 2015-10-27 16:54:41 -07:00
Robbie Hanson
488c32ebf6 Updating Xcode-desktop project to use latest CocoaLumberjack version. 2015-10-27 16:25:54 -07:00
Robbie Hanson
ae676711cd Fixing SearchResultsExample project 2015-10-27 16:24:00 -07:00
Robbie Hanson
b7ccae4519 Fixing some annotation issues: databaseIdentifier can be nil 2015-10-27 16:11:15 -07:00
Robbie Hanson
33701416ca Fixing CloudKitTodo project via pod update 2015-10-27 15:43:07 -07:00
Robbie Hanson
00d1d837d2 Updating project via recommendations from Xcode 7 2015-10-27 15:38:00 -07:00
Robbie Hanson
89a74a64d3 Removing YapDebugDictionary class. It's no longer needed thanks to the latest language features. 2015-10-27 15:35:19 -07:00
Robbie Hanson
4793753b58 Merge branch 'xcode7' into 'master' 2015-10-27 15:22:39 -07:00
Robbie Hanson
5579e78586 Merge pull request #229 from sbooth/aggregate-query-fix
Aggregate function parameter ignored
2015-10-27 11:55:14 -07:00
Robbie Hanson
13001b091c Update travis.yml to use Xcode 7 2015-10-27 11:43:04 -07:00
Robbie Hanson
0af3647cba Merge pull request #228 from sbooth/nullability-annotations
Nullability annotations
2015-10-27 11:37:50 -07:00
Stephen F. Booth
68c146f648 Don't ignore the aggregateFunction parameter in +queryWithAggregateFunction:string:parameters: 2015-10-25 14:10:56 -04:00
Stephen F. Booth
220e020219 Made some properties nullable per unit test warnings 2015-10-24 22:42:01 -04:00
Stephen F. Booth
ea90ca9016 Added nullability annotations for Views extension 2015-10-24 22:33:30 -04:00
Stephen F. Booth
4b11306135 Added nullability specifiers for SecondaryIndex extension 2015-10-24 22:20:56 -04:00
Stephen F. Booth
748c268133 Added nullability specifiers for SearchResults extension 2015-10-24 22:17:17 -04:00
Stephen F. Booth
c112389dec Added nullability specifiers for Relationships extension 2015-10-24 22:12:16 -04:00
Stephen F. Booth
424f783470 Added nullability annotations to Hooks extension 2015-10-24 15:27:10 -04:00
Stephen F. Booth
f237104ff8 Added nullability annotations to FullTextSearch extension 2015-10-24 15:25:37 -04:00
Stephen F. Booth
63ceaf9959 Added nullability annotations to FilteredViews extension 2015-10-24 15:25:23 -04:00
Stephen F. Booth
e7b247f290 Added nullability annotations to CloudKit extension 2015-10-24 15:25:06 -04:00
Stephen F. Booth
4c1362f725 Added nullability annotations to Extensions protocol 2015-10-24 15:24:46 -04:00
Stephen F. Booth
acef1d7d79 Added nullability annotations 2015-10-24 14:57:31 -04:00
Stephen F. Booth
e6fe4c2c14 Standardized location of NS_ASSUME_NONNULL_BEGIN and NS_ASSUME_NONNULL_END 2015-10-23 13:52:02 -04:00
Stephen F. Booth
ad1c0b2748 Added forward declaration for YapDatabaseExtensionTransaction and made the result from nullable 2015-10-22 19:57:03 -04:00
Stephen F. Booth
6d7f7b87bb Added nullability annotations for the core classes 2015-10-22 19:48:40 -04:00
Robbie Hanson
0addc15712 Adding pragmaSynchronous getter. 2015-10-19 10:32:32 -07:00
Robbie Hanson
698b6841fc Minor bug fix: pragma getters weren't going through the connectionQueue. 2015-10-19 10:32:02 -07:00
Robbie Hanson
d7ad1b14c0 Updating FullTextSearch extension to use new YapMutationStack class. 2015-10-16 18:42:37 -07:00
Robbie Hanson
d484846de6 Minor refactoring: standardizing on some internal variable names within extensions. 2015-10-16 18:23:53 -07:00
Robbie Hanson
db8c00bcbd Updating RTreeIndex extension to use new YapMutationStack class. 2015-10-16 18:10:45 -07:00
Robbie Hanson
68e8bb44f4 Updating SecondaryIndex extension to use new YapMutationStack class. 2015-10-16 17:53:29 -07:00
Robbie Hanson
70b72f648f Fixing iOS Unit Test project 2015-10-16 17:10:20 -07:00
Robbie Hanson
00aec4890a Fixing new compiler warning. 2015-10-16 17:08:45 -07:00
Robbie Hanson
d48c4e8a90 Adding a YapMutationStack class to solve the remaining edge cases surrounding mutation-during-enumeration detection. 2015-10-16 16:34:28 -07:00
Robbie Hanson
dfc4d222d1 Adding Carthage stuff to .gitignore 2015-10-16 16:30:56 -07:00
Robbie Hanson
23a3457c87 Fixing modulemap file & removing previous comments. 2015-10-14 14:58:48 -07:00
Robbie Hanson
f17c7f7996 Setting modulemap file for Mac Framework. 2015-10-14 14:58:24 -07:00
Robbie Hanson
968ce7e798 Marking schemes as shared. 2015-10-14 14:57:49 -07:00
Robbie Hanson
5c0885c1e2 Working towards Carthage support 2015-10-14 12:17:23 -07:00
Robbie Hanson
56b4ff2253 Fixing missing import & removing corresponding private header from modulemap. 2015-10-12 17:54:58 -07:00
Robbie Hanson
ece44bfeaf Bumping podspec to v2.7.3 2015-10-09 11:05:03 -07:00
Robbie Hanson
23461c2ee8 Minor bug fix for YDBCloudKit - an attachRequest (for a collection/key that doesn't exist) followed by a detachRequest, will now properly remove the pending attachRequest. 2015-10-02 17:04:27 -07:00
Robbie Hanson
5b1f5668de Bug fix for YapCache - it was ignoring a countLimit of zero (unlimited countLimit) if initialized with a countLimit of zero. 2015-09-30 09:08:39 -07:00
Robbie Hanson
c659338401 Fixing recent typos in YDBCloudKit 2015-09-26 14:11:19 -07:00
Robbie Hanson
b9b947d5e5 Converting YapDatabaseBlockType to a bit mask in order to make several common operations easier. 2015-09-26 14:09:56 -07:00
Robbie Hanson
aae19b3942 Adding support for YapDatabaseBlockInvoke bit mask to FullTextSearch & FilteredViews. 2015-09-26 13:03:15 -07:00
Robbie Hanson
27a935bb27 Another bug fix for issue #215 - Bug in YapDatabaseHooks extension 2015-09-25 14:25:32 -07:00
Robbie Hanson
3f603e5435 Adding support for YapDatabaseBlockInvoke bit mask to YapDatabaseRTreeIndex. 2015-09-25 12:20:09 -07:00
Robbie Hanson
0b4d7c433d Adding support for YapDatabaseBlockInvoke bit mask to YapDatabaseCloudKit. 2015-09-25 11:38:53 -07:00
Robbie Hanson
1760bfb3bb Fixing CloudKit project using fixed CocoaPod spec 2015-09-25 11:37:50 -07:00
Robbie Hanson
083c2f1960 Bug fix for issue #215 - Bug in YapDatabaseHooks extension 2015-09-25 09:52:25 -07:00
Robbie Hanson
3dd1adca67 Adding support for YapDatabaseBlockInvoke bit mask to YapDatabaseSecondaryIndex. 2015-09-24 17:09:25 -07:00
Robbie Hanson
3e2a738f39 Touching Xcode project with latest version of Xcode (recommended upgrades to project file) 2015-09-24 17:09:08 -07:00
Robbie Hanson
9cb15c3187 Merge branch 'master' of https://github.com/yapstudios/YapDatabase 2015-09-24 16:26:28 -07:00
Robbie Hanson
0106e3b46a Touching Xcode project with latest version of Xcode (recommended upgrades to project file) 2015-09-24 16:26:02 -07:00
Robbie Hanson
f4617f7ea0 Merge pull request #214 from skeeet/master
Removed "-weak_library /usr/lib/libc++.dylib" from podspec.
2015-09-24 16:00:00 -07:00
Robbie Hanson
40f4bb4144 Minor code cleanup 2015-09-22 11:25:11 -07:00
Robbie Hanson
4c3496a593 Merge branch 'master' of https://github.com/yapstudios/YapDatabase 2015-09-21 14:17:58 -07:00
Robbie Hanson
571429e9d5 Adding support for YapDatabaseBlockInvoke bit mask to YapDatabaseView. 2015-09-21 14:17:35 -07:00
Aleksei Shevchenko
5ae87357fd added "s.libraries = 'c++'" as suggested by @chrisballinger 2015-09-17 16:21:37 -07:00
Aleksei Shevchenko
df0d16bc4a Removed "-weak_library /usr/lib/libc++.dylib" from podspec.
Should solve bitcode conflict.
2015-09-17 15:40:57 -07:00
Robbie Hanson
3c5aa211f0 Merge pull request #213 from danthorpe/YAP-208_module_includes
Adds missing headers to the module map
2015-09-16 14:16:08 -07:00
Robbie Hanson
6b759a3940 Fixing SearchResultsExample Xcode project. 2015-09-16 12:25:26 -07:00
Robbie Hanson
d069f292ef Working towards a standardized mechanism for configuring how/when extension blocks are invoked. (E.g. YapDatabaseViewGrouping) 2015-09-15 21:20:15 -07:00
Robbie Hanson
240dcd7fdb Fixing Xcode projects (new header file means pod needs to be updated) 2015-09-15 15:51:36 -07:00
Robbie Hanson
4a95f1cdc6 Removing deprecated method: findRangeInGroup:usingBlock:blockType: 2015-09-15 15:50:46 -07:00
Robbie Hanson
fe11e3d97d Adding common YapDatabaseBlockType enum for all extensions to share. 2015-09-15 15:30:55 -07:00
Robbie Hanson
5ba03779d6 Fixing CloudKitTodo xcode project. 2015-09-11 12:03:13 -07:00
Daniel Thorpe
e7b8989fec [YAP-208]: Adds the final missing header
But this seems wrong, as the header is called: YapDatabaseSearchQueuePrivate.h - so, I guess it's private?
2015-09-10 22:29:57 +01:00
Daniel Thorpe
29419f1577 [YAP-208]: Adds the RTree headers 2015-09-10 22:20:47 +01:00
Robbie Hanson
4ab80a16b0 Fixing Xcode-mobile workspace 2015-09-10 11:13:45 -07:00
Robbie Hanson
1998437ce1 Simplifying YapDatabaseHooks API & adding unit tests for it. 2015-09-10 11:05:41 -07:00
Robbie Hanson
f32c6ce328 Bumping podspec version. 2015-08-28 11:16:51 -07:00
Robbie Hanson
4a981b62cd Minor API change: YapDatabaseCloudKit.recordHandler now includes a YapDatabaseReadTransaction parameter. Fixes issue #210 2015-08-28 11:07:52 -07:00
Robbie Hanson
1bced92645 Adding proper comments for YapDatabaseCloudKit block types. 2015-08-28 10:12:43 -07:00
Robbie Hanson
b9e8635775 Added private utility method to extract all tableNames from the database (for use by extensions). 2015-08-26 16:17:57 -07:00
Robbie Hanson
dbece64715 Bug fix for issue #205 - Touching an object does not work as expected 2015-08-26 14:48:28 -07:00
Robbie Hanson
57125caca8 Added touchRowForKey:inCollection: method to YapDatabaseTransaction, along with corresponding hook for extensions. 2015-08-26 12:14:13 -07:00
Robbie Hanson
50b8ab8aa1 Adding missing API usage check for YDBCloudKit. 2015-08-26 11:36:33 -07:00
Robbie Hanson
c2254ea760 Just moving some methods around. (no functional changes) 2015-08-26 11:35:53 -07:00
Robbie Hanson
f19636c59d Explicitly marking a YDBCloudKit property as dynamic. 2015-08-20 16:55:58 -07:00
Robbie Hanson
b861e0d65d Removing explicit values from some NS_ENUM's. (The explicit values are no longer needed thanks to other type-checking mechanisms.) 2015-08-20 16:55:10 -07:00
Robbie Hanson
7826e12f9f Bumping podspec version to 2.7.1 2015-08-19 09:22:52 -07:00
Robbie Hanson
6c59d9aac0 Fixed bug in YapDatabaseView's find method(s). Thanks Xcode analyzer! 2015-08-19 09:19:58 -07:00
Robbie Hanson
e1a5c9a160 Fixing compiler warning. 2015-08-19 09:12:33 -07:00
Robbie Hanson
d8680775b6 Added support for aggregate functions to YapDatabaseQuery & YapDatabaseSecondaryIndex. Fixes issue #156 2015-08-18 10:05:25 -07:00
Robbie Hanson
aea9aff92b Added support for BLOB & NUMERIC types to YapDatabaseSecondaryIndex. 2015-08-17 15:02:36 -07:00
Robbie Hanson
f283dd215e Bug fix for YapDatabaseCloudKit - didn't remove all sqlite tables during extension removal process. 2015-08-14 11:14:10 -07:00
Robbie Hanson
f6c25dd61b Minor documentation fix. 2015-08-14 11:13:23 -07:00
Robbie Hanson
649a8bed8e Minor bug fix: If a readWriteTransaction was aborted (via rollback), the IsOnConnectionQueueKey wasn't unset. 2015-08-12 11:53:39 -07:00
Robbie Hanson
db49b57a99 Fixing compiler warning (unused function) 2015-08-12 10:30:10 -07:00
Robbie Hanson
ccd4c2af24 Investigating travis-ci failure. 2015-08-11 16:04:33 -07:00
Robbie Hanson
af6bcea37a Updating .gitignore, and adding missing workspace files 2015-08-11 15:47:54 -07:00
Robbie Hanson
e8f6cc5d2b Fighting with xctool (and not having much luck) 2015-08-11 15:28:36 -07:00
Robbie Hanson
f20161e4d8 Merge branch 'issue200' 2015-08-11 14:25:51 -07:00
Robbie Hanson
3ea0ba6ed4 Updating pod for Xcode-desktop project. 2015-08-11 14:19:42 -07:00
Robbie Hanson
61058605ce Investigating travis-ci failure. 2015-08-11 14:18:56 -07:00
Robbie Hanson
4779686154 Investigating issue #200 - Getting a crash inside YDBCKChangeQueue 2015-08-11 13:49:35 -07:00
Robbie Hanson
72ebf2b535 Removing unused group from Xcode project. 2015-08-11 13:47:55 -07:00
Robbie Hanson
c25cfc87c5 Updating Podspec to v2.7 2015-08-10 15:52:29 -07:00
Robbie Hanson
719adaed4c Investigating travis-ci failure. 2015-08-10 15:51:51 -07:00
Robbie Hanson
cb90cab344 Investigating travis-ci failure. 2015-08-10 15:47:32 -07:00
Robbie Hanson
3bff9f15ff Investigating travis-ci failure. 2015-08-10 15:37:17 -07:00
Robbie Hanson
4efe8eb5ae Upgrading travis-ci to latest Xcode (v6.4) 2015-08-10 15:31:10 -07:00
Robbie Hanson
47413fa400 Adding optimized find method (YapDatabaseView) in case one only needs the first match. 2015-07-31 17:46:31 -07:00
Robbie Hanson
e36e3c75aa Converting [YapDatabaseView findRangeInGroup:usingBlock:blockType:] to modern syntax. (no more explicit blockType parameter) 2015-07-31 17:41:30 -07:00
Robbie Hanson
4bc3065819 Minor documentation improvement. 2015-07-31 16:53:19 -07:00
Robbie Hanson
bf3b8ba075 Minor optimization: Changing [string appendFormat] to [string appendString] where possible. 2015-07-27 16:06:49 -07:00
Robbie Hanson
8cba7320cc Bug fix for issue #197 - sqlite3_wal_checkpoint_v2 blocking 2015-07-25 18:28:29 -07:00
Robbie Hanson
8ffbf4ea97 Disabling recent debug/test code. 2015-07-25 18:26:24 -07:00
Robbie Hanson
f2fcd99d91 Adding a bit of test code to validate checkpoint algorithm. 2015-07-25 17:04:21 -07:00
Robbie Hanson
20275b591b Bug fix for issue #195 - YapDatabaseLoggingTechniqueDisabled and Foundation problem 2015-07-20 14:22:42 -07:00
Robbie Hanson
63a7078b24 A bit of code cleanup - moving copied code into a single utility method. 2015-07-07 14:34:22 -07:00
Robbie Hanson
2435d1e2fa Minor bug fix for the size calculation of the internal keyCache. (maps rowid -> YapCollectionKey) 2015-07-07 14:12:56 -07:00
Robbie Hanson
cb8b66e5b6 Removing brittle unit test. (It depended upon some hard coded execution times.) 2015-07-07 11:00:38 -07:00
Robbie Hanson
79aa43a41c Added support for backing up a sqlite file (plus WAL) via the sqlite_backup API. Issue #122 2015-07-07 10:38:30 -07:00
Robbie Hanson
f5eb0eaccb Fixing CloudKitTodo project 2015-07-02 17:13:40 -07:00
Robbie Hanson
9227a97373 Fixing Xcode-mobile project 2015-07-02 16:44:06 -07:00
Robbie Hanson
acc282b9ca Fixing Xcode-desktop project 2015-07-02 16:36:59 -07:00
Robbie Hanson
abf804b18c Merge branch 'grgcombs-pullreq/use-lumberjack-v2' into 2.7 2015-07-02 15:20:00 -07:00
Robbie Hanson
ab17a7f90b Merge branch 'pullreq/use-lumberjack-v2' of https://github.com/grgcombs/YapDatabase into grgcombs-pullreq/use-lumberjack-v2 2015-07-02 15:18:57 -07:00
Robbie Hanson
b3162bf4df Fixing type signatures for YapMurmurHashData methods. 2015-07-02 14:19:06 -07:00
Robbie Hanson
fddd74a82d Adding support for memory mapped I/O. 2015-06-30 19:06:50 -07:00
Robbie Hanson
a1920839e6 Fixing misspelled variable name: toalFrameCount -> totalFrameCount 2015-06-30 18:48:15 -07:00
Robbie Hanson
a40549ea18 Adding support for flushing internal cached sqlite pages.
There's a method to do this called sqlite3_db_release_memory. That is now exposed via the new YapDatabaseConnectionFlushMemoryFlags_Internal.
2015-06-28 16:25:27 -07:00
Robbie Hanson
e3e9797ee5 Bug fix for [YapDatabaseCloudKitTransaction populate]. Thanks Xcode 7 + generics. 2015-06-28 15:26:02 -07:00
Robbie Hanson
f56b485f64 Fixing recent unit tests to work with new YapDatabaseView grouping/sorting/filtering block signature. 2015-06-28 15:25:19 -07:00
Robbie Hanson
b8e812db59 Bug fix for [YapDatabaseCloudKitTransaction populate]. Thanks Xcode 7 + generics. 2015-06-28 15:21:28 -07:00
Robbie Hanson
bafe2f08ba Adding generics specifications (Xcode 7 only). 2015-06-28 15:20:11 -07:00
Robbie Hanson
2944274b0d Minor code cleanup - renaming "id key" to "NSString *hash" in order to properly specify what we're enumerating. 2015-06-28 15:16:42 -07:00
Robbie Hanson
8df37b9f78 Minor code cleanup - renaming "id key" to "NSNumber *rowid" in order to properly specify what we're enumerating. 2015-06-28 15:16:11 -07:00
Robbie Hanson
f35bf83f89 Fixing recent unit tests to work with new YapDatabaseView grouping/sorting/filtering block signature. 2015-06-28 14:35:27 -07:00
Robbie Hanson
382a9cafa8 Xcode 7 upgrade checks & fixes 2015-06-28 14:34:44 -07:00
Robbie Hanson
d6b1cb79ac Merge branch 'master' into 2.7 2015-06-28 14:06:38 -07:00
Robbie Hanson
e0756f1a9c Bumping podspec to v2.6.5 2015-06-27 17:49:44 -07:00
Robbie Hanson
6b91166a80 Improving Swift support within YapDatabaseQuery. Fixes issue #170 2015-06-27 17:28:31 -07:00
Robbie Hanson
03a02e87d4 Bug fix for YapDatabaseQuery: didn't properly handle empty arrays or multiple arrays in parameter list.
Now also supports NSNull in parameter list.
2015-06-27 16:22:01 -07:00
Robbie Hanson
c428950dd2 Decreasing default metadataCacheLimit to 250 (to match default objectCacheLimit) 2015-06-27 15:28:25 -07:00
Robbie Hanson
4d359dcdf0 Minor formatting fixes (no functional changes) 2015-06-27 15:08:13 -07:00
Robbie Hanson
82426acd8a Adding unit tests for issue #186 2015-06-26 16:50:33 -07:00
Robbie Hanson
a9f4aa497f Bug fix for issue #186 - Crash on replaceMetadata:forKey:inCollection with filtered views 2015-06-26 15:56:19 -07:00
Robbie Hanson
7a71ccfa54 Bug fix for issue #187 - Typo in some comments 2015-06-26 15:21:21 -07:00
Robbie Hanson
e15360be58 Merge branch 'snipsco-rtree-extension' 2015-06-26 14:50:56 -07:00
Greg Combs
877139b29b [Pods] Update the Travis script for CocoaPods 2015-06-25 12:06:03 -05:00
Greg Combs
6665603689 [Pods] Decoupled CocoaLumberjack using CocoaPods
This allows users to link against a different CocoaLumberjack than what was provided in YapDatabase previously.  Consequently, CocoaLumberjack sources have been removed from the YapDatabase repository.

Moreover, the Xcode-mobile and Xcode-desktop test projects now each have a Podfile.  The downside is that you have to run `pod install` before executing the tests the first time around, but the upside is that CocoaLumberjack and YapDatabase libraries are now linked via Pods, and the test projects aren't so dependent on specific versions.
2015-06-25 11:53:59 -05:00
maelp
f4dd11fd39 Add comment about the storage precision of coordinates in r-tree 2015-06-22 11:14:03 +02:00
maelp
9f315a2e67 Add a RTreeIndex extension 2015-06-19 14:19:33 +02:00
Robbie Hanson
e51b06c6a2 Merge pull request #181 from chrisballinger/travis-ci
Add support for running tests on Travis-CI
2015-06-17 10:33:51 -07:00
Robbie Hanson
2d3a9ab394 Fixing warnings & error when YapDatabaseLoggingTechnique is disabled. Fixes issue #182 2015-06-12 15:14:08 -07:00
Chris Ballinger
90fc09257d Travis: Use Xcode 6.3 2015-06-11 14:03:10 -07:00
Robbie Hanson
f3c977d3d6 Adding "YapDatabaseReadTransaction *transaction" to parameter list for YapDatabaseView & YapDatabaseFilteredView blocks.
This allows for more flexibility when implementing your grouping/sorting/filtering blocks. That is, you can now use other objects (in the database), or even other extensions to assist you in the implementation logic.
2015-06-09 15:07:14 -07:00
Robbie Hanson
a870ac0437 Merge branch 'xcodeproject' of https://github.com/dhardiman/YapDatabase into dhardiman-xcodeproject 2015-06-09 11:11:35 -07:00
Robbie Hanson
bcc2559f96 Minor fix for double-retain of strongSelf in checkpoint method.
This may have caused YapDatabase instances to stick around longer than needed during attempted deallocation. Addresses issue #40
2015-06-09 10:33:36 -07:00
Robbie Hanson
a224d78ab5 Changing a few "char *" variables to "const char *". (no functional changes) 2015-06-09 10:30:48 -07:00
Robbie Hanson
2d0584be50 Fixing bug in YapDatabaseRelationship extension.
If one attempted to enumerate edges that included a source or destination that wasn't yet inserted into the database, then the code would short-circuit & return no edges. This was despite the fact that YapDatabaseRelationship explicitly supports adding edges for source/destination nodes that haven't been inserted yet. This patches the bug, and includes corresponding unit tests.

See also: https://groups.google.com/forum/#!topic/yapdatabase/E7q0truTrp8
2015-06-05 18:52:43 -07:00
Robbie Hanson
3649d66c5b Fixing unit test - now uses semaphores to guarantee proper test, instead of making assumptions on sleeping & timing. 2015-06-05 18:47:00 -07:00
Robbie Hanson
fbbc8b7863 Bug fix for CloudKitManager: It would sometimes fail to properly fetch the data from the server on a fresh app launch (first run after install). 2015-05-31 14:39:57 -07:00
Robbie Hanson
e6ccd9c623 Bug fix for issue #178 - EXC_BAD_INSTRUCTION crash when syncing for the first time 2015-05-31 14:31:18 -07:00
Dave Hardiman
fb1b558293 Remove private header from module 2015-05-27 11:25:59 +01:00
Dave Hardiman
7e2e3ceab3 Fix cocoalumberjack path 2015-05-26 16:36:34 +01:00
Dave Hardiman
38c737e019 Add universal framework target 2015-05-26 16:33:28 +01:00
Dave Hardiman
b78979ca2f Add xcode project for dynamic framework 2015-05-26 16:32:03 +01:00
Chris Ballinger
412d7f1e43 Run OS X unit tests on Travis-CI 2015-05-14 17:10:07 -07:00
Robbie Hanson
192e165da8 Adding ability to set PRAGMA page_size of underlying sqlite database. 2015-05-14 14:58:13 -07:00
Robbie Hanson
d0920352d5 Changing YapCollectionKeyCreate to a macro. Better performance & fixes compiler issues. 2015-05-14 14:02:51 -07:00
Robbie Hanson
e4b239390d Bumping podspec to v2.6.4 2015-05-13 18:52:06 -07:00
Robbie Hanson
4baf5f5d06 Adding notification for when a YapDatabase instance is deallocated, and thus has closed all references to the underlying sqlite files. Fixes issue #139 2015-05-13 18:40:21 -07:00
Robbie Hanson
ab78f558ec Adding getters for the sqlite '-wal' & '-shm' file paths. 2015-05-13 18:13:04 -07:00
Robbie Hanson
bb2e4e6132 Removing a bunch of deprecated methods. 2015-05-13 18:01:59 -07:00
Robbie Hanson
1d29a79daf Fixing podspec. Issue #172 2015-05-12 16:32:26 -07:00
Robbie Hanson
b32aae66b7 Bumping podspec to v2.6.3 2015-05-12 11:52:01 -07:00
Robbie Hanson
f93b8f95c6 Bug fix for issue #171 - Not passing options in init method 2015-05-11 17:14:32 -07:00
Robbie Hanson
5e6d7b2630 Bumping podspec version to 2.6.2
Also struggled to push the podspec to trunk. (It wouldn't lint either.) Had to make some compromises here just to get it pushed. Perhaps someone more knowledgable with podspec's can find a cleaner alternative.
2015-05-05 19:00:45 -07:00
Robbie Hanson
c12c600e8c Merge branch 'master' of https://github.com/yapstudios/YapDatabase 2015-05-04 14:03:55 -07:00
Robbie Hanson
49ff0ad229 Allows a YapDatabase instance to be un-encrypted regardless of whether SQLCipher is present. 2015-05-04 14:03:49 -07:00
Robbie Hanson
01b674e8fb Merge pull request #167 from ngocluu/bug-fixes
Bug fixes
2015-04-30 15:00:06 -05:00
Robbie Hanson
807c271fb9 Merge pull request #168 from Canis-UK/master
Nullability fixes for enumeration callback blocks.
2015-04-30 14:53:50 -05:00
Canis Lupus
aa59f3a701 Nullability fixes for enumeration callback blocks. 2015-04-29 18:19:37 +01:00
Ngoc Luu
e8efa8c322 Fix warning "-[NSKeyedUnarchiver initForReadingWithData:]: data is empty; did you forget to send -finishEncoding to the NSKeyedArchiver?" 2015-04-29 08:48:03 +07:00
Ngoc Luu
774dfe6b71 Minor bug fix for YapDatabaseSecondaryIndexTransaction. 2015-04-29 08:36:50 +07:00
Robbie Hanson
a9fd3551ca Fixing analyzer warning.
The analyzer was warning about calling setObject:forKey:, where the key was 'prevRecordTableHash' (saying that the key could be nil). I don't believe it's possible for prevRecordTableInfo to be non-nil & prevRecordTableHash to be nil. But this fixes the warning, and also more closely matches the other if statements within the method.
2015-04-24 14:41:09 -07:00
Robbie Hanson
dc076f0920 Fixing improper logging macro. Thanks analyzer. 2015-04-24 14:38:13 -07:00
Robbie Hanson
624b667260 Fixing analyzer warning: dead store (value stored to variable is never read) 2015-04-24 14:37:06 -07:00
Robbie Hanson
bb26a5e259 Merge pull request #166 from jj0b/patch-1
Changed YDB_NodeDeleteRules to use NS_OPTIONS
2015-04-22 21:45:42 -07:00
Robbie Hanson
d71dfc366b Minor refactoring: renaming SQLITE_COL_START to SQLITE_COLUMN_START 2015-04-22 15:24:51 -07:00
Robbie Hanson
ce3af11d10 Fixing code to use SQLITE_BIND_START standard. 2015-04-22 12:26:58 -07:00
Robbie Hanson
70556c15ff Minor improvement for hard-coded version number within #ifdef statements. 2015-04-22 12:24:39 -07:00
Jason Job
51e85ff449 Changed YDB_NodeDeleteRules to use NS_OPTIONS
Using NS_OPTIONS is better than using a C-style enum because NS_OPTIONS (and NS_ENUM) are fully compatible with Swift, whereas a C-style enum is more difficult to access in Swift.
2015-04-22 11:25:10 -07:00
Robbie Hanson
089cbfba45 Merge branch 'issue_157' 2015-04-21 00:16:01 -07:00
Robbie Hanson
54bfb0a51b Bug fix for issue #157 - WAL is never cleared
A few edge-case scenarios were discovered where the WAL file could grow without bound. This change adds an "aggressive" checkpoint operation, along with a new YapDatabaseOptions property to control when this aggressive checkpoint should be executed.
2015-04-20 23:58:13 -07:00
Robbie Hanson
6988d0e2f4 Code organization (moving methods around). No functional changes. 2015-04-17 11:57:31 -07:00
Robbie Hanson
f7d4628adf Bug fix for improbable (but theoretically possible) multi-threading edge case.
The following steps would have to occur:
- connection is on longLivedReadTransaction
- checkpoint completes, invokes [connection maybeResetLongLivedReadTransaction]
- maybeResetLongLivedReadTransaction gets writeQueue
- [connection asyncReadWrite] invoked, gets connectionQueue,
- [connection beginLongLivedReadTransaction] invoked, waiting on connectionQueue
- maybeResetLongLivedReadTransaction pauses writeQueue, leaves writeQueue, waiting on connectionQueue
- asyncReadWrite un-pauses writeQueue, gets writeQueue, completes
- beginLongLivedReadTransaction completes
- maybeResetLongLivedReadTransaction gets connectionQueue, has longLivedReadTransaction & proper snapshot, but non-suspended writeQueue
2015-04-17 11:48:31 -07:00
Robbie Hanson
0012888455 A few more nullable annotations 2015-04-15 17:43:45 -07:00
Robbie Hanson
39ef7d211a Minor performance optimizations 2015-04-15 17:43:17 -07:00
Robbie Hanson
beef66002e Merge pull request #163 from danthorpe/YAP-162_nullability_annotation
Nullability annotations
2015-04-15 16:44:02 -07:00
Daniel Thorpe
28fbebf353 [YAP-162]: Annotates YapDatabaseTransaction for nullability. 2015-04-15 12:24:09 +01:00
Daniel Thorpe
bcc16114df [YAP-162]: Annotate YapDatabaseConnection for nullability. 2015-04-15 11:57:04 +01:00
Daniel Thorpe
58a87f9d7a [YAP-162]: Adds annotations to YapDatabase header. 2015-04-15 11:41:36 +01:00
Robbie Hanson
c333155c68 Merge pull request #161 from dlahyani/feature/fix-xcode-warnings
Fix XCode Warnings
2015-04-14 10:30:01 -07:00
Daniel Lahyani
4f38da7165 YapDatabaseFilteredView: Add @dynamic directive for super's properties. 2015-04-14 14:47:44 +03:00
Daniel Lahyani
a9141469ad Fix sing mismatches in assignments and comparisons. 2015-04-14 14:47:15 +03:00
Daniel Lahyani
6763f6c9b1 Remove misplaced semicolons. 2015-04-14 14:46:25 +03:00
Daniel Lahyani
fff4666e6e Mark unused parameters with __unused. 2015-04-14 14:40:16 +03:00
Robbie Hanson
16a45bb3a4 Standardizing on the use of SQLITE_BIND_START & SQLITE_COL_START.
The sqlite3_bind interface is 1-based.
The sqlite3_column interface is 0-based.
This is very confusing, and it becomes difficult to keep straight.
To make it easier for everybody, I'm standardizing on the use of constants
along with a format for using them. The goal is to make the code easier to
read/understand, and also more difficult to screw up when coding.
2015-04-11 13:34:26 -07:00
Robbie Hanson
4fc4277c9e Correcting log level for error message. Was warn, but should have been error. 2015-04-08 15:51:05 -07:00
Robbie Hanson
912d9190d5 Minor refactoring & improvements for YapDatabaseConnectionState. Making variable names more understandable, and adding a timestamp (for future work). Working towards a fix for issue #157 2015-04-02 09:30:25 -07:00
Robbie Hanson
be14dfa27b The database should perform an asyncCheckpoint during the startup process. Partially addresses issue #157 2015-04-01 10:29:10 -07:00
Robbie Hanson
d8b11dfcc6 Merge branch 'master' of https://github.com/yapstudios/YapDatabase 2015-03-31 18:24:23 -07:00
Robbie Hanson
94afc9f0b4 Bug fixes for YapDatabaseSearchResultsView extension. Wasn't properly updating stored snippet. And wasn't properly updating after items were inserted/updated. 2015-03-31 18:24:14 -07:00
Robbie Hanson
30f2a084b5 Merge pull request #153 from Kirow/master
Fix to SearchResultsExample project
2015-03-31 09:56:00 -07:00
Robbie Hanson
98dd700bde Adding method that allows one to fetch the previous versionTag that was being used by a YapDatabaseView (or view subclass) during last app run. 2015-03-29 14:06:39 -07:00
Robbie Hanson
521e0917ec Removing outdated architecture comment. 2015-03-29 14:05:48 -07:00
Robbie Hanson
d2686498c9 Standardizing on extension key naming (ext_key_X), and moving several shared keys into their corresponding private header file. 2015-03-29 14:05:28 -07:00
Kirow
a77be9d6d7 fix SearchResultsExample project
- removed deprecated methods
- subscripting usage
2015-03-28 18:42:24 +02:00
Kirow
0983865e56 Fix to SearchResultsExample project
Added YapMurmurHash
2015-03-28 18:13:07 +02:00
Robbie Hanson
43e11da060 Adding YapDatabaseHooks extension. 2015-03-27 16:17:35 -07:00
Robbie Hanson
d6a980a1b9 Bumping podspec version to 2.6.1 2015-03-25 18:45:02 -04:00
Robbie Hanson
6268df46cc Bug fixes for CloudKitTodo sample project. 2015-03-25 00:56:17 -04:00
Robbie Hanson
d54873599a Merge branch 'master' of https://github.com/yapstudios/YapDatabase 2015-03-22 14:05:12 -07:00
Robbie Hanson
55a00e2e53 Bug fixes related to thread safety for CloudKitManager in CloudKitTodo sample app. 2015-03-22 14:04:44 -07:00
Robbie Hanson
ff9dec57f0 Merge pull request #147 from pizthewiz/prune-redundant-property
Remove redundant options property declaration
2015-03-20 16:21:05 -07:00
Robbie Hanson
4754eb24f3 Merge pull request #146 from pizthewiz/search-results-example
Fix SearchResultsExample compile failure
2015-03-20 16:19:24 -07:00
Robbie Hanson
f1e4a71455 Fixing a few compiler warnings (unused function) 2015-03-19 09:40:55 -07:00
Robbie Hanson
568197eadb Adding screen shots to repo so I can use them in the wiki 2015-03-18 17:49:49 -07:00
Robbie Hanson
5d92cbbb37 Bumping podspec version. 2015-03-18 16:28:43 -07:00
Robbie Hanson
1a7698e174 Update README.md 2015-03-18 16:19:43 -07:00
Robbie Hanson
31123b0991 Fixing a few compiler warnings, and cleaning up Xcode projects. 2015-03-18 16:03:48 -07:00
Robbie Hanson
dd3611fbcd Updating MyDatabaseObjectExample project. 2015-03-17 18:59:49 -07:00
Robbie Hanson
6f4288d317 Minor bug fix for MyDatabaseObject example class. 2015-03-17 18:58:17 -07:00
Robbie Hanson
e591c7d4c2 YapDatabaseCloudKit improvements - now detects fetched changes that we made, and can ignore them. 2015-03-17 12:57:59 -07:00
Robbie Hanson
750309248f Minor improvements for YapDatabaseCloudKit extension. And bug fixes for CloudKitTodo sample project. 2015-03-17 01:14:59 -07:00
Robbie Hanson
70c5904f5c Bug fix for CloudKitTodo sample app: didn't fetch record changes when returning from background. 2015-03-17 00:18:02 -07:00
Robbie Hanson
8da13ab838 Improved merge handling for YapDatabaseCloudKit. Can now detect which properties were changed by remote device(s) in a CKRecord. 2015-03-16 22:34:48 -07:00
Robbie Hanson
abf503aa07 Bug fix for typo in YapDatabaseCloudKitTransaction that could have lead to problems if the same CKRecord was modified multiple times within the same transaction. 2015-03-16 15:56:40 -07:00
Robbie Hanson
1f9dcbd29d Minor bug fixes for YapDatabaseCloudKit to support various edge cases (in merge handling). 2015-03-15 13:07:33 -07:00
Robbie Hanson
8e50c13608 Removing all the workaround code I had added. No longer needed now that I've identified the root cause of the problem. 2015-03-15 00:56:57 -07:00
Robbie Hanson
5f19ef10f5 Finally tracked down that bug in Apple's CloudKit framework. And it was a doozy !! 2015-03-15 00:01:58 -07:00
Jean-Pierre Mouilleseaux
724da95cac remove redundant options property deceleration
The options property is already declared by the superclass YapDatabaseView and Xcode was giving a warning.
2015-03-12 11:11:36 -07:00
Jean-Pierre Mouilleseaux
888601b488 get search results example building again
It appears that several files shifted after the SearchResultsExample project was created and those changes weren't reflected in the project file which of course causes it to blow up.
2015-03-12 11:08:47 -07:00
Robbie Hanson
745e718f0d Major re-working of YapDatabaseCloudKit to address bugs in Apple's CloudKit framework/service implementation. 2015-03-11 18:49:26 -07:00
Robbie Hanson
841b857c9a Adding sqlite version property to YapDatabase. 2015-03-05 10:34:02 -08:00
Robbie Hanson
db620994ff Bug fix for crash in CloudKitTodo example. 2015-02-27 16:53:56 -08:00
Robbie Hanson
bbf940fd99 Bug fix for YapDatabaseCloudKit - didn't properly handle merging records in the queue if the record had already been deleted/detached locally. 2015-02-27 16:31:34 -08:00
Robbie Hanson
47a3d048f2 Several bug fixes for CloudKitTodo example. Also improving MyDatabaseObject to support situations in which the localObject & CKRecord share the same property name, but have different data formats. 2015-02-26 17:49:53 -08:00
Robbie Hanson
0911a071f4 Merge branch 'Canis-UK-prehooks' into 2.6 2015-02-25 11:19:12 -08:00
Robbie Hanson
4ebc53d310 Bug fixes for the following: issue #108, issue #132 2015-02-16 15:08:08 -08:00
Robbie Hanson
1a5484d0d5 Bug fix for crash in CloudKitTodo example project. 2015-02-16 15:06:06 -08:00
Robbie Hanson
dfdabcc376 Merge branch 'master' into 2.6 2015-02-16 14:00:33 -08:00
Robbie Hanson
d3ae1c0935 Bug fix for issue #135 2015-02-16 13:16:19 -08:00
Canis Lupus
c79ca35568 Extension hooks that trigger before operations are applied. 2015-02-06 14:18:46 +00:00
Robbie Hanson
288ca45d1e Merge pull request #138 from northtech/query-swift
Tweak Swift behavior of YapDatabaseQuery.
2015-02-03 22:12:06 -08:00
Caleb Davenport
1726965c6e Tweak Swift behavior of YapDatabaseQuery.
- Remove need for special function since `queryWithFormat:arguments:` is imported as an initializer.
2015-02-03 22:03:12 -08:00
Robbie Hanson
588d488549 Merge pull request #137 from northtech/query-swift
YapDatabaseQuery Swift Compatibility
2015-02-03 17:56:59 -08:00
Caleb Davenport
04baad3293 Restore documentation on method implementations. 2015-02-03 17:51:01 -08:00
Caleb Davenport
7cc0f34012 Add shim for calling YapDatabaseQuery with Swift. yapstudios/YapDatabase#136 2015-02-03 17:33:47 -08:00
Caleb Davenport
378b6d1aca Add va_list method to YapDatabaseQuery. yapstudios/YapDatabase#136 2015-02-03 17:19:03 -08:00
Robbie Hanson
632f54756c Adding userInfo property to YapDatabaseTransaction. This allows arbitrary data to be associated with a transaction. 2015-01-27 11:05:30 -08:00
Robbie Hanson
41060b267b Bug fix: The skipInitialViewPopulation option concerns only the *initial* view population. That is, the very first time the view is registered. Subsequent registrations of a persistent view should follow the standard view re-population routine. For example, if the versionTag is later changed (v2.1 -> v2.2 upgrade), then the view should automatically be re-populated. 2015-01-14 11:50:28 -08:00
Robbie Hanson
dabe7e6a46 Fixing implementation for nonPersistent views, and adding corresponding unit tests. 2015-01-14 11:36:59 -08:00
Robbie Hanson
ded710faed Restoring proper tabbing 2015-01-14 11:17:59 -08:00
Robbie Hanson
c94ce122ba Minor API change for view enumeration methods with a filter: the filter should come before the block as its invoked first. 2015-01-09 15:53:58 -08:00
Nico Prananta
3e0feff462 unit test skipInitialPopulationView for YDBView and YDBFilteredView 2015-01-09 11:27:10 +09:00
Nico Prananta
687a095f66 Merge commit 'af1d5facb953fb37a572a45a6b75297a1bf8b8eb' 2015-01-09 10:45:55 +09:00
Nico Prananta
dec7e7f793 synthesize skipInitialViewPopulation 2015-01-07 22:23:21 +09:00
Nico Prananta
d009f0a02b fix needs populate view in view transaction and filtered view transaction. 2015-01-07 22:09:32 +09:00
Robbie Hanson
b562c77515 Didn't realize git was ignoring Xcode workspaces 2014-12-07 02:53:39 -08:00
Robbie Hanson
4345bce2b8 Minor improvements to the minimalistic UI for CloudKitTodo - auto sizing title field 2014-12-07 02:02:54 -08:00
Robbie Hanson
873d08920f Minor improvements to the minimalistic UI for CloudKitTodo - multi-line table cells & on/off checkmark buttons 2014-12-06 21:47:21 -08:00
Robbie Hanson
ed2fb0b6a2 Minor improvements to the minimalistic UI for CloudKitTodo - now uses colors to reflect todo.priority 2014-12-06 18:23:32 -08:00
Robbie Hanson
2b07f7084b Bug fixes: Merging remote records actually works now. 2014-12-06 17:24:48 -08:00
Robbie Hanson
a537c25323 Bug fix: Looks like remoteRecord.changedKeys isn't given to us. 2014-12-05 18:05:46 -08:00
Robbie Hanson
bac946bd8f Fixing crash: Forgot to make a mutable copy. And forgot to actually store the object back into the database. 2014-12-05 18:04:50 -08:00
Robbie Hanson
255bd19340 Bug fix: Code didn't take into account that 'nil' is a valid value in a CKRecord 2014-12-05 16:41:34 -08:00
Robbie Hanson
94990b1c3d Adding more efficient access to inFlight / queued / pending change-sets count. 2014-12-05 16:39:01 -08:00
Robbie Hanson
fcf36874b5 Minor bug fix: The mergeChangesForRecordID wasn't taking into account the databaseIdentifier. Which may have caused problems if there were multiple records with the same recordID spread across different databaseIdentifier's. 2014-12-05 15:04:54 -08:00
Robbie Hanson
1db0e6ed6c Bug fix: Wasn't properly updating the cleanRecordTabeleInfoCache (in both completionConnection, and other connections) 2014-12-04 20:02:38 -08:00
Robbie Hanson
3dd8be11ff Adding "Base CKRecord" to EditViewController screen. This allows for viewing the recordChangeTag. 2014-12-04 18:58:12 -08:00
Robbie Hanson
52142f0cbc Merge branch 'master' into 2.6 2014-12-04 18:29:03 -08:00
Robbie Hanson
5e110f9ebc Cool new macro trick for MyDatabaseObject. 2014-12-04 18:27:20 -08:00
Robbie Hanson
81def8cb2b Bug fix - improper checking was causing the mappings to get re-written to the database when it didn't need to be. 2014-12-04 18:04:24 -08:00
Robbie Hanson
ee160dd02a Bug fix for mergeRecord:databaseIdentifier: - wasn't storing sanitized version of record if it was a "clean" merge. 2014-12-04 18:03:43 -08:00
Robbie Hanson
92df3e1167 Bug fix for MyTodo : wasn't properly saving todo.priority. Also dropping todo.notes because it doesn't add to the usefulness of the example code. 2014-12-04 18:01:39 -08:00
Robbie Hanson
123ba53c4d Performance improvement for MyDatabaseObject. It now caches (within the class) the calculated class configuration information. 2014-12-04 17:59:57 -08:00
Robbie Hanson
af1d5facb9 Merge pull request #130 from mackross/master
Fix so row inserts into a view are included in -hasChangesFor… methods.
2014-12-04 16:59:58 -08:00
Andrew Mackenzie-Ross
688f4df63d Fix so row inserts into a view are included in -hasChangesFor… methods. 2014-12-04 16:49:34 -08:00
Robbie Hanson
11d3b116d2 Fixing compiler warnings 2014-12-04 16:18:28 -08:00
Robbie Hanson
ce3219e1b3 Fixing capitalization in the textField 2014-12-04 01:29:37 -08:00
Robbie Hanson
4810ce82c2 Work In Progress (YapDatabaseCloudKit) 2014-12-04 01:18:45 -08:00
Robbie Hanson
9f98df3b4a Renaming YapDatabaseCloudKitTest to CloudKitTodo 2014-12-03 23:19:09 -08:00
Robbie Hanson
64923d2915 Refactoring ivar name, and fixing related crash. 2014-12-03 22:58:48 -08:00
Robbie Hanson
1c25579448 Bug fix: Wasn't properly deleting the CKRecordID. 2014-12-03 22:58:07 -08:00
Robbie Hanson
7bbac53ace Bug fix for recordHandlerBlock. Should be using hasChangedSyncableProperties (instead of hasChangedProperties). 2014-12-03 21:02:39 -08:00
Robbie Hanson
d3b2e099fe Adding ability to fetch previouslyRegisteredExtensionNames. 2014-12-03 12:43:37 -08:00
Robbie Hanson
af240344bb Work In Progress (YapDatabaseCloudKit) 2014-12-02 23:23:37 -08:00
Robbie Hanson
5521de158a Work In Progress (YapDatabaseCloudKit) 2014-12-02 00:39:02 -08:00
Robbie Hanson
e450be7094 Updating all github links to the new yapstudios address 2014-12-01 21:53:24 -08:00
Robbie Hanson
29d70761cb Adding ability to enumerate changedKeys for a set of commits. 2014-12-01 18:33:11 -08:00
Robbie Hanson
801769afcb Work In Progress (YapDatabaseCloudKit) 2014-12-01 10:28:33 -08:00
Robbie Hanson
89e0f3f8bd Work In Progress (YapDatabaseCloudKit) 2014-11-25 19:18:33 -08:00
Robbie Hanson
c67c6970eb Work In Progress (YapDatabaseCloudKit) 2014-11-25 18:10:07 -08:00
Robbie Hanson
88ef306b0e The YapDatabaseSanitizer is now split into YapDatabasePreSanitizer & YapDatabasePostSanitizer. 2014-11-25 17:47:28 -08:00
Robbie Hanson
447f5a449d Modifying YapDatabaseOptions.passphraseBlock to return NSData instead of NSString. This makes a bit more sense because sqlite3_key takes a 'void*' parameter, which doesn't necessarily need to be a string. Also, since the block no longer returns a "passphrase", the block was renamed to YapDatabaseOptions.cipherKeyBlock. (Note that one can still return a string as before by simply encoding it, via UTF8 with NULL termination, to NSData.) 2014-11-25 10:41:57 -08:00
Robbie Hanson
a2868ea795 Merge branch 'master' into 2.6 2014-11-25 09:36:46 -08:00
Robbie Hanson
ae82b794e0 Updating to podspec to v2.5.4 2014-11-25 09:26:36 -08:00
Robbie Hanson
d84938db27 Fixing Mac/Desktop Xcode project. 2014-11-24 15:22:36 -08:00
Robbie Hanson
f678c89ee2 Improving the documentation (and flexibility) of YapCache to allow it to be exposed to the outside world. (It's no longer internal/private. It can now be used in your projects if you want.) 2014-11-24 15:00:42 -08:00
Robbie Hanson
77d17228f6 Adding another init method to YapDatabase for convenience. All the same options, but less typing for a common init scenario. 2014-11-24 11:01:27 -08:00
Robbie Hanson
9e3a7b5be8 Work In Progress (YapDatabaseCloudKit) - I may finally have the general API nailed down 2014-11-24 10:44:22 -08:00
Robbie Hanson
ce0d1d814e Work In Progress (YapDatabaseCloudKit) 2014-11-16 19:35:25 -08:00
Robbie Hanson
edc2a6996b Merge branch 'master' into 2.6 2014-11-16 14:45:11 -08:00
Robbie Hanson
618654866a Work In Progress (YapDatabaseCloudKit) 2014-11-16 14:44:19 -08:00
Robbie Hanson
68bdb5b8db Bug fix for issue #125 - View mapping notification bug. Unit tests added. 2014-11-14 18:21:24 -08:00
Robbie Hanson
64ebd9edef Work In Progress (YapDatabaseCloudKit) 2014-11-05 23:39:06 -08:00
Robbie Hanson
23436198f5 Merge branch 'master' into 2.6 2014-11-05 21:24:48 -08:00
Robbie Hanson
c90dc0e2c7 Minor bug fix. Copying fix from commit e2ee3a348d into another location. 2014-11-05 18:24:42 -08:00
Robbie Hanson
6daaabd152 Minor performance optimization. We shouldn't need to update the visibility unless the rangeOptions changed. 2014-11-05 18:19:53 -08:00
Robbie Hanson
e0d2e00ce1 Possible bug fix for issue #125. Unit test added. 2014-11-05 18:13:38 -08:00
Robbie Hanson
56bdf15023 Merge branch 'master' into 2.6 2014-11-05 12:34:30 -08:00
Robbie Hanson
e2ee3a348d Bug fix for issue #128 - Flexible range minLength bug. (Unit tests added) 2014-11-05 12:27:01 -08:00
Robbie Hanson
781da8ce14 Work In Progress (YapDatabaseCloudKit) 2014-11-05 11:09:11 -08:00
Nico Prananta
9f717d54a0 skip initial view population 2014-11-05 00:46:03 +09:00
Robbie Hanson
46942f30b8 Work In Progress (YapDatabaseCloudKit) 2014-10-30 10:00:29 -07:00
Robbie Hanson
b4c1cf5fea Work In Progress (YapDatabaseCloudKit) 2014-10-24 12:10:40 -07:00
Robbie Hanson
1310c8d99c Bug fix for MyDatabaseObject example. 2014-10-24 12:04:24 -07:00
Robbie Hanson
bb5040bcbe Extensions API Change: prepareChangeset is now flushPendingChangesToExtensionTables. commitTransaction is now didCommitTransaction. rollbackTransaction is now didRollbackTransaction. 2014-10-20 16:35:52 -07:00
Robbie Hanson
041b528938 Work In Progress (YapDatabaseCloudKit) 2014-10-20 11:17:23 -07:00
Robbie Hanson
776d2676e3 Minor code consolidation & cleanup. 2014-10-20 11:14:46 -07:00
Robbie Hanson
3967465e08 Bug fix for minor memory leak 2014-10-12 11:46:25 -07:00
Robbie Hanson
fcb98e1c7b Merge branch 'master' into 2.6 2014-10-08 15:01:36 -07:00
Robbie Hanson
9b9e253255 Updating podspec 2014-10-08 12:15:10 -07:00
Robbie Hanson
0fa9dcefc1 Merge pull request #121 from mackross/master
Imports required for dynamic framework.
2014-10-08 12:06:27 -07:00
Robbie Hanson
ece9c86aa4 Merge pull request #120 from Tundaware/119-nsarray-query-parameters
Adds support for NSArray parameters to YapDatabaseQuery
2014-10-08 12:02:54 -07:00
Robbie Hanson
dff790b281 The permittedTransactions API was really only meant for debugging. Using a macro to allow it to be disabled. 2014-10-08 10:49:23 -07:00
Robbie Hanson
fb89e8c77e Improving benchmarking code to test readOnly transaction overhead when using a longLivedReadTransaction 2014-10-08 10:38:24 -07:00
Robbie Hanson
bfe91a9789 Improving benchmarking code to test readOnly transaction overhead when using a longLivedReadTransaction 2014-10-08 10:37:06 -07:00
Andrew Mackenzie-Ross
8f47440ed0 Imports required for dynamic framework. 2014-10-07 23:45:50 -07:00
George Cox
5701e64c60 Adds support for NSArray parameters to YapDatabaseQuery
Example:
[YapDatabaseQuery queryWithFormat:@"WHERE col IN (?)", anArray];

- Adds unit tests for YapDatabaseQuery
- Adds new unit test for YapDatabaseSecondaryIndex since it makes use of YapDatabaseQuery

Addresses issue #119
2014-10-06 23:28:49 -04:00
Robbie Hanson
722f370a9c Merge branch 'master' into 2.6 2014-10-02 16:08:42 -07:00
Robbie Hanson
41c8e77e32 Fix for assertion crash in YapDatabaseView. Bug caused by recent commit. Unit test added. 2014-10-02 16:08:03 -07:00
Robbie Hanson
620e52d00a Merge branch 'master' into 2.6
Resolved Conflicts:
	YapDatabase/Extensions/FullTextSearch/YapDatabaseFullTextSearch.m
	YapDatabase/Extensions/SecondaryIndex/YapDatabaseSecondaryIndex.m
2014-10-01 18:21:48 -07:00
Robbie Hanson
e3ff0dcb08 Updating YapDatabaseSecondaryIndex init API to work with Swift. (Similar to recent fixes for YapDatabaseView) 2014-10-01 15:19:01 -07:00
Robbie Hanson
154510f365 Restoring removed init methods in YapDatabaseFullTextSearch as deprecated. 2014-10-01 12:33:52 -07:00
Robbie Hanson
4d54895ffb Updating YapDatabaseFullTextSearch init API to work with Swift. (Similar to recent fixes for YapDatabaseView) 2014-10-01 10:30:19 -07:00
Robbie Hanson
6b4dffe66d Fixed an obscure bug in YapDatabaseView that may not properly remove a rowid if an item is inserted & deleted in the same transaction. Unit test added. 2014-09-30 18:53:44 -07:00
Robbie Hanson
e5a3a521ee Stricter error checking in [YapDatabaseViewTransaction commitTransaction] 2014-09-30 17:44:24 -07:00
Robbie Hanson
46f3d404c3 Minor bug fix: internal keyCache wasn't properly cleared when the database was cleared 2014-09-30 12:36:16 -07:00
Robbie Hanson
efdab65696 Minor performance improvement for Views 2014-09-30 12:09:06 -07:00
Robbie Hanson
9bd4c942b5 Minor extensions API change: supportsDatabase:withRegisteredExtensions: is now an optional method override. Previously it was required. 2014-09-30 12:03:24 -07:00
Robbie Hanson
043deeec1a Adding MyDatabaseObjectExample. This puts the MyDatabaseObject base class example from the wiki into the project, and also expands on the idea in order to optionally track which properties of an object have changed. 2014-09-28 15:55:28 -07:00
Robbie Hanson
65097c1015 Added permittedTransactions property. Allows for enforcement of desired behavior for dedicated connections. 2014-09-24 22:41:24 -07:00
Robbie Hanson
db28cc46be Simplifying the API for creating Views. Instead of passing a block & blockType, there is a new wrapper class that automatically sets the blockType for you. This also helps when using YDBViews in Swift. Addresses issue #91. 2014-09-14 17:32:11 -07:00
Robbie Hanson
58c0a6b729 Removing setPrimitive methods, which have been fundamentally broken since the addition of extensions. Replacing them with advanced setObject methods that allow one to pass pre-serialized versions of the object and/or metadata. Also renaming the primitive accessors to use the new serializedObject / serializedMetadata terminology. Fixes issue #23 2014-09-08 21:38:12 -07:00
Robbie Hanson
11169abe42 Fixing log statement - snapshots were backwards 2014-09-08 14:22:03 -07:00
Robbie Hanson
d441af1a05 Adding YapWhitelistBlacklist class. This replaces primitive whitelist sets for things like options.allowedCollections. 2014-09-06 12:56:35 -07:00
Robbie Hanson
c464004f7c Adding convenience method: [YapDatabaseView isEmptyGroup:] 2014-09-05 17:52:29 -07:00
Robbie Hanson
2c09b0adff Bug fix for rolling back an in-memory view. 2014-09-05 17:47:16 -07:00
Robbie Hanson
ad44c04e3a Adding ability to fetch "pragma auto_vacuum" value. This helps for those who need to run vacuum in order to fix older databases. 2014-08-27 12:20:03 -07:00
Robbie Hanson
fbfc86826f Bumping version in podspec 2014-08-27 10:18:30 -07:00
Robbie Hanson
69de36d7b8 Bug fix: flushMemory operation should be asynchronous, so as not to block the main thread. Fixes issue #113 2014-08-26 16:55:25 -07:00
Robbie Hanson
3bd290a99b Adding ability to run VACUUM command (synchronously or asynchronously) 2014-08-26 16:49:23 -07:00
Robbie Hanson
9ef69790c2 Bug fix: checkpoint queue was implicitly retaining self 2014-08-26 15:57:22 -07:00
Robbie Hanson
e1b2e91f9a Performance optimization for YapCache 2014-08-23 14:15:41 -07:00
Robbie Hanson
5ca9fb146b Improving documentation for extensions protocol. 2014-08-23 12:22:58 -07:00
Robbie Hanson
86b5e8d2b5 Moving documentation into the *.m files for YapDatabaseExtension protocol. 2014-08-23 11:39:33 -07:00
Robbie Hanson
60240b8f53 More logging and help for common exception. 2014-08-21 16:47:39 -07:00
Robbie Hanson
607f51c07b Bumping version in podspec 2014-08-21 14:33:21 -07:00
Robbie Hanson
ce645ec22f Several minor performance improvements for getSectionChanges:rowChanges:forNotifications:withMappings: 2014-08-21 14:24:01 -07:00
Robbie Hanson
84606fd92b Fixing minor typo - caused view changeset to be generated unnecessarily (but without other harm). 2014-08-21 13:51:04 -07:00
Robbie Hanson
a8036ed520 Removed some unnecessary code (dead stores), left over from previous refactoring. 2014-08-21 13:46:44 -07:00
Robbie Hanson
043051d8fb Bug fix: Pragma auto_vacuum may not have been set properly if a previous database file was auto deleted or renamed due to corruption. Thanks analyzer. 2014-08-21 13:41:31 -07:00
Robbie Hanson
1b61108b6a Bug fix: Invoking [YapDatabaseViewMappings updateWithTransaction] (rather than going through getSectionChanges:rowChanges:::) did not result in properly updating rangeOptions. Several unit tests added. 2014-08-21 11:48:16 -07:00
Robbie Hanson
dc544a5fa0 Bug fix for crash caused by YapDatabaseView - getSectionChanges:rowChanges:::. Bug recreated by removing all items from a view group, and using mappings with a flexible range. Corresponding unit test added. 2014-08-20 15:23:37 -07:00
Robbie Hanson
dc10016e6c Bug fix for crash caused by YapDatabaseView - getSectionChanges:rowChanges:::. Bug recreated by removing all items from the database, and using mappings with a flexible range. 2014-08-19 08:26:15 -07:00
Robbie Hanson
5e0db923b6 Merge pull request #111 from mackross/master
Update YapDatabase podspec version to 2.5.0
2014-08-18 20:33:44 -07:00
mackross
e3d4932af2 Update YapDatabase podspec version to 2.5.0 2014-08-18 10:51:06 -07:00
Robbie Hanson
74de12c980 Adding ability to query a YapDatabaseView to see if a particular group (or groups) changed, without using mappings. 2014-08-15 14:39:34 -07:00
Robbie Hanson
ac8f1b0323 Tiny tiny performance improvement (for the common case) 2014-08-15 14:38:55 -07:00
Robbie Hanson
3a309c82f9 Bug fix for potential subtle bug in YapDatabaseView. Code didn't take into account possibility of empty pages, which is possible if items have been deleted from the view within the transaction. 2014-08-12 15:43:37 -07:00
Robbie Hanson
fc911d22b1 Merge branch '2.5' 2014-08-12 09:02:38 -07:00
Robbie Hanson
fb96066543 Bug fix for issue #104 2014-08-12 08:57:45 -07:00
Robbie Hanson
1d848f4388 Minor documentation improvement. 2014-08-12 08:54:39 -07:00
Robbie Hanson
9737a4f585 Adding ability to create a YapDatabaseQuery instance that matches all items. 2014-08-12 08:54:10 -07:00
Robbie Hanson
e230dbcda5 Setting the "pragma journal_size_limit" to zero by default. This should result in the WAL file staying much smaller during continued heavy use of the database. 2014-08-08 13:42:36 -07:00
Robbie Hanson
944076b55b Adding internal utility method to fetch the sqlite version. 2014-08-08 13:36:19 -07:00
Jordan Hamill
0467ec6f22 Handle NSNull for secondary indexed column when adding a row. 2014-08-07 12:47:41 -07:00
Robbie Hanson
87d167b0bf Merge pull request #97 from jordanhamill/handle-nsnull-secondary-indices
Handle NSNull for secondary indexed column when adding a row.
2014-08-07 12:33:35 -07:00
Robbie Hanson
dadb597115 Adding a method to fetch a rough estimate of the size of change-set (as it affects a YapDatabaseView). Addresses issue #103 2014-08-07 12:23:17 -07:00
Robbie Hanson
90a76f1392 Adding enumerateGroupsUsingBlock method to YapDatabaseViewTransaction. 2014-08-07 11:17:16 -07:00
Robbie Hanson
a4ab5714cf Setting auto_vacuum value to "full" for new databases. This ensures the database file gets truncated when a lot of data is deleted. 2014-08-04 17:19:16 -07:00
Robbie Hanson
59b79ae37e Apparently "pragma synchronous" defaults to "full", and not "normal" as the documentation states. It also appears this needs to be set per-connection. None of this is very well documented in sqlite. 2014-08-04 17:16:34 -07:00
Robbie Hanson
dfc4782d7c Bug fix - unused utility method wasn't working properly 2014-08-04 17:09:25 -07:00
Robbie Hanson
03e470c0a6 Exposing the YapDatabaseOptions property (post-init) 2014-08-04 17:07:59 -07:00
Robbie Hanson
66ac94282b Adding enumerate...withFilter: methods to YapDatabaseViewTransaction (Convenience) 2014-07-31 16:59:53 -07:00
Robbie Hanson
7a38986b18 Minor documentation cleanup 2014-07-29 14:05:57 -07:00
Jordan Hamill
7d0bda4776 Handle NSNull for secondary indexed column when adding a row. 2014-07-24 19:00:00 +01:00
Robbie Hanson
b1204068a6 Syntax change to make writing code for YapDatabase more readable. Also a nod to Swift and Trailing Closures. 2014-07-15 10:53:16 -07:00
Robbie Hanson
ad4e173ae2 Fixing ambiguity in code that was causing unit test to occasionally fail. 2014-07-11 17:42:57 -07:00
Robbie Hanson
ee253306bf Improving configurability of mappings: One can not configure a dynamic setting for "all" groups, and then provide specific overrides for particular groups. 2014-07-11 17:14:35 -07:00
Robbie Hanson
cf8f2c9a01 Bug fix: Improper sectionChanges / rowChanges may have been calculated when using mappings with autoGroupConsolidation + dynamicGroups. 2014-07-11 17:12:09 -07:00
Robbie Hanson
e61a7d3d1b Minor documentation improvements 2014-07-11 15:57:36 -07:00
Robbie Hanson
b1506de241 A bit of code cleanup 2014-07-11 15:57:19 -07:00
Robbie Hanson
e14c8f00ac Bug fix for issue #89 - potential infinite loop when using multiple ranges 2014-07-11 12:41:05 -07:00
Robbie Hanson
0fa1052ece Adding a few extra convenience methods for fetching metadata from a YapDatabaseView. 2014-07-02 16:05:22 -07:00
Robbie Hanson
51e78c842b Merge pull request #92 from JanGorman/master
Less strict CocoaLumberjack subspec versioning
2014-06-30 17:24:28 -07:00
Robbie Hanson
628e3b2e6c API change: renamed method: unregisterExtension: -> unregisterExtensionWithName: 2014-06-30 16:14:07 -07:00
Robbie Hanson
4712ed98d1 Adding dedicated accessor for the yapMemoryTableTransaction 2014-06-30 15:20:50 -07:00
Robbie Hanson
4c99d5d049 Performance improvement for non-persistent (in-memory only) extensions. Also fixing bugs having to do with rollback of transactions, and associated block changes. Plus minor bug fixes for improved thread safety concerning property accessors in YapDatabaseView. 2014-06-30 15:07:47 -07:00
Jan Gorman
27072f2dd1 Less strict CocoaLumberjack subspec versioning 2014-06-30 14:14:33 +02:00
Robbie Hanson
965178f440 Converting enum to modern NS_ENUM. 2014-06-26 18:48:17 -07:00
Robbie Hanson
fce797b05a Converting enum to modern NS_ENUM. 2014-06-26 18:40:50 -07:00
Robbie Hanson
1e98e1b00b According to Apple's "Adopting Modern Objective-C" : "the type for [NS_OPTIONS] should usually be NSUInteger". 2014-06-26 18:40:18 -07:00
Robbie Hanson
e91b4aace9 Updating CocoaLumberjack to commit fe6824c675ede4ecc19ca1edd95b0c36e3cb245c. Fixes issue #82 2014-06-13 18:27:30 -07:00
Robbie Hanson
136ace8e07 Bug fix for new YapDatabaseViewState optimization. But was introduced via commit 2fc6bcc85c (24 hours prior). 2014-06-11 13:57:24 -07:00
Robbie Hanson
ab1ef7a5af Updating code to match new NS_OPTIONS syntax. 2014-06-10 16:50:53 -07:00
Robbie Hanson
0f887245b3 Merge branch 'master' of https://github.com/danthorpe/YapDatabase into danthorpe-master 2014-06-10 15:56:07 -07:00
Robbie Hanson
2fa69ac170 Decreasing log level in relationship extension 2014-06-10 15:52:04 -07:00
Robbie Hanson
2fc6bcc85c Memory optimization: allowing multiple YapDatabaseViewConnections to share a single immutable "state" 2014-06-10 15:51:39 -07:00
Robbie Hanson
08420fff7c Minor change - casting array as immutable in situations where it's not expected to be mutated 2014-06-09 17:27:04 -07:00
Daniel Thorpe
d70187e87c Converts enum typedefs to NS_ENUM or NS_OPTIONS as appropriate
Without this, they cannot be inferred by/using Swift.

Signed-off-by: Daniel Thorpe <danthorpe@me.com>
2014-06-09 14:13:55 +01:00
Robbie Hanson
c00b215fb9 Added support for encrypting the destinationFilePath when storing it to the database. Also fixed a few bugs in the YapDatabaseRelationship extension. And added quite a bit more unit test coverage for the extension. 2014-05-30 16:35:21 -07:00
Robbie Hanson
2d62d2f272 Added an optimization that allows extensions to cache information from the latest commit. If an extension requires initial state to be built (in prepareIfNeeded), then it can use this optimization to sometimes do so without any disk IO. 2014-05-23 17:52:11 -07:00
Robbie Hanson
17732ebe7a Adding allowedCollections options to YapDatabaseSecondaryIndex 2014-05-20 17:10:17 -07:00
Robbie Hanson
2a3b582874 Work in progress on YapDatabaseSearchResultsView 2014-05-20 08:56:22 -07:00
Robbie Hanson
9f448c0e0e Work in progress on YapDatabaseSearchResultsView 2014-05-19 20:55:58 -07:00
Robbie Hanson
94f6a6c6a5 Fixing compiler warning (which is actually a false positive) 2014-05-19 20:55:23 -07:00
Robbie Hanson
11f80b4318 Performance improvement for YapCollectionKey, and many related activities, especially consolidateRowChanges 2014-05-19 20:54:54 -07:00
Robbie Hanson
ed9e1db96d Performance improvement for consolidateRowChanges 2014-05-19 20:49:51 -07:00
Robbie Hanson
94ac39e4aa Performance improvement for processRowChanges 2014-05-19 20:45:36 -07:00
Robbie Hanson
ab6c07f54d Bug fix for crash (in new YapDatabaseSearchResultsView code) 2014-05-19 20:39:28 -07:00
Robbie Hanson
a95c0f430b Work in progress on YapDatabaseSearchResultsView 2014-05-16 18:04:00 -07:00
Robbie Hanson
8ae3f99569 Work in progress on YapDatabaseSearchResultsView 2014-05-15 19:27:52 -07:00
Robbie Hanson
084adbe33d Work in progress on YapDatabaseSearchResultsView 2014-05-15 18:52:51 -07:00
Robbie Hanson
ec93fb55eb Renaming a few methods: numberOfKeysInGroup -> numberOfItemsInGroup, numberOfKeysInAllGroups -> numberOfItemsInAllGroups. This name change matches the API in YapDatabaseViewMappings (also UICollectionView). The previous methods have been marked as deprecated. 2014-05-15 17:59:10 -07:00
Robbie Hanson
24b6cba20a Removing deprecated methods 2014-05-15 17:53:56 -07:00
Robbie Hanson
e95e33a2f0 Work in progress on YapDatabaseSearchResultsView 2014-05-15 17:35:51 -07:00
Robbie Hanson
467652c42d Work in progress 2014-05-14 17:33:26 -07:00
Robbie Hanson
ee539faec5 Work in progress 2014-05-14 14:26:28 -07:00
Robbie Hanson
f19c06e89f Updating podspec to version 2.4.3 2014-05-13 17:27:13 -07:00
Robbie Hanson
ace283ce77 Merge branch 'master' into 2.5 2014-05-13 17:23:54 -07:00
Robbie Hanson
de727e1c04 Bug fix for issue #76 - Setting default objectPolicy & metadataPolicy doesn't affect new connections 2014-05-13 17:22:04 -07:00
Robbie Hanson
229dddf116 Updating relationship extension API to address several requests / shortcomings. The manual edge removal API has been improved, and proper documentation for it has been added. 2014-05-13 16:58:52 -07:00
Robbie Hanson
da291bcafa Bug fix - was passing improper parameters to yapDatabaseRelationshipEdgeDeleted:withReason: 2014-05-13 15:30:06 -07:00
Robbie Hanson
78696a3dce Fixing compiler warnings in unit test code (shadowed variable warnings) 2014-05-13 15:22:05 -07:00
Robbie Hanson
8b19cb964a Bug fix for issue #74 - shadowed variable warnings 2014-05-13 13:16:51 -07:00
Robbie Hanson
606a0aba1e Work in progress 2014-05-01 18:30:20 -07:00
Robbie Hanson
be4387cfd2 Standardizing sqlite3_stmt method structure. 2014-05-01 15:59:03 -07:00
Robbie Hanson
8cf409f594 Merge branch 'master' into 2.5 2014-04-30 18:34:01 -07:00
Robbie Hanson
e1e2ea1e23 Work in progress 2014-04-30 18:31:47 -07:00
Robbie Hanson
0be3c2f3fc Adding a few more unit tests. 2014-04-29 16:52:20 -07:00
Robbie Hanson
a50673713a Merge pull request #70 from chrisballinger/sqlcipher-fts
Use FTS subspec for SQLCipher
2014-04-25 10:28:55 -07:00
Robbie Hanson
eaf869e77f Work in progress 2014-04-24 14:45:08 -07:00
Chris Ballinger
1b2bb60fad Use FTS subspec for SQLCipher 2014-04-24 12:32:13 -07:00
Robbie Hanson
c687466d28 Merge branch 'master' into 2.5 2014-04-24 11:10:57 -07:00
Robbie Hanson
2607767ee6 Work in progress 2014-04-24 11:10:38 -07:00
Robbie Hanson
e2ed9318a4 Updating podspec to version 2.4.2 2014-04-16 12:00:55 -07:00
Robbie Hanson
005f97b7f3 Converting setCustomObjectForYapDatabaseModifiedNotification method into a property named yapDatabaseModifiedNotificationCustomObject. This makes it readable too. 2014-04-16 11:56:58 -07:00
Robbie Hanson
2bd9d9678e Work in progress on YapDatabaseSearchResultsView 2014-04-16 11:10:10 -07:00
Robbie Hanson
f4e44eda76 Merge branch 'master' into 2.5 2014-04-15 20:25:23 -07:00
Robbie Hanson
4caea30961 Merge pull request #68 from choefele/master
Fixed Xcode analyzer issues
2014-04-10 09:17:46 -07:00
Claus Höfele
c33266dac0 Fixed analyzer issues "Branch condition evaluates to a garbage value (within a call to 'FreeYapDatabaseString')" and "Potential leak of memory pointed to by '_dstFilePath.str'" 2014-04-10 12:41:41 +02:00
Claus Höfele
80ac68a22a Fixed analyzer issue "Access to instance variable 'count' results in a dereference of a null pointer (loaded from variable 'pageMetadata')" 2014-04-10 11:49:17 +02:00
Claus Höfele
5c9b14384a Fixed analyzer issue "Value stored to 'srcCollection' is never read" 2014-04-10 11:46:02 +02:00
Robbie Hanson
d6b2856395 Work in progress 2014-04-05 17:01:08 -07:00
Robbie Hanson
ec2699a1ff Work in progress 2014-04-04 18:53:34 -07:00
Robbie Hanson
4cb027d9ea Optimizing advanced enumerate method in YapDatabaseView 2014-04-04 16:20:39 -07:00
Robbie Hanson
66d54d4551 Consolidating code in FTS extension. Adding internal rowid versions of the enumerate methods. 2014-04-04 16:19:43 -07:00
Robbie Hanson
9da56a1ee4 Merge branch 'master' into 2.5 2014-04-02 15:50:34 -07:00
Robbie Hanson
119f56ad22 Method stubs for YapDatabaseSearchResults (new extension in progress) 2014-04-02 15:48:20 -07:00
Robbie Hanson
ddf0bea1f4 Converting YapDatabaseSecondaryIndex extension to use new versionTag style. 2014-04-02 15:47:26 -07:00
Robbie Hanson
bc13c79ca9 Converting YapDatabaseFullTextSearch extension to use new versionTag style. 2014-04-02 15:32:07 -07:00
Robbie Hanson
549e0a1724 Adding a few helpful properties to YapDatabaseRelationship 2014-04-02 15:23:36 -07:00
Robbie Hanson
1e214586d1 Converting YapDatabaseRelationship extension to use new versionTag style. 2014-04-02 15:07:30 -07:00
Robbie Hanson
7eab44c93e Making YapDatabaseViewOptions subclass-able 2014-04-02 14:52:04 -07:00
Robbie Hanson
aaeaf759f6 Update README.md 2014-03-31 17:27:21 -07:00
Robbie Hanson
b755301d15 Bug fix - YapDatabaseFilteredView wasn't updating its groupingBlock & sortingBlock when it was changed in the parentView. 2014-03-31 17:02:23 -07:00
Robbie Hanson
4fe118fc81 Bug fix - One should not be able to change the groupingBlock / sortingBlock of a filteredView. 2014-03-31 16:46:48 -07:00
Robbie Hanson
1ac301c775 Exposing the internal collectionKey for the YapDatabaseViewRowChange class. I found some situations in which this is valuable. 2014-03-28 14:17:20 -07:00
Robbie Hanson
81e555a9de Comments clarifications 2014-03-28 12:29:29 -07:00
Robbie Hanson
4de0e73e47 Updating podspec to v2.4.1 2014-03-28 12:28:42 -07:00
Robbie Hanson
2a6d26a958 Merge branch 'master' of https://github.com/yaptv/YapDatabase 2014-03-28 12:27:56 -07:00
Robbie Hanson
a81d289e77 Fixes for Desktop Xcode project 2014-03-28 12:27:40 -07:00
Robbie Hanson
c78fccae32 Merge pull request #64 from chrisballinger/sqlcipher-option
Add SQLCipher support
2014-03-28 12:19:17 -07:00
Chris Ballinger
26276796c3 Add SQLCipher support 2014-03-28 00:12:18 -07:00
Robbie Hanson
33691cf541 Adding advanced configuration options. This includes configuration of PRAGMA synchronous option, and telling YapDatabase how to handle corrupt database files. Fixes issue #51 2014-03-26 16:26:55 -07:00
Robbie Hanson
e43cccd658 Minor performance improvement - no need to standardize the path twice 2014-03-26 16:24:26 -07:00
Robbie Hanson
4110c4e925 Renaming YapDatabaseDefaults class to YapDatabaseConnectionDefaults 2014-03-26 16:23:53 -07:00
Robbie Hanson
a7a983ef00 Removing unnecessary pragma code 2014-03-26 12:15:05 -07:00
Robbie Hanson
7f7072b7e7 Merge pull request #62 from leonardfactory/fix-section-changes
Small bug fix for section changes consolidation crashing
2014-03-26 10:34:26 -07:00
Leonardo Ascione
a806d92745 Small bug fix for section changes consolidation crashing
YapDatabase now doesn’t crash when replacing all section&rows
2014-03-25 22:36:03 +01:00
Robbie Hanson
316a9a2ce9 Bug fix for issue #59 - Relationship deletion rules not being followed correctly. Also added a unit test for the problem. 2014-03-14 16:09:27 -07:00
Robbie Hanson
867b7d2e22 Minor performance optimization 2014-03-11 18:10:39 -07:00
Robbie Hanson
cfeb2c5196 Fixing compiler warning about unused variable 2014-03-11 18:09:18 -07:00
Robbie Hanson
282da09e2d Fixing compiler warnings in unit tests 2014-03-11 18:09:02 -07:00
Robbie Hanson
1663a5bdef Upgrading project to use XCTest 2014-03-11 18:02:14 -07:00
Robbie Hanson
fa5e6dfb61 Small bug fix for relationship extension 2014-03-09 17:43:53 -07:00
Robbie Hanson
3713d54772 Small bug fix for relationship extension 2014-03-07 18:41:13 -08:00
Robbie Hanson
4c1397475a Bug fix: YapDatabaseFilteredView was not properly updated when its parentView changed groupingBlock or filteringBlock 2014-03-07 18:14:21 -08:00
Robbie Hanson
84f7604cdd Bug fix: YapDatabaseView may have returned incorrect results in 'numberOfGroups' and 'allGroups' methods, if invoked during a readWriteTransaction after removing all items from a particular group. 2014-03-07 18:13:03 -08:00
Robbie Hanson
f22a2c99fb Adding unit tests for issue #54 2014-03-06 20:07:42 -08:00
Robbie Hanson
8e170e8ff2 Bug fix for YapDatabaseRelationship extension - error log in the wrong place 2014-03-06 20:07:04 -08:00
Robbie Hanson
ac2366b3b3 Switching from abstract memoryFlushLevels to a more defined flags setup. Also changing the default memoryFlush to flush both caches and pre-compiled statements. 2014-03-06 19:49:28 -08:00
Robbie Hanson
cfd4b23028 Minor bug fix: keyCache wasn't getting flushed during flushMemoryWithLevel method 2014-03-06 19:07:15 -08:00
Robbie Hanson
a3c1862172 Multiple bug fixes for YapDatabaseRelationship. Fixes issue #54 2014-03-06 19:06:23 -08:00
Robbie Hanson
23c015407d Bug fix for YapDatabaseView change processing (get sectionChanges & rowChanges) when a flexible range is being used. Added associated unit tests to match. 2014-03-05 18:35:59 -08:00
Robbie Hanson
179aa0b328 Minor improvement to new unit test. Issue #52 2014-02-25 09:29:36 -08:00
Robbie Hanson
978a756bc5 Adding unit test for issue #52 2014-02-25 09:15:27 -08:00
Robbie Hanson
bdf8bcc1cb Merge branch 'sans-transform' into 2.4 2014-02-24 19:29:07 -08:00
Robbie Hanson
db18d6a55e Adding transaction parameter to YapDatabaseViewMappings group & sort block. Issue #41 2014-02-24 19:28:39 -08:00
Robbie Hanson
b0e92fb26d Using NSArray declaration instead of NSMutableArray from within code-blocks that aren't designed to make changes to the array. 2014-02-24 18:30:05 -08:00
Robbie Hanson
07a24ef74f Adding ability to change groupingBlock / sortingBlock of a view on-the-fly. 2014-02-20 18:26:55 -08:00
Robbie Hanson
1f233c06c0 Bug fix: Changing the filterBlock of a YapDatabaseFilteredView wasn't properly notifying extensions dependent upon it. 2014-02-18 18:54:09 -08:00
Robbie Hanson
14670401cd Bug fix: YapDatabaseFilteredView wasn't properly storing the versionTag within the init method. 2014-02-18 18:52:03 -08:00
Robbie Hanson
37af705719 Bug fix: replacePrimitiveData wasn't acting like the other methods concerning nil parameters 2014-02-17 22:39:20 -08:00
Robbie Hanson
6ccb872d85 Performance improvement for extensions (speedup for fetching info from rowid) 2014-02-17 22:38:48 -08:00
Robbie Hanson
5de9f5bf8a Adding enumerateKeysAndObjects method to YapCache 2014-02-17 22:29:22 -08:00
Robbie Hanson
bc3b8e90e4 Merge branch into 2.4
Resolved Conflicts:
	Testing/UnitTesting/TestYapDatabaseFilteredView.m
	YapDatabase/YapDatabase.m
2014-02-17 10:08:00 -08:00
Jon Nolen
dd8ae971e3 fixing deleting rows check, to make sure we are getting rows that may have been moved. 2014-02-12 15:23:31 -05:00
Jon Nolen
b057c78cf6 fixing autoconsolidation issues, updating groupname validation for modifiers 2014-02-12 14:52:14 -05:00
Jon Nolen
de5b8c2864 writing unit tests, handling dependencies, isReversed and rangeOptions differently. 2014-02-12 11:49:58 -05:00
Robbie Hanson
6781ec626e Moving block type definitions to their own header file. 2014-02-11 19:58:33 -08:00
Robbie Hanson
acbc639a16 Minor performance improvement for YapDatabaseView populate method. 2014-02-11 19:38:54 -08:00
Robbie Hanson
7d9d69beb3 Adding some missing trace log statements. 2014-02-11 19:37:55 -08:00
Robbie Hanson
fa5dac87c5 Bug fix: Updating the filterBlock post-init didn't persist the new versionTag. 2014-02-11 19:17:15 -08:00
Robbie Hanson
e3fc1903e6 Moving block type definitions to their own header file. 2014-02-11 19:12:43 -08:00
Jon Nolen
3fde99e157 updating tests for dynamic group addition to mapping for happiest path... pending tests for making sure ranges, reverse, dependencies, and consolidations remain intact. 2014-02-11 16:09:06 -05:00
Jon Nolen
880019754e renaming more tests to describe test 2014-02-11 15:26:34 -05:00
Jon Nolen
3cfc97eeb8 reorganizing tests for view mappings. 2014-02-11 15:09:58 -05:00
Jon Nolen
e033891706 refactoring to smaller methods, conditionally updating groups only if needed. started renaming/reorganizing tests to make their intent more clear. 2014-02-11 14:41:17 -05:00
Jon Nolen
f701d8640f adding initWithFilter:sort:view initializer for dynamic groups 2014-02-10 22:53:25 -05:00
Robbie Hanson
95a20a5a7c Bug fixes: Unregistering an extension was not removing it from extensionsOrder array. Automatic unregistration of dependent extensions was using multiple transactions. 2014-02-10 11:31:54 -08:00
Robbie Hanson
0df1ff4d4d Changing YapDatabaseView from using an "int version" to a "NSString *versionTag". This allows for increased flexibility, and makes it easier to include information such as the current localization or configuration info.
Also converting YapDatabaseFilteredView to use the same terminology.
2014-02-09 16:00:12 -08:00
Robbie Hanson
47f9cd5af3 Optimizing view registration process 2014-02-07 18:51:39 -08:00
Robbie Hanson
1522ed18ce Bug fix for non-persistent filtered views. Fixes case where re-registering a non-persistent filtered view immediately upon app launch may result in an empty view. 2014-02-07 16:41:53 -08:00
Robbie Hanson
91cfb0efd8 Updating podspec version to match branch 2014-02-07 16:18:40 -08:00
Robbie Hanson
92e29a01bb Bug fix: The relationship extension needs to run its preCommit routine before any other extension. Implementing this with a new method hook for extensions. 2014-02-07 16:18:11 -08:00
Robbie Hanson
ab1806fb73 Updating podspec. Min deployment target is iOS 6.0. Fixes issue #38 2014-02-07 15:22:55 -08:00
Robbie Hanson
94fcf2addb Bug fix: was not properly unregistering extension dependencies beyond 1 level deep. 2014-02-07 15:22:41 -08:00
Robbie Hanson
4bb0e35cc1 Adding unit tests for automatic unregistration of extension dependencies 2014-02-07 15:22:25 -08:00
Robbie Hanson
c3e30da09a Updating podspec. Min deployment target is iOS 6.0. Fixes issue #38 2014-02-07 15:20:10 -08:00
Robbie Hanson
03d1d2f834 Bug fix: was not properly unregistering extension dependencies beyond 1 level deep. 2014-02-07 15:15:44 -08:00
Robbie Hanson
56200bce7f Adding unit tests for automatic unregistration of extension dependencies 2014-02-07 15:14:20 -08:00
Robbie Hanson
7a6c6c0ca0 Merge branch 'master' into 2.4
Resolved Conflicts:
	YapDatabase/YapDatabaseConnection.m
2014-02-07 14:05:04 -08:00
Robbie Hanson
e1eabf014c Minor documentation improvements 2014-02-07 13:59:18 -08:00
Robbie Hanson
7b696b8fd9 Skipping an unnecessary array copy. 2014-02-07 13:58:55 -08:00
Robbie Hanson
cee8fba03d Adding several more convenience methods to simplify fetching objects with a view + mappings. 2014-02-06 17:00:35 -08:00
Robbie Hanson
c626547f11 Fixing podspec 2014-02-05 17:49:17 -08:00
Robbie Hanson
632d4ce6c2 Working on YapDatabaseRelationship extension. Feature complete but needs more unit testing. 2014-02-04 19:38:01 -08:00
Robbie Hanson
defbc653b7 Clarifying benchmark text 2014-02-04 19:34:44 -08:00
Robbie Hanson
44154b9853 Adding podspec 2014-02-03 12:33:27 -08:00
Robbie Hanson
83661d883a Work in progress - adding the ability to create a relationship between an object in the database, and a file on disk. If the object is deleted, the extension can automatically delete the associated file. 2014-01-28 19:07:13 -08:00
Robbie Hanson
dde6f12b89 Standardizing location of extension class version declaration 2014-01-28 16:56:54 -08:00
Robbie Hanson
260a069ae2 Adding sanity check to secondary index registration. Will spit out a warning message if the setup has changed, but the version number didn’t. Only runs for debug compiles. Issue #29 2014-01-28 12:25:55 -08:00
Robbie Hanson
ac1db476cb Adding additional utility method to get column names and affinity for a given table 2014-01-28 12:22:56 -08:00
Robbie Hanson
e37028619c Bug fix for internal utility method 2014-01-28 12:22:14 -08:00
Robbie Hanson
ec8bec5c13 Minor changes to a few extensions to simplify the code 2014-01-28 12:21:39 -08:00
Robbie Hanson
2dcf6e1870 Adding init method with version parameter to SecondaryIndex extension. Issue #29 2014-01-27 17:55:33 -08:00
Robbie Hanson
28a8148ab2 Merge branch 'master' of https://github.com/yaptv/YapDatabase 2014-01-24 18:03:17 -08:00
Robbie Hanson
85da904bb1 Bug fix for non-persistent views. Fixes case where re-registering a non-persistent view immediately upon app launch may result in an empty view. 2014-01-24 18:03:05 -08:00
Robbie Hanson
cc1e9e29e6 Minor optimization - adding early bailout if given key is nil 2014-01-24 18:02:52 -08:00
Robbie Hanson
6dd3e42b39 Bug fix for non-persistent views. Fixes case where re-registering a non-persistent view immediately upon app launch may result in an empty view. 2014-01-24 18:01:59 -08:00
Robbie Hanson
4b296c0fb1 Minor optimization - adding early bailout if given key is nil 2014-01-22 10:29:09 -08:00
Robbie Hanson
07dbca9453 Adding a few convenience methods for YapDatabaseRelationship extension 2014-01-21 11:05:53 -08:00
Robbie Hanson
6f2eb29968 Update README.md 2014-01-21 10:15:32 -08:00
Robbie Hanson
a4af99b852 Fixing import - shouldn’t require double import to use the protocol 2014-01-10 09:18:07 -08:00
Robbie Hanson
71e32647a0 Working on YapDatabaseRelationship extension. Adding methods to manually manage graph edges. This is in addition to the YapDatabaseRelationshipNode protocol. 2014-01-09 20:18:23 -08:00
Robbie Hanson
2c25762386 Bug fix for issue #27 - groupingBlock & sortingBlock were not being set properly in all scenarios 2014-01-07 10:58:24 -08:00
Robbie Hanson
d3440d5675 Bug fix for method nearestIndexPathForRow when using consolidated grouping 2014-01-07 10:58:13 -08:00
Robbie Hanson
819f1d8fa2 Bug fix for issue #27 - groupingBlock & sortingBlock were not being set properly in all scenarios 2014-01-07 10:46:22 -08:00
Robbie Hanson
d5bb7d2eee Bug fix for method nearestIndexPathForRow when using consolidated grouping 2014-01-06 17:10:57 -08:00
Robbie Hanson
469bd4e230 Changing priority of nodeDeleteRule flags 2014-01-06 16:13:04 -08:00
Robbie Hanson
79b92a062e Update README.md 2014-01-06 13:45:46 -08:00
Robbie Hanson
68a1cfb812 Performance optimization: Changing extension protocol to pass YapCollectionKey objects, which means extensions don’t have to create their own version. 2014-01-03 15:43:05 -08:00
Robbie Hanson
61479b3d0f Moving some methods around. Improving documentation. 2014-01-03 14:47:53 -08:00
Robbie Hanson
3c7c23a737 Minor documentation updates 2014-01-02 21:41:28 -08:00
Robbie Hanson
1756fcbf81 A few bug fixes for YapDatabaseRelationship extension 2014-01-02 21:38:58 -08:00
Robbie Hanson
ac559665cd Adding unit tests for YapDatabaseRelationship extension 2014-01-02 21:17:58 -08:00
Robbie Hanson
273f6cf622 Updating unit test code to reflect updated API 2014-01-02 16:32:53 -08:00
Robbie Hanson
97aad31bc4 Work in Progress 2014-01-02 16:26:52 -08:00
Robbie Hanson
b8c6d11ac5 Small bug fix for YapDatabaseFilteredView 2014-01-02 16:26:14 -08:00
Robbie Hanson
05c8fea8ad Adding ability to replace the object, without modifying the existing metadata. 2014-01-02 16:25:33 -08:00
Robbie Hanson
38c8f4ae9a Adding private declaration of protocol implementation for proper compiler warnings 2014-01-02 15:53:27 -08:00
Robbie Hanson
da5a298544 Adding method to fetch metadata using rowid. Also adding optimized methods to fetch using a combination of YapCollectionKey + rowid 2014-01-02 15:51:40 -08:00
Robbie Hanson
4bd204f3d7 Adding internal method to remove a row using a rowid 2014-01-02 11:01:26 -08:00
Robbie Hanson
52d0f053ef Renaming internal method 2014-01-02 10:59:43 -08:00
Robbie Hanson
e500704a23 Changing all ‘NSStringFromSelector(_cmd)’ to equivalent pre-defined macro ‘THIS_METHOD’ 2014-01-02 10:58:49 -08:00
Robbie Hanson
a6bb248319 Adding safety net for situation where assertions are disabled. 2014-01-02 10:54:34 -08:00
Robbie Hanson
e99a3f1778 Bug fix: Forgot to finalize some sqlite statements. Might have resulted in the following error message: “Error in sqlite_close: 5 unable to close due to unfinalised statements” 2013-12-19 12:52:24 -06:00
Robbie Hanson
4a6e4a262e Work in Progress 2013-12-19 12:51:38 -06:00
Robbie Hanson
e085a1ca0e Bug fix: Forgot to finalize some sqlite statements. Might have resulted in the following error message: “Error in sqlite_close: 5 unable to close due to unfinalised statements” 2013-12-19 12:50:28 -06:00
Robbie Hanson
063142d2cf Update README.md 2013-12-15 19:36:03 -08:00
Robbie Hanson
84b27ca2fb Update README.md 2013-12-15 19:35:21 -08:00
Robbie Hanson
14fe547024 Merge branch '2.3' 2013-12-15 19:25:18 -08:00
Robbie Hanson
c3f532075e Merge pull request #25 from wisenomad/master
Fix 'No previous prototype for function' compiler warning
2013-12-15 19:23:40 -08:00
Robbie Hanson
a6b3c5f604 Work in Progress 2013-12-15 19:13:51 -08:00
Robbie Hanson
3097be916d Documentation improvements, and removing unneeded casts and asserts. 2013-12-15 19:13:21 -08:00
Robbie Hanson
edc90a733b Fixing NSLog statements which should be YDBLog statements. 2013-12-15 19:12:27 -08:00
wisenomad
df7952139e Fix 'No previous prototype for function' compiler warning
for YDBExtractFileNameWithoutExtension() function in
YapDatabaseLogging.m
2013-12-15 23:47:31 +02:00
Robbie Hanson
ac473133b5 In YapDatabaseViewMappings, adding the ability to consolidate multiple groups into a single section. This can be done automatically using a threshold based upon the total number of items in the tableView. 2013-12-07 22:42:12 -08:00
Robbie Hanson
fd084aa2a0 Bug fix for potential crash due to assertion failure 2013-12-06 11:14:37 -08:00
Robbie Hanson
870cf9f763 Bug fix for infinite loop problem when auto unregistering extensions due to dependencies 2013-12-06 11:14:13 -08:00
Robbie Hanson
822b798e7e Implementing extension class renaming support to smooth transition from YapCollectionsDatabase to YapDatabase 2013-12-05 13:31:30 -08:00
Robbie Hanson
3cf3804c11 Bug fix : extension architecture wasn’t dropping values from yap2 table in certain circumstances 2013-12-05 13:29:11 -08:00
Robbie Hanson
75cfbd0e32 A few small bug fixes, and some extra related unit tests 2013-12-04 23:14:41 -08:00
Robbie Hanson
ead4707d12 Restoring some lost unit tests 2013-12-02 11:33:20 -08:00
Robbie Hanson
278bfcef6c Fixing desktop build 2013-12-02 11:22:09 -08:00
Robbie Hanson
a15f3d413c Reorganizing file layout 2013-11-30 23:18:30 -08:00
Robbie Hanson
8c6b63972f Renaming YapAbstractDatabaseExtension to YapDatabaseExtension 2013-11-30 22:44:56 -08:00
Robbie Hanson
9549cbe0a1 Merging YapAbstractDatabase & YapDatabase (now that there is only a single subclass) 2013-11-30 22:07:26 -08:00
Robbie Hanson
8fdea2dab0 Renaming all YapCollectionsDatabaseX classes to YapDatabaseX 2013-11-29 22:04:32 -08:00
Robbie Hanson
4572a3e593 MAJOR CHANGE : Dropping key/value datastore. The collection/key/value datastore will remain and become the new standard. 2013-11-29 20:19:29 -08:00
Robbie Hanson
8b18e35b62 Adding ability to change filteringBlock on-the-fly, and get a corresponding diff to smoothly animate changes 2013-11-28 13:58:44 -08:00
Robbie Hanson
6bec3414fa Adding ability to change filteringBlock on-the-fly, and get a corresponding diff to smoothly animate changes 2013-11-28 12:04:50 -08:00
Robbie Hanson
0132c6a78b Switching from a ‘int version’ to a ‘string tag’ system for versioning of filteredViews 2013-11-27 17:44:01 -08:00
Robbie Hanson
8804956335 Fixing improper name (internal change) 2013-11-27 17:22:16 -08:00
Robbie Hanson
4fa6871ae5 Moving dependency checking into extensions to allow for more fine grained checking (such as class type) 2013-11-27 16:58:08 -08:00
Robbie Hanson
3f3d3c98e3 Adding a method to assist in maintaining a selection for UITableView or UICollectionView 2013-11-25 19:35:58 -08:00
Robbie Hanson
42aa6109ce Adding some convenience methods for views when using mappings 2013-11-25 19:35:16 -08:00
Robbie Hanson
9a1776a1bc Merge branch 'master' into 2.3 2013-11-21 20:02:19 -08:00
Robbie Hanson
2848f711dd Working on YapDatabaseFilteredView 2013-11-21 20:01:29 -08:00
Robbie Hanson
3df2c51de4 Bug fixes for new extension dependencies code 2013-11-20 17:39:19 -08:00
Robbie Hanson
1d5bc05c36 Minor performance improvements for views 2013-11-20 17:33:21 -08:00
Robbie Hanson
8019de5046 Working towards allowing extensions to have dependencies on other extensions 2013-11-13 17:04:57 -08:00
Robbie Hanson
795d3cffac Fixing typo in documentation 2013-11-13 13:20:23 -08:00
Robbie Hanson
833289c54f Update README.md 2013-11-07 16:53:35 -08:00
Robbie Hanson
cbc03572a8 Adding methods to fetch the count of matching rows for a given query. 2013-11-07 16:23:17 -08:00
Robbie Hanson
78f3cf0412 Bug fix for YapDatabaseViewMappings 2013-11-04 09:58:49 -08:00
Robbie Hanson
a680b514a6 Adding another helper method to YapDatabaseViewMappings 2013-11-04 09:57:44 -08:00
Robbie Hanson
ef3616910f Adding another method for un-sectioned data in mappings 2013-10-31 16:42:17 -07:00
Robbie Hanson
8a68babb88 Re-organizing YapDatabaseViewMappings header to make it more understandable. Fixing bugs in getter methods in mappings due to isReversed option. Improving unit tests. 2013-10-31 16:28:39 -07:00
Robbie Hanson
b8a87306ed Bug fix for new enumerateCollectionsForKey:usingBlock: method. 2013-10-31 13:59:10 -07:00
Robbie Hanson
1adf72daef Adding enumerate method for collections, and for a particular key 2013-10-30 17:51:14 -07:00
Robbie Hanson
2d13f94ca5 Removing dead code 2013-10-28 10:28:13 -07:00
Robbie Hanson
f874d20074 Merge branch 'master' into 2.2 2013-10-28 10:19:21 -07:00
Robbie Hanson
ad3bed410e Updating comments to point to new wiki article 2013-10-25 18:56:01 -07:00
Robbie Hanson
507f062f6b Merge branch '2.1' into 'master' 2013-10-25 16:49:58 -07:00
Robbie Hanson
d32c0118fc Adding YapDatabasePolicyCopy option 2013-10-25 16:40:44 -07:00
Robbie Hanson
7df48a167d Changing the default object & metadata policy. They are now YapDatabasePolicyContainment. This is more in line with what most people expect, and errs on the side of safety. 2013-10-25 15:55:57 -07:00
Robbie Hanson
332678d4db Bug fix: YapDatabasePolicyContainment wasn't enforced during changeset processing. 2013-10-25 15:48:51 -07:00
Robbie Hanson
2c6cbd29ed Minor improvements to YapDatabaseViewMappings 2013-10-22 13:31:25 -07:00
Robbie Hanson
33b8a35ef9 Improving comments for exception 2013-10-22 13:30:55 -07:00
Robbie Hanson
08999c6fd5 Consolidating test files 2013-10-22 10:54:13 -07:00
Robbie Hanson
d2885ce6f4 Adding YapCollectionsDatabaseSecondaryIndex 2013-10-22 10:43:48 -07:00
Robbie Hanson
d0d3af6e67 Improving documentation 2013-10-22 10:43:27 -07:00
Robbie Hanson
590fb7935f Adding YapDatabaseSecondaryIndex extension 2013-10-21 17:06:59 -07:00
Robbie Hanson
b8675e074f Code cleanup. Removing unneeded method from YapAbstractDatabaseExtensionTransaction. 2013-10-21 17:06:23 -07:00
Robbie Hanson
36043c9b7a Adding the ability to specify which collection(s) to enumerate when populating the view. 2013-10-15 11:30:10 -07:00
Robbie Hanson
e57add8f3b Updated README 2013-10-14 18:53:03 -07:00
Robbie Hanson
4d23173223 Merge branch 2.1 into 2.2 2013-10-14 18:40:47 -07:00
Robbie Hanson
823d2670cd Updating unit tests to test both persistent and non-persistent views. 2013-10-14 18:35:36 -07:00
Robbie Hanson
624fe2c88f Adding the ability to set default configuration values for all new connections 2013-10-14 17:09:05 -07:00
Robbie Hanson
5245a09e25 Adding sanity exception during YapDatabaseViewMappings initialization 2013-10-14 12:55:43 -07:00
Robbie Hanson
74619eb732 Bug fix for migration between persistent & non-persistent views. 2013-10-12 21:43:57 -07:00
Robbie Hanson
9aee378c93 Adding option for non-persistent (in-memory only) view (YapCollectionsDatabaseView) 2013-10-11 18:18:23 -07:00
Robbie Hanson
a1c3c6a36a Adding option for non-persistent (in-memory only) view. 2013-10-11 16:44:32 -07:00
Robbie Hanson
635283991a Adding benchmarks for YapCollectionsDatabase 2013-10-09 12:06:39 -07:00
Robbie Hanson
395e197ba6 Minor code cleanup and minor optimizations 2013-10-09 11:33:14 -07:00
Robbie Hanson
4977d01e87 Updating documentation 2013-10-08 18:18:23 -07:00
Robbie Hanson
a6fb23430c Adding object containment policy option. Still needs documentation. 2013-10-08 00:31:08 -07:00
Robbie Hanson
c865a40695 Bug fix for YapCollectionsDatabase: Was not properly flushing changeset in removeAllObjectsInCollection. Under the right conditions, this could lead to sibling connections having the wrong values in their cache. 2013-10-08 00:12:56 -07:00
Robbie Hanson
f4d6d71af2 Update README.md 2013-10-07 22:44:56 -07:00
Robbie Hanson
dddf05a015 Bug fix for YapCollectionsDatabase init method that takes a single sanitizer. Also a small optimization in the init methods to only create the default serializer/deserializer when it will be needed. 2013-10-07 17:44:08 -07:00
Robbie Hanson
2864e20363 Adding a connection pool to reduce the overhead of creating and destroying connections 2013-10-01 23:38:51 -07:00
Robbie Hanson
a782e46231 Minor documentation improvements 2013-10-01 23:20:37 -07:00
Robbie Hanson
5f9c84f017 Bug fix: Ensure private cached is used, even if user enables "global" shared cache 2013-09-29 16:47:50 -07:00
Robbie Hanson
1c9c6b4014 Bug fix: Ensure private cached is used, even if user enables "global" shared cache 2013-09-29 16:46:58 -07:00
Robbie Hanson
fa73aa31f7 Bug fix: Ensure private cached is used, even if user enables "global" shared cache 2013-09-29 16:37:08 -07:00
Robbie Hanson
7aa3dd914e Fixing potential deadlock situation 2013-09-29 16:37:00 -07:00
Robbie Hanson
c3e7ffcbff Bug fix: Ensure private cached is used, even if user enables "global" shared cache 2013-09-29 16:34:41 -07:00
Robbie Hanson
d189e4c83d Fixing potential deadlock situation 2013-09-29 16:28:23 -07:00
Robbie Hanson
abd1300fef Fixing logging support for non-lumberjack techniques (NSLog & Disabled) 2013-09-25 14:35:40 -07:00
Robbie Hanson
f74984be80 Bug fix for touch methods in YapCollectionsDatabaseTransaction 2013-09-24 18:26:19 -07:00
Robbie Hanson
6ecf432d03 Update README.md 2013-09-24 08:52:05 -07:00
Robbie Hanson
0eebec11af Adding the ability to touch items in the database. And internal changes to make it more explicit if an extension has made independent changes to the database file. 2013-09-24 08:51:31 -07:00
Robbie Hanson
59d631bed1 Bug fix: setPrimitive methods could result in YapNull values ending up in the cache(s) of sibling connections 2013-09-23 16:49:39 -07:00
Robbie Hanson
006239f509 Update README.md 2013-09-23 15:24:35 -07:00
Robbie Hanson
52ffb89f4e Bug fix: read-write transactions that generated external change-sets, but not internal change-sets were being ignored. 2013-09-20 15:54:24 -07:00
Robbie Hanson
3e470c7990 Improving documentation for creating extensions 2013-09-20 15:42:57 -07:00
Robbie Hanson
865d9bce06 Adding a method to find ranges within the View using a binary search algorithm. 2013-09-19 18:25:25 -07:00
Robbie Hanson
a7c773a74d Adding iOS 5 compatibility 2013-09-19 11:16:51 -07:00
Robbie Hanson
a45932895f Prepping to test iOS 5 issues 2013-09-19 11:15:57 -07:00
Robbie Hanson
c113e5ef91 Fixing Xcode 5 issues 2013-09-19 11:14:32 -07:00
Robbie Hanson
fb9d244677 Merging latest fixes from CocoaLumberjack project 2013-09-19 09:59:31 -07:00
Robbie Hanson
1d1e1d1047 Fixing compiler warnings 2013-09-17 16:16:53 -07:00
Robbie Hanson
509dd41d02 Adding FullTextSearch extension to Xcode desktop project 2013-09-17 16:16:40 -07:00
Robbie Hanson
02e1c2a54a Fixing analyzer warnings 2013-09-17 16:16:13 -07:00
Robbie Hanson
078801fbcb Adding YapCollectionsDatabaseFullTextSearch extension 2013-09-17 15:44:10 -07:00
Robbie Hanson
4a61e401a5 Improving unit tests 2013-09-17 15:43:38 -07:00
Robbie Hanson
667e0fd968 Finishing snippet support in YapDatabaseFullTextSearch 2013-09-17 15:42:50 -07:00
Robbie Hanson
ca66422685 Working on Full Text Search extension 2013-09-16 20:13:24 -07:00
Robbie Hanson
36004caa62 Adding calls to super in Unit Tests. 2013-09-16 20:12:49 -07:00
Robbie Hanson
dec71de856 Cleaning up AppDelegate 2013-09-16 20:12:05 -07:00
Robbie Hanson
a17b4b85aa Minor code cleanup. Adding some extra comments, and moving some methods around. 2013-09-16 18:43:27 -07:00
Robbie Hanson
b5be6b7199 Bug fix for BigEndian conversion 2013-09-13 15:35:20 -07:00
Robbie Hanson
06efe1dab8 Renaming a folder: View -> Views 2013-09-13 15:34:49 -07:00
Robbie Hanson
599d45868d Adding sanitizers to help safeguard for thread safety 2013-09-13 15:03:54 -07:00
Robbie Hanson
acce215cf0 The serializer & deserializer now take 'key' and 'collection, key' parameters. This makes it easier to customize the serialization & deserialization routines based on the key or collection. 2013-09-12 19:36:33 -07:00
Robbie Hanson
32a952b0f3 Adding an optional name property to connections in order to assist with debugging 2013-09-12 16:36:20 -07:00
Robbie Hanson
bd2f20ad15 Changing a few hard coded strings to internal constants 2013-09-12 15:17:27 -07:00
Robbie Hanson
0d4cc960d1 Optimizing creation of extensions changeset dictionary using sharedKeySet 2013-09-10 15:31:41 -07:00
Robbie Hanson
3f29c32202 Simplifying the layout of columns in the page table to be more transparent. This should also decrease the amount of data being written when modifying pages. 2013-09-10 15:15:42 -07:00
Robbie Hanson
1b4bd08c71 Minor code formatting changes. 2013-09-10 08:59:17 -07:00
Robbie Hanson
4be594515a Adding an exception (which can be disabled) for implicitly ending a long-lived read transaction. 2013-09-09 16:41:47 -07:00
Robbie Hanson
fd38438c49 Adding an exception (which can be disabled) for implicitly ending a long-lived read transaction. 2013-09-09 16:40:12 -07:00
Robbie Hanson
2fe828446e Minor optimization: Skip copy bytes step if not requested 2013-09-09 16:03:44 -07:00
Robbie Hanson
cc327ec057 Minor optimization: Skip deserialization step if not requested 2013-09-09 15:59:20 -07:00
Robbie Hanson
45f5df8340 Adding a few more methods for dealing with primitive data 2013-09-09 15:47:31 -07:00
Robbie Hanson
e8e9c645a0 Forgot to increment version number. Should automatically upgrade now. 2013-09-06 12:39:51 -07:00
Robbie Hanson
a01785a2ff Fixing parameter in header type 2013-09-06 12:09:49 -07:00
Robbie Hanson
b7f3fa49b0 Bug fix for threading issue that could create a dangling pointer in certain situations. Fixes issue #14 2013-09-06 11:37:41 -07:00
Robbie Hanson
76e37239aa Very minor optimization 2013-09-06 11:36:04 -07:00
Robbie Hanson
32eab13bce Some generic debugging code (in AppDelegate) 2013-09-06 00:24:35 -07:00
Robbie Hanson
4b9af85774 Changing 'database' to 'database2' and adding automatic migration code for seamless upgrades 2013-09-06 00:24:12 -07:00
Robbie Hanson
287ff886cd Adding some utility methods to YapAbstractDatabase 2013-09-06 00:22:24 -07:00
Robbie Hanson
c52b843a16 Some generic debugging code (in AppDelegate) 2013-09-06 00:15:07 -07:00
Robbie Hanson
c035fe73aa Standardizing storage format (endian) of int64_t in view page 2013-09-05 17:21:32 -07:00
Robbie Hanson
6da75c327f Fixing spelling typos in method names 2013-09-05 16:08:17 -07:00
Robbie Hanson
04c2c99ac5 Critical bug fix: proper copies were not being made of the page prior to broadcasting the changeset to other connections. Could result in a timing issue bug. 2013-09-05 16:04:02 -07:00
Robbie Hanson
d4fcb388c8 Adding code to ensure pages don't grow too big in memory during a transaction 2013-09-05 15:59:09 -07:00
Robbie Hanson
1338a5ccb5 Improving unit test coverage for YapCollectionsDatabaseView 2013-09-05 15:57:08 -07:00
Robbie Hanson
361a1acc3f Switching from generic NSMutableArray to dedicated page class to store int64_t rowId's. This should improve performance, and reduce the size of pages on disk. 2013-09-05 15:53:40 -07:00
Robbie Hanson
a78de8a58b Merging latest fixes from CocoaLumberjack project 2013-09-05 15:07:24 -07:00
Robbie Hanson
72485d8b7f Minor optimization (no need to copy NSNull) 2013-09-05 12:56:47 -07:00
Robbie Hanson
4c145b84f2 Critical bug fix: proper copies were not being made of the page prior to broadcasting the changeset to other connections. Could result in a timing issue bug. 2013-09-05 12:52:48 -07:00
Robbie Hanson
00da4ccb3e Adding generic debugging template to AppDelegate 2013-09-05 12:33:17 -07:00
Robbie Hanson
a067888f9a Critical bug fix: proper copies were not being made of the page prior to broadcasting the changeset to other connections. Could result in a timing issue bug. 2013-09-05 12:31:26 -07:00
Robbie Hanson
b4d4df2e87 Adding code to ensure pages don't grow too big in memory during a transaction 2013-09-05 12:09:07 -07:00
Robbie Hanson
54d25538a1 Improving unit test coverage for YapDatabaseView 2013-09-05 12:08:32 -07:00
Robbie Hanson
bd3cf894d7 Switching from generic NSMutableArray to dedicated page class to store int64_t rowId's. This should improve performance, and reduce the size of pages on disk. 2013-09-05 12:08:09 -07:00
Robbie Hanson
19f8dce685 YapCollectionsDatabaseView now stores rowId's(int64_t) instead of collection/key tuples. This means it will take up less space. Plus it can use "integer primary key" lookups for improved performance in certain places. 2013-09-04 15:39:47 -07:00
Robbie Hanson
9cc26ab5af Bug fixes for new methods in YapCollectionsDatabaseTransaction 2013-09-04 15:37:58 -07:00
Robbie Hanson
3ace3c3c2b Bug fix (duplicate declaration of lastKey variable) 2013-09-04 14:56:06 -07:00
Robbie Hanson
116db5d88e A bit of code cleanup 2013-09-04 14:55:37 -07:00
Robbie Hanson
a21c1ce459 Dropping getCountForKeyStatement. It should be as fast to use the existing getRowid:forKey: method. 2013-09-03 15:05:30 -07:00
Robbie Hanson
a9f3804329 Dropping getCountForKeyStatement. It should be as fast to use the existing getRowid:forKey: method. 2013-09-03 14:28:40 -07:00
Robbie Hanson
1c7d23edc6 Update README.md 2013-09-03 08:22:43 -07:00
Robbie Hanson
3be74679b5 Completing transition of YapCollectionsDatabase to pass rowId's to extensions 2013-09-02 17:57:37 -07:00
Robbie Hanson
e5b87d812a Minor performance improvement: switching to a do/while system to skip multiple needsMarkSqlLevelSharedReadLock checks. 2013-09-02 17:06:13 -07:00
Robbie Hanson
3877b331bc Minor performance improvement: switching to a do/while system to skip multiple needsMarkSqlLevelSharedReadLock checks. 2013-09-02 16:43:46 -07:00
Robbie Hanson
c9378b6137 Minor change to removeObjectsForKeys: the extensions are now invoked in-sync with the batch modifications. And the database isn't marked as mutated if nothing is deleted. 2013-09-02 16:40:30 -07:00
Robbie Hanson
f81bbdcb9f Minor change: Changing from alloc/initWithBytesNoCopy to simply dataWithBytesNoCopy 2013-09-02 16:11:29 -07:00
Robbie Hanson
08165044b1 WIP - Changing YapCollectionsDatabase to be able to pass rowId's to the extensions. The extensions can then use the raw rowId instead of the key. 2013-08-29 19:22:16 -07:00
Robbie Hanson
9320eb23b7 A few optimizations for primitive access method 2013-08-29 19:21:27 -07:00
Robbie Hanson
d40147b54e Adding additional primitive access methods. 2013-08-29 19:20:43 -07:00
Robbie Hanson
64b099b43a WIP - Changing YapCollectionsDatabase to be able to pass rowId's to the extensions. The extensions can then use the raw rowId instead of the key. 2013-08-29 09:22:53 -07:00
Robbie Hanson
6e1420a7ec Bug fix - rowId access methods weren't using the cache 2013-08-28 17:44:28 -07:00
Robbie Hanson
d740133cda YapDatabaseView now stores rowId's(int64_t) instead of keys(NSString). This means it will take up less space. Plus it can use "integer primary key" lookups for improved performance in certain places. 2013-08-28 15:45:26 -07:00
Robbie Hanson
fef2f05178 Changing architecture to be able to pass rowId's to the extensions. The extensions can then use the raw rowId instead of the key. 2013-08-27 15:26:51 -07:00
Robbie Hanson
b48e88b1b8 Removing unneeded import 2013-08-26 18:50:23 -07:00
Robbie Hanson
bb2989d42b Minor documentation fixes 2013-08-26 18:50:04 -07:00
Robbie Hanson
267c570922 Adding ability to fetch position of range within group 2013-08-23 18:14:30 -07:00
Robbie Hanson
5efbfe9479 Optimizing creation of changeset dictionaries using sharedKeySet's 2013-08-19 16:20:04 -07:00
Robbie Hanson
2957d7465a Adding a reverse option to mappings 2013-08-19 15:45:01 -07:00
Robbie Hanson
af9a3932f6 A bit of internal code cleanup 2013-08-19 15:36:43 -07:00
Robbie Hanson
36c34f1eae Critical bug fix for mappings 2013-08-16 17:52:44 -07:00
Robbie Hanson
4cd2130611 Optimizing creation of changeset dictionaries using sharedKeySet's 2013-08-16 15:44:44 -07:00
Robbie Hanson
ec3fa1f78e Improving unit tests for YapDatabaseViewMappings 2013-08-16 14:52:13 -07:00
Robbie Hanson
8ab71a751f Improving description strings for YapDatabaseViewRowChange objects 2013-08-16 14:51:56 -07:00
Robbie Hanson
5b72389dd6 Bug fixes for "cell drawing dependency" mappings 2013-08-16 14:51:26 -07:00
Robbie Hanson
6858f47b32 Improving unit tests for YapDatabaseViewMappings 2013-08-15 19:47:27 -04:00
Robbie Hanson
bbfeb971e8 Bug fix: max should always be greater than or equal to min 2013-08-15 19:43:50 -04:00
Robbie Hanson
8b93c1ad47 Bug fix for mappings pinned to the end with a range option 2013-08-15 19:43:17 -04:00
Robbie Hanson
76cfa323d3 Bug fix for changeset processing in flexible ranges 2013-08-15 19:42:28 -04:00
Robbie Hanson
aca32977c9 Improving unit tests for YapDatabaseViewMappings 2013-08-15 18:49:46 -04:00
Robbie Hanson
2613e6902c Bug fix for changeset processing in flexible ranges 2013-08-15 18:49:24 -04:00
Robbie Hanson
5be822eed2 Bug fix for documentation 2013-08-15 00:31:36 -04:00
Robbie Hanson
d5920f0cf1 Renaming modifiedColumns to changes. Adding change flag for a change due to a dependency. 2013-08-15 00:30:02 -04:00
Robbie Hanson
ed8dffc27b Improving unit tests for YapDatabaseViewMappings 2013-08-14 23:52:34 -04:00
Robbie Hanson
8a9d476ba9 Bug fix for flexible ranges 2013-08-14 23:52:17 -04:00
Robbie Hanson
8427864ae1 Improving unit tests for YapDatabaseViewMappings 2013-08-14 23:29:15 -04:00
Robbie Hanson
8cb6f9cda5 Adding "cell drawing dependency" options to YapDatabaseViewMappings. Other bug fixes for mappings. 2013-08-14 23:28:41 -04:00
Robbie Hanson
e3ae93ec4c Working on unit tests for mappings 2013-08-11 12:33:01 -07:00
Robbie Hanson
3621f4c504 Implementing todo items for flexible ranges 2013-08-11 12:32:43 -07:00
Robbie Hanson
5a80109f49 Adding several mappings methods to YapDatabaseViewMappings class to simplify cases when using range options. 2013-08-09 10:57:21 -07:00
Robbie Hanson
98e2b316e6 Documentation updates 2013-08-09 10:56:22 -07:00
Robbie Hanson
627f1c10c2 Bug fix for on-the-fly extension registration / unregistration / auto-unregistration. Fixes issue #11 2013-08-08 18:58:50 -07:00
Robbie Hanson
6dd197af77 Adding some general debugging code to AppDelegate. Handy to have around for odd job debugging. 2013-08-08 18:57:57 -07:00
Robbie Hanson
cebbbb426e Bug fix for view changeset processing 2013-08-06 14:42:28 -07:00
Robbie Hanson
39ab816dad Work In Progress - Working on adding range & limit support on a per-group basis (via mappings object) 2013-08-06 14:17:20 -07:00
Robbie Hanson
b2efe4dadb Dynamic sections are more complicated than static sections, and require extra code to deal with them. Therefore, they should be opt-in, not opt-out. 2013-08-01 11:55:48 -07:00
Robbie Hanson
96266b18c6 Bug fix for view changeset processing 2013-08-01 11:52:15 -07:00
Robbie Hanson
4d32b1c54a Work In Progress - Working on adding range & limit support on a per-group basis (via mappings object) 2013-08-01 10:56:35 -07:00
Robbie Hanson
c392ec369d Minor documentation fixes 2013-07-30 18:18:22 -07:00
Robbie Hanson
aee85e6767 Bug fix for view changeset processing (mutating immutable objects) 2013-07-30 18:17:10 -07:00
Robbie Hanson
382845fa39 Adding per-group configuration of allowsEmptySection 2013-07-29 19:36:47 -07:00
Robbie Hanson
ad0b116ae1 Adding checks & exceptions to ensure the mappings & notifications passed into the API are correct. 2013-07-26 18:43:53 -07:00
Robbie Hanson
a595a9e8c4 Adding snapshot to external notification. Adding associated constant for key in dictionary. 2013-07-26 17:31:12 -07:00
Robbie Hanson
616f11b915 Improving documentation in several places. 2013-07-26 17:03:19 -07:00
Robbie Hanson
00074c550f Adding public property to the transactions to allow access to the parent connection. This may be helpful to methods that take a transaction as a parameter. 2013-07-26 17:01:57 -07:00
Robbie Hanson
c09d909e52 Bug fix for nil mappings getting passed to the API 2013-07-25 14:43:33 -07:00
Robbie Hanson
5bff1b0fc2 Merge branch 'master' of https://github.com/yaptv/YapDatabase 2013-07-23 22:06:34 -07:00
Robbie Hanson
c17efb20f6 Removing some outdated documentation 2013-07-23 22:06:29 -07:00
Robbie Hanson
8243a9cfa3 Update README.md 2013-07-23 18:11:56 -07:00
Robbie Hanson
9677c4e533 Merge branch '2.0' into 'master' 2013-07-23 17:49:09 -07:00
Robbie Hanson
c5a6e6cacf Updating benchmarks. Making them accessible through UI. 2013-07-23 17:04:44 -07:00
Robbie Hanson
b946bb6261 Simplifying internal database registration code. 2013-07-23 16:04:43 -07:00
Robbie Hanson
5ed5e3f191 Fixing Xcode project for desktop 2013-07-23 11:25:31 -07:00
Robbie Hanson
b80858c1aa Views now support section changes. 2013-07-23 09:57:35 -07:00
Robbie Hanson
59b63444c9 Simplifying snapshot storage code. May be a tiny bit faster too. 2013-07-18 13:58:05 -07:00
Robbie Hanson
8fe39ef71b Bug fix for mutation-during-enumeration protection 2013-07-18 11:49:47 -07:00
Robbie Hanson
3884b60167 Improving unit tests for mutation-during-enumeration protection 2013-07-18 11:21:37 -07:00
Robbie Hanson
bd350ea114 Added unit test for dropping a view 2013-07-18 10:54:55 -07:00
Robbie Hanson
a18245813d Adding mutation-during-enumeration protection to YapCollectionsDatabaseView 2013-07-17 19:17:06 -07:00
Robbie Hanson
3a90d8d879 Adding mutation-during-enumeration protection to YapDatabaseView 2013-07-17 18:29:22 -07:00
Robbie Hanson
504fd01a16 Dropping Timestamp categories. They have been superseded by Views. 2013-07-17 16:51:47 -07:00
Robbie Hanson
90863d82e1 Changing table names for views. Cleaner name. 2013-07-17 15:29:42 -07:00
Robbie Hanson
ac9b59e4e0 Auto-drop sqlite tables for extensions that are no longer used. 2013-07-17 15:29:11 -07:00
Robbie Hanson
2434b545f7 Performance optimizations: adding direct access to serializer & deserializer 2013-07-17 12:03:11 -07:00
Robbie Hanson
2059a644e4 Using new properly typed connection ivars in views 2013-07-17 11:41:56 -07:00
Robbie Hanson
2686d50d8b Adding properly typed ivar to transactions, and removing a whole bunch of casting 2013-07-17 11:32:59 -07:00
Robbie Hanson
ac29bb42fe Renaming preCommitTransaction to preCommitReadWriteTransaction to make its use more understandable 2013-07-17 10:54:27 -07:00
Robbie Hanson
5cbf694eea Minor bug fix: forgot to reset the registeredExtensionsChanged flag 2013-07-16 19:30:09 -07:00
Robbie Hanson
59ab66e049 Dropping configurable pageSize stuff. I have a better idea. 2013-07-16 19:05:28 -07:00
Robbie Hanson
406f562ce5 Bug fix: extension registration should go through writeQueue so it occurs before readWrite operations. 2013-07-16 18:35:35 -07:00
Robbie Hanson
23a07e8d79 Adding simple versioning to views to allow for changing the blocks. 2013-07-16 15:38:59 -07:00
Robbie Hanson
de93eecdcb Auto-drop tables if registering an extension with the same name as a previous extension when class differs. 2013-07-15 17:50:08 -07:00
Robbie Hanson
b45e350245 Adding ext: shorthand for a connection 2013-07-15 12:31:58 -07:00
Robbie Hanson
39b1a8668a Adding simple YES/NO query to see if a view changed at all (given an array of notifications) 2013-07-15 12:21:31 -07:00
Robbie Hanson
b0b6f7ba2f Bug fix for extension registration process 2013-07-15 11:51:53 -07:00
Robbie Hanson
6708736adc Working on extension unregistration 2013-07-12 18:23:17 -07:00
Robbie Hanson
1fba34129e Fixing view population bug. Adding unit test for view population. 2013-07-12 12:32:38 -07:00
Robbie Hanson
fa63eaa6a5 Bug fix for extension registration process 2013-07-11 10:03:11 -07:00
Robbie Hanson
5a5aeafef9 Adding more unit tests for YapCollectionsDatabaseView 2013-07-10 23:38:45 -07:00
Robbie Hanson
c984150581 Bug fixes from unit testing 2013-07-10 23:35:10 -07:00
Robbie Hanson
a7349f1a5c Bug fixes for fetching keys in views 2013-07-10 23:00:07 -07:00
Robbie Hanson
2209254d52 Improving pageCache hit percentage in views 2013-07-10 22:56:51 -07:00
Robbie Hanson
1b33b69600 Bug fix for views: changeset processing was dropping more items from cache than needed 2013-07-10 22:55:26 -07:00
Robbie Hanson
a44e7fc931 Adding more unit tests for YapDatabaseView 2013-07-10 18:58:46 -07:00
Robbie Hanson
1092fce17a Bug fix for views 2013-07-10 18:58:09 -07:00
Robbie Hanson
090805b8c7 Renaming some ivars and simplifying code 2013-07-09 23:06:56 -07:00
Robbie Hanson
c07351b637 Auto-populate a view during registration 2013-07-09 22:50:48 -07:00
Robbie Hanson
ce884b219e Bug fix: stored class name should be the name of the top-level extension class, not the extension transaction class. 2013-07-09 22:09:04 -07:00
Robbie Hanson
36dcdabf14 Changing required method to be more simple and useful. 2013-07-09 22:08:06 -07:00
Robbie Hanson
c515244154 Fixing bug in splitOversizedPage method of views 2013-07-09 21:54:49 -07:00
Robbie Hanson
82ec7f9d59 Consolidating a few methods into one 2013-07-09 21:40:30 -07:00
Robbie Hanson
014856f687 Renaming blockType enum to use new "row" terminology. 2013-07-09 13:59:49 -07:00
Robbie Hanson
6c9fe867f7 Removing dead code 2013-07-09 12:11:09 -07:00
Robbie Hanson
883ffa5bcf Adding row enumeration to views 2013-07-09 12:07:03 -07:00
Robbie Hanson
e9dd90cebc Adding asynchronous extension registration methods 2013-07-09 11:33:53 -07:00
Robbie Hanson
02e146a494 Fixing potential memory leak (on older systems) 2013-07-09 11:33:35 -07:00
Robbie Hanson
0eaf135709 Improving the extension registration process. Working towards on-the-fly extension creation and auto-population. 2013-07-09 10:24:11 -07:00
Robbie Hanson
b33268b6cc Dropping really old upgrade path support (pre-public-release upgrade path) 2013-07-09 09:54:39 -07:00
Robbie Hanson
116f462b27 Moving the guts of the registerExtension method into an internal method in order to prepare for an async version. Starting to add extension related values to the yap2 table. 2013-07-05 10:16:07 -07:00
Robbie Hanson
c4a81c716d Upgrading internal yap database scheme to add an extension column. 2013-07-04 21:23:59 -07:00
Robbie Hanson
a16f88efe4 Implementing todo item, and fixing crasher that was possible due to extension registration not using notePendingChanges. 2013-07-04 20:26:21 -07:00
Robbie Hanson
ff3b90b019 Minor performance optimization for creating new connections. Also ensures the connection's prepare method is truly the first method invoked. 2013-07-04 17:58:40 -07:00
Robbie Hanson
98e79eac5b Documentation fixes 2013-07-04 17:46:04 -07:00
Robbie Hanson
333f4aa076 Code cleanup. Removing ivars from YapAbstractDatabaseExtension classes. This makes it more like a protocol, and removes a bunch of messing casting from the concrete extension classes. 2013-07-04 13:34:16 -07:00
Robbie Hanson
a0333fdb53 Adding "touch" options to a view for increased flexibility of external changeset 2013-07-03 17:53:13 -07:00
Robbie Hanson
01625ac2de Bug fix for views: modified columns flags weren't being merged during consolidation 2013-07-03 12:01:56 -07:00
Robbie Hanson
0ae05a59f3 Minor performance optimization 2013-07-02 18:36:55 -07:00
Robbie Hanson
fb9c8aa453 Silencing analyzer warnings 2013-07-02 18:11:51 -07:00
Robbie Hanson
aa2d85308e Minor performance optimization 2013-07-02 18:01:34 -07:00
Robbie Hanson
da36b6d703 Silencing analyzer warnings 2013-07-02 17:53:44 -07:00
Robbie Hanson
2edaf521fe Bug fix: Dirty items being removed from a view's cache were never re-added during a read-write transaction 2013-07-02 17:43:41 -07:00
Robbie Hanson
3ae7d422b9 Bug fix: Dirty items being removed from a view's cache were never re-added during a read-write transaction 2013-07-02 16:11:06 -07:00
Robbie Hanson
a17ca2c7c3 Bug fix for view pages when the corresponding page is empty. 2013-06-28 19:34:45 -07:00
Robbie Hanson
4256cedae7 Adding convenience methods for fetching the first & last objects in a view 2013-06-28 19:06:03 -07:00
Robbie Hanson
82ddf8fc9c Updating views with new "Row" terminology 2013-06-28 19:04:41 -07:00
Robbie Hanson
5ad8f24190 Documentation improvements 2013-06-28 19:02:24 -07:00
Robbie Hanson
68edc9e9f8 Extending flushMemoryWithLevel into extensions 2013-06-28 13:05:04 -07:00
Robbie Hanson
f493550132 Adding missing dealloc methods to YapDatabaseViewConnection and YapCollectionsDatabaseViewConnection 2013-06-28 13:04:29 -07:00
Robbie Hanson
84b2d9b0d2 Some minor documentation improvements 2013-06-28 13:03:28 -07:00
Robbie Hanson
43bd981eb5 Some file system restructuring 2013-06-28 12:27:41 -07:00
Robbie Hanson
d86ba172dd Fixing compiler error for Mac OS X 2013-06-28 12:25:07 -07:00
Robbie Hanson
95793e608a Renaming YapDatabaseViewOperation to YapDatabaseViewChange 2013-06-28 01:55:58 -07:00
Robbie Hanson
6e6b294039 Adding Update to changeset notifications for views 2013-06-28 01:03:04 -07:00
Robbie Hanson
bcffa18e7d Bug fix for YapCollectionsDatabaseConnection in new changeset method 2013-06-28 00:10:45 -07:00
Robbie Hanson
1969ba69f4 Post the YapDatabaseModifiedNotification to the main thread 2013-06-26 17:50:46 -07:00
Robbie Hanson
7fa8f0a169 Bug fix for longLivedReadTransaction's 2013-06-25 09:36:33 -07:00
Robbie Hanson
2e3bbfa69e Fixing bugs in view extensions 2013-06-24 19:41:34 -07:00
Robbie Hanson
016a4e8d58 Copying license from master branch 2013-06-24 11:28:02 -07:00
Robbie Hanson
e9a0a0c51e Adding enumerateRowsForKeys:: method to YapDatabase 2013-06-24 11:14:19 -07:00
Robbie Hanson
332bd09124 Bug fix for YapDatabase - YapNull may have been passed into the block parameter while enumerating metadata.. Should have been nil. 2013-06-21 19:33:02 -07:00
Robbie Hanson
78529ecccd Bug fix for YapDatabase - an object may be reported as existing in the database when it doesn't. 2013-06-21 19:31:42 -07:00
Robbie Hanson
bd4f42f05e A bit of code cleanup and increased protection if object deserializer returns nil 2013-06-21 19:00:05 -07:00
Robbie Hanson
e3931d7570 Bug fix for enumerateRowsForKeys:::. Code didn't take into account that objects may get evicted from the cache mid-enumeration. 2013-06-21 18:40:19 -07:00
Robbie Hanson
7f9346df0b Increased protection if object deserializer returns nil 2013-06-21 18:33:17 -07:00
Robbie Hanson
0261a17328 A bit of code cleanup 2013-06-21 18:32:25 -07:00
Robbie Hanson
7af185e0f0 Adding external changeset for views 2013-06-21 17:57:56 -07:00
Robbie Hanson
67a5d17980 Adding consolidation step to view operations log 2013-06-21 17:50:42 -07:00
Robbie Hanson
8aa286e70f Working on view changesets 2013-06-21 15:11:40 -07:00
Robbie Hanson
fd91439ef7 Adding preCommitTransaction hook, and fixing consolidation bug in views 2013-06-21 11:29:37 -07:00
Robbie Hanson
ee3ce242a9 Added safety mechanism if database is updated mid enumeration (YapCollectionsDatabase) 2013-06-19 13:08:55 -07:00
Robbie Hanson
8b88ef0009 Implementing todo item concerning setPrimitiveData and extensions 2013-06-19 12:22:08 -07:00
Robbie Hanson
c7a2d9c814 Adding return statements after throw for clarity. 2013-06-19 12:19:47 -07:00
Robbie Hanson
a3f1800c46 Bug fix: forgot to test to ensure block wasn't NULL in a few places. 2013-06-19 12:19:00 -07:00
Robbie Hanson
e2ab62fd1d Added safety mechanism if database is updated mid enumeration (YapDatabase) 2013-06-18 18:01:59 -07:00
Robbie Hanson
e9be32cd61 Adding fast enumeration to YapSet 2013-06-18 15:08:11 -07:00
Robbie Hanson
41f4337ee5 Minor bug fix in unit test 2013-06-18 15:07:06 -07:00
Robbie Hanson
04d11962c7 Adding changeset information to YapDatabaseModifiedNotification, and adding changeset query methods. 2013-06-14 16:11:24 -07:00
Robbie Hanson
9e87bc5523 Performance optimization for changeset processing. 2013-06-13 14:25:32 -07:00
Robbie Hanson
607594934d Stubbing view configuration methods. 2013-06-13 13:47:02 -07:00
Robbie Hanson
d4d71c03a1 Code cleanup (just moving some methods around) 2013-06-13 11:43:19 -07:00
Robbie Hanson
38626adf35 Bug fixes, and added unit tests for YapCollectionsDatabaseView 2013-06-12 17:30:56 -07:00
Robbie Hanson
c5812624b8 Adding separate read vs readwrite extension transaction objects 2013-06-10 17:04:36 -07:00
Robbie Hanson
8752ab7cfd Fixing bugs in YapCollectionsDatabaseView 2013-06-10 16:44:17 -07:00
Robbie Hanson
fa8d8715e2 Adding auto page expansion to YapDatabaseView 2013-06-10 16:21:03 -07:00
Robbie Hanson
fa4a5f8de0 Reducing number of times we create YapCollectionKey objects in YapCollectionsDatabaseViewTransaction 2013-06-10 11:08:22 -07:00
Robbie Hanson
909d8004d5 Dropping YapCollectionsDatabaseViewPage idea and switching to NSMutableArray 2013-06-09 21:34:13 -07:00
Robbie Hanson
871269f99b Bug fix for cache initialization 2013-06-09 21:33:01 -07:00
Robbie Hanson
4d237db968 Adding NSCoding support to YapCollectionKey 2013-06-09 21:31:15 -07:00
Robbie Hanson
52b72b6bcf Minor optimizations to changeset processing in YapCollectionsDatabase 2013-06-09 20:32:46 -07:00
Robbie Hanson
63c3822e2a Bug fixes for changeset processing in YapDatabaseViewConnection 2013-06-09 20:23:09 -07:00
Robbie Hanson
46fc76a977 Minor optimizations to changeset processing in YapDatabase 2013-06-09 20:22:35 -07:00
Robbie Hanson
0f3f7157b6 Improving mutable string protection in views 2013-06-09 14:00:02 -07:00
Robbie Hanson
ebb3a44789 Improving mutable string protection. 2013-06-09 13:27:06 -07:00
Robbie Hanson
5270153158 Adding YapDatabaseExtension hooks to YapCollectionsDatabase 2013-06-09 13:23:20 -07:00
Robbie Hanson
4c21e129a9 Improving and standardizing method names. 2013-06-09 11:53:36 -07:00
Robbie Hanson
3cfea9575a Improving and standardizing method names. 2013-06-09 01:23:45 -07:00
Robbie Hanson
efaee4b21b Improving mutable string protection. Improving and standardizing method names. 2013-06-09 00:23:45 -07:00
Robbie Hanson
dae42218cb Renaming YapCacheCollectionKey to simply YapCollectionKey, and making the class public. 2013-06-08 17:25:12 -07:00
Robbie Hanson
f4f83352cf Working on YapCollectionsDatabaseView (not ready yet) 2013-06-08 17:11:42 -07:00
Robbie Hanson
02454454fc Working on YapCollectionsDatabaseView (not ready yet) 2013-06-06 11:48:22 -07:00
Robbie Hanson
f4920cfb9c Bug fix for YapCollectionsDatabase - numHostParams was ignoring collection parameter. 2013-06-06 11:21:57 -07:00
Robbie Hanson
81f0c58a92 Fixing rare but potential deadlock case 2013-06-03 17:23:39 -07:00
Robbie Hanson
7e9e1a9a2c Properly terminate the longLivedReadTransaction on deallocation, if one forgets to call endLongLivedReadTransaction prior to deallocating the connection. 2013-06-01 19:54:10 -07:00
Robbie Hanson
3790e1e447 A bit of documentation 2013-06-01 19:52:38 -07:00
Robbie Hanson
a18add8571 Pending checkpoints shouldn't keep databases from being deallocated. 2013-05-31 17:52:39 -07:00
Robbie Hanson
71a8247c6d Dropping defunct logging config option 2013-05-31 17:51:48 -07:00
Robbie Hanson
c8774cf17c Smarter checkpointing 2013-05-31 17:50:13 -07:00
Robbie Hanson
c4f7312346 Change extensions to use their own separate (mainly temporary) database connection. 2013-05-31 14:30:48 -07:00
Robbie Hanson
6873c8510f Adding more information to connection state 2013-05-31 12:24:26 -07:00
Robbie Hanson
5a285a5150 Performance optimization: no need to mark the sql-level shared read-lock from a read-write transaction 2013-05-31 12:06:36 -07:00
Robbie Hanson
a62ab026f2 Exposing access to the snapshot variable 2013-05-28 17:58:35 -07:00
Robbie Hanson
8f08f79ba4 Use proper dictionary capacity 2013-05-28 02:15:13 -07:00
Robbie Hanson
8e20585c78 Adding some method swizzling for performance improvement 2013-05-28 02:14:42 -07:00
Robbie Hanson
d56fd97456 Renaming cacheSnapshot ivar to snapshot. Also making the ivar private. 2013-05-28 01:22:05 -07:00
Robbie Hanson
9a0b752c28 Moving rollback variable into transaction 2013-05-28 01:14:02 -07:00
Robbie Hanson
c12c174267 Adding long-lived read transactions & YapDatabaseModifiedNotification 2013-05-28 01:10:38 -07:00
Robbie Hanson
f4eeadc8e2 Fixing potential memory leak 2013-05-27 16:08:04 -07:00
Robbie Hanson
c433958977 Minor optimization: was setting the same variable twice 2013-05-27 15:19:37 -07:00
Robbie Hanson
67e1815e3d Forgot to flush rollback pre-compiled statement during memory flush. 2013-05-27 15:11:47 -07:00
Robbie Hanson
ee0a5a860c Optimizing performance of snapshot serialization/deserialization 2013-05-26 16:25:47 -07:00
Robbie Hanson
896820e0f2 Tweaking unit test: decreasing delay 2013-05-26 16:25:24 -07:00
Robbie Hanson
d2d4c11f4b Bug fix: rollback state change wasn't going through snapshotQueue 2013-05-26 15:32:02 -07:00
Robbie Hanson
a6054f1ae0 Performance optimization: immediately drop changeset if there are no other connections 2013-05-26 15:31:46 -07:00
Robbie Hanson
289a8d4cf1 Adding keysInRange method to YapDatabaseView 2013-05-26 15:22:16 -07:00
Robbie Hanson
4b38c80267 Adding enumeration methods to YapDatabaseView 2013-05-26 12:39:38 -07:00
Robbie Hanson
4ebe917033 YapDatabaseView optimization: Don't set dirtyKeys if pageKey hasn't changed 2013-05-25 20:59:40 -07:00
Robbie Hanson
1cbdc8b1f9 Adding grouping/sorting by keys only 2013-05-25 20:15:37 -07:00
Robbie Hanson
8bb02e7666 Fixing Xcode-desktop project for 2.0 branch 2013-05-25 12:57:10 -07:00
Robbie Hanson
431b5c6710 Adding Xcode-desktop project for Mac OS X compilation 2013-05-25 12:50:49 -07:00
Robbie Hanson
88d96bc2f1 Fixing some compiler warnings when compiling for Mac OS X 2013-05-25 12:50:13 -07:00
Robbie Hanson
d0203dfdfb Fixing some compiler warnings when compiling for Mac OS X 2013-05-25 12:47:25 -07:00
Robbie Hanson
9cb6004540 Fixing some compiler warnings when compiling for Mac OS X 2013-05-25 12:47:05 -07:00
Robbie Hanson
0d78ae9071 Fixing some compiler warnings when compiling for Mac OS X 2013-05-25 12:36:23 -07:00
Robbie Hanson
5864f332e2 Fixing build error when compiling for Mac OS X 2013-05-25 12:36:06 -07:00
Robbie Hanson
efd1921cbc Working on documentation 2013-05-25 10:41:12 -07:00
Robbie Hanson
da68853e83 Adding some documentation. Trivial changes. 2013-05-23 18:42:22 -07:00
Robbie Hanson
d6e2832a85 Refactor to "extensions" 2013-05-23 18:11:12 -07:00
Robbie Hanson
f1d9c83739 Bug fixes for timestamp category 2013-05-23 12:34:49 -07:00
Robbie Hanson
5d6a77b165 Completed unit test for YapDatabaseView 2013-05-23 12:09:29 -07:00
Robbie Hanson
d2e3af3b24 Working on unit tests for YapDatabaseView 2013-05-22 17:43:04 -07:00
Robbie Hanson
0a704d824d Project cleanup. Starting work on unit tests. 2013-05-22 12:09:37 -07:00
Robbie Hanson
768be7a644 Work in progress - entering testing stages 2013-05-22 11:21:26 -07:00
Robbie Hanson
9a19ddfe91 Merging latest changes from CocoaLumberjack project 2013-05-22 11:06:11 -07:00
Robbie Hanson
cb91862722 Work in Progress 2013-05-20 15:10:25 -07:00
Robbie Hanson
0a50c02f3b Work in progress 2013-04-27 01:08:30 -07:00
Robbie Hanson
707872a6f0 Improvements to logging header 2013-04-15 18:05:10 -07:00
Robbie Hanson
c2c4fffb9b Work in progress 2013-04-15 18:04:29 -07:00
Robbie Hanson
a05ff049f4 Work in progress: Flushing out how views will fit into existing architecture 2013-04-10 20:02:34 -07:00
Robbie Hanson
d745ebc035 Bug fix: The internal cache retains keys, not copy, for performance. So it's an error to put mutable keys in the cache. 2013-04-10 19:37:50 -07:00
Robbie Hanson
57ec398e9f Add items to the cache during enumeration if the cache size is unlimited, or if the cache isn't full. 2013-04-10 19:35:39 -07:00
Robbie Hanson
84dcad1b59 Renaming file 2013-04-08 16:18:26 -07:00
Robbie Hanson
48c3cf2975 Work in progress: Flushing out how views will fit into existing architecture 2013-04-07 21:01:21 -07:00
Robbie Hanson
785550fb03 Work in progress: Flushing out how views will fit into existing architecture 2013-04-07 13:45:54 -07:00
Robbie Hanson
ca2367fd3a Removing "ordered" code. Will be replaced with more flexible "views" idea. 2013-04-07 13:36:15 -07:00
2819 changed files with 291312 additions and 30203 deletions

24
.gitignore vendored
View File

@ -1,6 +1,11 @@
# Xcode
## Mac OS X
.DS_Store
## Xcode - Build
build/
DerivedData
## Xcode - Settings
*.pbxuser
!default.pbxuser
*.mode1v3
@ -9,10 +14,17 @@ build/
!default.mode2v3
*.perspectivev3
!default.perspectivev3
*.xcworkspace
!default.xcworkspace
xcuserdata
profile
## Xcode - Other
*.xccheckout
*.moved-aside
DerivedData
.idea/
*.xcuserstate
# Carthage
Carthage/Checkouts
Carthage/Build
## Custom
LumberjackUser.h
LumberjackUser.temp.h

9
.travis.yml Normal file
View File

@ -0,0 +1,9 @@
language: objective-c
osx_image: xcode9.2
before_script:
- export LANG=en_US.UTF-8
script:
- cd ./Testing/Xcode-desktop
- xcodebuild -workspace YapDatabaseTesting.xcworkspace -scheme YapDatabaseTesting clean
- xcodebuild -workspace YapDatabaseTesting.xcworkspace -scheme YapDatabaseTesting -configuration release test

1
Cartfile Executable file
View File

@ -0,0 +1 @@
github "CocoaLumberjack/CocoaLumberjack"

1
Cartfile.resolved Normal file
View File

@ -0,0 +1 @@
github "CocoaLumberjack/CocoaLumberjack" "3.3.0"

View File

@ -0,0 +1,523 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
51EE553F951BF40945032BD5 /* libPods-CloudKitTodo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = ABB1832E9FCC349F48EB4C9C /* libPods-CloudKitTodo.a */; };
DC212CE11F6D98F600C11BF0 /* CloudKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC212CE01F6D98F600C11BF0 /* CloudKit.framework */; };
DC6071471A33F3FF00207DE9 /* TodoCell.m in Sources */ = {isa = PBXBuildFile; fileRef = DC6071461A33F3FF00207DE9 /* TodoCell.m */; };
DC60714A1A33FC3900207DE9 /* checkmark-off.png in Resources */ = {isa = PBXBuildFile; fileRef = DC6071481A33FC3900207DE9 /* checkmark-off.png */; };
DC60714B1A33FC3900207DE9 /* checkmark-on.png in Resources */ = {isa = PBXBuildFile; fileRef = DC6071491A33FC3900207DE9 /* checkmark-on.png */; };
DC927FFD1A344BA500FEEAEA /* TodoTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = DC927FFC1A344BA500FEEAEA /* TodoTextView.m */; };
DCDE77211A3023E9001D8FCE /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = DCDE77201A3023E9001D8FCE /* main.m */; };
DCDE77241A3023E9001D8FCE /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = DCDE77231A3023E9001D8FCE /* AppDelegate.m */; };
DCDE772A1A3023E9001D8FCE /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DCDE77281A3023E9001D8FCE /* Main.storyboard */; };
DCDE772C1A3023E9001D8FCE /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DCDE772B1A3023E9001D8FCE /* Images.xcassets */; };
DCDE772F1A3023E9001D8FCE /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = DCDE772D1A3023E9001D8FCE /* LaunchScreen.xib */; };
DCDE77701A302A44001D8FCE /* CloudKitManager.m in Sources */ = {isa = PBXBuildFile; fileRef = DCDE776D1A302A44001D8FCE /* CloudKitManager.m */; };
DCDE77711A302A44001D8FCE /* DatabaseManager.m in Sources */ = {isa = PBXBuildFile; fileRef = DCDE776F1A302A44001D8FCE /* DatabaseManager.m */; };
DCDE77761A302A66001D8FCE /* EditViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DCDE77731A302A66001D8FCE /* EditViewController.m */; };
DCDE77771A302A66001D8FCE /* RootViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DCDE77751A302A66001D8FCE /* RootViewController.m */; };
DCDE78801A302B29001D8FCE /* MyDatabaseObject.m in Sources */ = {isa = PBXBuildFile; fileRef = DCDE787D1A302B29001D8FCE /* MyDatabaseObject.m */; };
DCDE78811A302B29001D8FCE /* MyTodo.m in Sources */ = {isa = PBXBuildFile; fileRef = DCDE787F1A302B29001D8FCE /* MyTodo.m */; };
DCDE78831A302B46001D8FCE /* libsqlite3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DCDE78821A302B46001D8FCE /* libsqlite3.dylib */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
703B5BE0F88E9B9E927805E5 /* Pods-CloudKitTodo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CloudKitTodo.release.xcconfig"; path = "Pods/Target Support Files/Pods-CloudKitTodo/Pods-CloudKitTodo.release.xcconfig"; sourceTree = "<group>"; };
ABB1832E9FCC349F48EB4C9C /* libPods-CloudKitTodo.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-CloudKitTodo.a"; sourceTree = BUILT_PRODUCTS_DIR; };
DC212CE01F6D98F600C11BF0 /* CloudKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CloudKit.framework; path = System/Library/Frameworks/CloudKit.framework; sourceTree = SDKROOT; };
DC6071451A33F3FF00207DE9 /* TodoCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TodoCell.h; sourceTree = "<group>"; };
DC6071461A33F3FF00207DE9 /* TodoCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TodoCell.m; sourceTree = "<group>"; };
DC6071481A33FC3900207DE9 /* checkmark-off.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "checkmark-off.png"; sourceTree = "<group>"; };
DC6071491A33FC3900207DE9 /* checkmark-on.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "checkmark-on.png"; sourceTree = "<group>"; };
DC927FFB1A344BA500FEEAEA /* TodoTextView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TodoTextView.h; sourceTree = "<group>"; };
DC927FFC1A344BA500FEEAEA /* TodoTextView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TodoTextView.m; sourceTree = "<group>"; };
DCDE771B1A3023E9001D8FCE /* CloudKitTodo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CloudKitTodo.app; sourceTree = BUILT_PRODUCTS_DIR; };
DCDE771F1A3023E9001D8FCE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
DCDE77201A3023E9001D8FCE /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
DCDE77221A3023E9001D8FCE /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
DCDE77231A3023E9001D8FCE /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
DCDE77291A3023E9001D8FCE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
DCDE772B1A3023E9001D8FCE /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
DCDE772E1A3023E9001D8FCE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = "<group>"; };
DCDE77681A302873001D8FCE /* CloudKitTodo.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = CloudKitTodo.entitlements; sourceTree = "<group>"; };
DCDE776C1A302A44001D8FCE /* CloudKitManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CloudKitManager.h; sourceTree = "<group>"; };
DCDE776D1A302A44001D8FCE /* CloudKitManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CloudKitManager.m; sourceTree = "<group>"; };
DCDE776E1A302A44001D8FCE /* DatabaseManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DatabaseManager.h; sourceTree = "<group>"; };
DCDE776F1A302A44001D8FCE /* DatabaseManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DatabaseManager.m; sourceTree = "<group>"; };
DCDE77721A302A66001D8FCE /* EditViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EditViewController.h; sourceTree = "<group>"; };
DCDE77731A302A66001D8FCE /* EditViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EditViewController.m; sourceTree = "<group>"; };
DCDE77741A302A66001D8FCE /* RootViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RootViewController.h; sourceTree = "<group>"; };
DCDE77751A302A66001D8FCE /* RootViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RootViewController.m; sourceTree = "<group>"; };
DCDE787C1A302B29001D8FCE /* MyDatabaseObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MyDatabaseObject.h; sourceTree = "<group>"; };
DCDE787D1A302B29001D8FCE /* MyDatabaseObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MyDatabaseObject.m; sourceTree = "<group>"; };
DCDE787E1A302B29001D8FCE /* MyTodo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MyTodo.h; sourceTree = "<group>"; };
DCDE787F1A302B29001D8FCE /* MyTodo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MyTodo.m; sourceTree = "<group>"; };
DCDE78821A302B46001D8FCE /* libsqlite3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsqlite3.dylib; path = usr/lib/libsqlite3.dylib; sourceTree = SDKROOT; };
F32EDD3AE8334674ADF30C82 /* Pods-CloudKitTodo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CloudKitTodo.debug.xcconfig"; path = "Pods/Target Support Files/Pods-CloudKitTodo/Pods-CloudKitTodo.debug.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
DCDE77181A3023E9001D8FCE /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
DC212CE11F6D98F600C11BF0 /* CloudKit.framework in Frameworks */,
DCDE78831A302B46001D8FCE /* libsqlite3.dylib in Frameworks */,
51EE553F951BF40945032BD5 /* libPods-CloudKitTodo.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
2BCD426F1D5F7D0B429BB734 /* Pods */ = {
isa = PBXGroup;
children = (
F32EDD3AE8334674ADF30C82 /* Pods-CloudKitTodo.debug.xcconfig */,
703B5BE0F88E9B9E927805E5 /* Pods-CloudKitTodo.release.xcconfig */,
);
name = Pods;
sourceTree = "<group>";
};
DCDE77121A3023E9001D8FCE = {
isa = PBXGroup;
children = (
DCDE771D1A3023E9001D8FCE /* CloudKitTodo */,
DCDE776B1A3028EA001D8FCE /* Frameworks */,
DCDE771C1A3023E9001D8FCE /* Products */,
2BCD426F1D5F7D0B429BB734 /* Pods */,
);
sourceTree = "<group>";
};
DCDE771C1A3023E9001D8FCE /* Products */ = {
isa = PBXGroup;
children = (
DCDE771B1A3023E9001D8FCE /* CloudKitTodo.app */,
);
name = Products;
sourceTree = "<group>";
};
DCDE771D1A3023E9001D8FCE /* CloudKitTodo */ = {
isa = PBXGroup;
children = (
DCDE77221A3023E9001D8FCE /* AppDelegate.h */,
DCDE77231A3023E9001D8FCE /* AppDelegate.m */,
DCDE78781A302AD6001D8FCE /* Managers */,
DCDE787B1A302B1B001D8FCE /* Model */,
DCDE787A1A302AFB001D8FCE /* UI */,
DCDE771E1A3023E9001D8FCE /* Supporting Files */,
);
path = CloudKitTodo;
sourceTree = "<group>";
};
DCDE771E1A3023E9001D8FCE /* Supporting Files */ = {
isa = PBXGroup;
children = (
DCDE77681A302873001D8FCE /* CloudKitTodo.entitlements */,
DCDE771F1A3023E9001D8FCE /* Info.plist */,
DCDE77201A3023E9001D8FCE /* main.m */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
DCDE776B1A3028EA001D8FCE /* Frameworks */ = {
isa = PBXGroup;
children = (
DC212CE01F6D98F600C11BF0 /* CloudKit.framework */,
DCDE78821A302B46001D8FCE /* libsqlite3.dylib */,
ABB1832E9FCC349F48EB4C9C /* libPods-CloudKitTodo.a */,
);
name = Frameworks;
sourceTree = "<group>";
};
DCDE78781A302AD6001D8FCE /* Managers */ = {
isa = PBXGroup;
children = (
DCDE776E1A302A44001D8FCE /* DatabaseManager.h */,
DCDE776F1A302A44001D8FCE /* DatabaseManager.m */,
DCDE776C1A302A44001D8FCE /* CloudKitManager.h */,
DCDE776D1A302A44001D8FCE /* CloudKitManager.m */,
);
name = Managers;
sourceTree = "<group>";
};
DCDE787A1A302AFB001D8FCE /* UI */ = {
isa = PBXGroup;
children = (
DCDE77741A302A66001D8FCE /* RootViewController.h */,
DCDE77751A302A66001D8FCE /* RootViewController.m */,
DCDE77721A302A66001D8FCE /* EditViewController.h */,
DCDE77731A302A66001D8FCE /* EditViewController.m */,
DC6071451A33F3FF00207DE9 /* TodoCell.h */,
DC6071461A33F3FF00207DE9 /* TodoCell.m */,
DC927FFB1A344BA500FEEAEA /* TodoTextView.h */,
DC927FFC1A344BA500FEEAEA /* TodoTextView.m */,
DCDE77281A3023E9001D8FCE /* Main.storyboard */,
DCDE772B1A3023E9001D8FCE /* Images.xcassets */,
DC6071481A33FC3900207DE9 /* checkmark-off.png */,
DC6071491A33FC3900207DE9 /* checkmark-on.png */,
DCDE772D1A3023E9001D8FCE /* LaunchScreen.xib */,
);
name = UI;
sourceTree = "<group>";
};
DCDE787B1A302B1B001D8FCE /* Model */ = {
isa = PBXGroup;
children = (
DCDE787C1A302B29001D8FCE /* MyDatabaseObject.h */,
DCDE787D1A302B29001D8FCE /* MyDatabaseObject.m */,
DCDE787E1A302B29001D8FCE /* MyTodo.h */,
DCDE787F1A302B29001D8FCE /* MyTodo.m */,
);
name = Model;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
DCDE771A1A3023E9001D8FCE /* CloudKitTodo */ = {
isa = PBXNativeTarget;
buildConfigurationList = DCDE773E1A3023E9001D8FCE /* Build configuration list for PBXNativeTarget "CloudKitTodo" */;
buildPhases = (
4D70F164321A80912E0E0351 /* [CP] Check Pods Manifest.lock */,
DCDE77171A3023E9001D8FCE /* Sources */,
DCDE77181A3023E9001D8FCE /* Frameworks */,
DCDE77191A3023E9001D8FCE /* Resources */,
A7E36A79EF95353C65F5D2B6 /* [CP] Embed Pods Frameworks */,
ED83D0453CE4BE42D9A22D78 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
dependencies = (
);
name = CloudKitTodo;
productName = CloudKitTodo;
productReference = DCDE771B1A3023E9001D8FCE /* CloudKitTodo.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
DCDE77131A3023E9001D8FCE /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0900;
ORGANIZATIONNAME = "Deusty LLC";
TargetAttributes = {
DCDE771A1A3023E9001D8FCE = {
CreatedOnToolsVersion = 6.1;
DevelopmentTeam = VT5GYGYX83;
SystemCapabilities = {
com.apple.BackgroundModes = {
enabled = 1;
};
com.apple.Push = {
enabled = 1;
};
com.apple.iCloud = {
enabled = 1;
};
};
};
};
};
buildConfigurationList = DCDE77161A3023E9001D8FCE /* Build configuration list for PBXProject "CloudKitTodo" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = DCDE77121A3023E9001D8FCE;
productRefGroup = DCDE771C1A3023E9001D8FCE /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
DCDE771A1A3023E9001D8FCE /* CloudKitTodo */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
DCDE77191A3023E9001D8FCE /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
DCDE772A1A3023E9001D8FCE /* Main.storyboard in Resources */,
DC60714A1A33FC3900207DE9 /* checkmark-off.png in Resources */,
DCDE772F1A3023E9001D8FCE /* LaunchScreen.xib in Resources */,
DCDE772C1A3023E9001D8FCE /* Images.xcassets in Resources */,
DC60714B1A33FC3900207DE9 /* checkmark-on.png in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
4D70F164321A80912E0E0351 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-CloudKitTodo-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
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# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
A7E36A79EF95353C65F5D2B6 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-CloudKitTodo/Pods-CloudKitTodo-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
ED83D0453CE4BE42D9A22D78 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "[CP] Copy Pods Resources";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-CloudKitTodo/Pods-CloudKitTodo-resources.sh\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
DCDE77171A3023E9001D8FCE /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
DCDE78801A302B29001D8FCE /* MyDatabaseObject.m in Sources */,
DCDE77771A302A66001D8FCE /* RootViewController.m in Sources */,
DCDE77701A302A44001D8FCE /* CloudKitManager.m in Sources */,
DCDE77761A302A66001D8FCE /* EditViewController.m in Sources */,
DC927FFD1A344BA500FEEAEA /* TodoTextView.m in Sources */,
DCDE77241A3023E9001D8FCE /* AppDelegate.m in Sources */,
DCDE77211A3023E9001D8FCE /* main.m in Sources */,
DCDE78811A302B29001D8FCE /* MyTodo.m in Sources */,
DC6071471A33F3FF00207DE9 /* TodoCell.m in Sources */,
DCDE77711A302A44001D8FCE /* DatabaseManager.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
DCDE77281A3023E9001D8FCE /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
DCDE77291A3023E9001D8FCE /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
DCDE772D1A3023E9001D8FCE /* LaunchScreen.xib */ = {
isa = PBXVariantGroup;
children = (
DCDE772E1A3023E9001D8FCE /* Base */,
);
name = LaunchScreen.xib;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
DCDE773C1A3023E9001D8FCE /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
DCDE773D1A3023E9001D8FCE /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = YES;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
DCDE773F1A3023E9001D8FCE /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = F32EDD3AE8334674ADF30C82 /* Pods-CloudKitTodo.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = CloudKitTodo/CloudKitTodo.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
HEADER_SEARCH_PATHS = (
"$(inherited)",
"\"${PODS_ROOT}/Headers/Public\"",
"\"${PODS_ROOT}/Headers/Public/CocoaLumberjack\"",
"\"${PODS_ROOT}/Headers/Public/Reachability\"",
"\"${PODS_ROOT}/Headers/Public/YapDatabase\"",
"\"${PODS_ROOT}/Headers/Private/YapDatabase\"",
);
INFOPLIST_FILE = CloudKitTodo/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.4th-a.CloudKitTodo";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE = "";
};
name = Debug;
};
DCDE77401A3023E9001D8FCE /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 703B5BE0F88E9B9E927805E5 /* Pods-CloudKitTodo.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = CloudKitTodo/CloudKitTodo.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
HEADER_SEARCH_PATHS = (
"$(inherited)",
"\"${PODS_ROOT}/Headers/Public\"",
"\"${PODS_ROOT}/Headers/Public/CocoaLumberjack\"",
"\"${PODS_ROOT}/Headers/Public/Reachability\"",
"\"${PODS_ROOT}/Headers/Public/YapDatabase\"",
"\"${PODS_ROOT}/Headers/Private/YapDatabase\"",
);
INFOPLIST_FILE = CloudKitTodo/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.4th-a.CloudKitTodo";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE = "";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
DCDE77161A3023E9001D8FCE /* Build configuration list for PBXProject "CloudKitTodo" */ = {
isa = XCConfigurationList;
buildConfigurations = (
DCDE773C1A3023E9001D8FCE /* Debug */,
DCDE773D1A3023E9001D8FCE /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
DCDE773E1A3023E9001D8FCE /* Build configuration list for PBXNativeTarget "CloudKitTodo" */ = {
isa = XCConfigurationList;
buildConfigurations = (
DCDE773F1A3023E9001D8FCE /* Debug */,
DCDE77401A3023E9001D8FCE /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = DCDE77131A3023E9001D8FCE /* Project object */;
}

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:CloudKitTodo.xcodeproj">
</FileRef>
</Workspace>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:CloudKitTodo.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace>

View File

@ -0,0 +1,17 @@
#import <UIKit/UIKit.h>
#import <Reachability/Reachability.h>
#import <YapDatabase/YapDatabase.h>
#import <YapDatabase/YapDatabaseCloudKit.h>
@class AppDelegate;
extern AppDelegate *MyAppDelegate;
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (nonatomic, strong) UIWindow *window;
@property (nonatomic, strong, readonly) Reachability *reachability;
@end

View File

@ -0,0 +1,165 @@
#import "AppDelegate.h"
#import "CloudKitManager.h"
#import "DatabaseManager.h"
#import "MyTodo.h"
#import "YapDatabaseLogging.h"
#import <CocoaLumberjack/CocoaLumberjack.h>
#import <CocoaLumberjack/DDTTYLogger.h>
#import <CloudKit/CloudKit.h>
#import <Reachability/Reachability.h>
#import <UserNotifications/UserNotifications.h>
#if DEBUG
static const NSUInteger ddLogLevel = DDLogLevelAll;
#else
static const NSUInteger ddLogLevel = DDLogLevelAll;
#endif
AppDelegate *MyAppDelegate;
@implementation AppDelegate
@synthesize reachability = reachability;
- (id)init
{
if ((self = [super init]))
{
// Store global reference
MyAppDelegate = self;
// Configure logging
[DDLog addLogger:[DDTTYLogger sharedInstance]];
[[DDTTYLogger sharedInstance] setColorsEnabled:YES];
#if TARGET_OS_IPHONE
UIColor *redColor = [UIColor redColor];
UIColor *orangeColor = [UIColor orangeColor];
UIColor *grayColor = [UIColor grayColor];
#else
NSColor *redColor = [NSColor redColor];
NSColor *orangeColor = [NSColor orangeColor];
NSColor *grayColor = [NSColor grayColor];
#endif
[[DDTTYLogger sharedInstance] setForegroundColor:redColor
backgroundColor:nil
forFlag:YDB_LOG_FLAG_ERROR // errors
context:YDBLogContext]; // from YapDatabase
[[DDTTYLogger sharedInstance] setForegroundColor:orangeColor
backgroundColor:nil
forFlag:YDB_LOG_FLAG_WARN // warnings
context:YDBLogContext]; // from YapDatabase
[[DDTTYLogger sharedInstance] setForegroundColor:grayColor
backgroundColor:nil
forFlag:YDB_LOG_FLAG_TRACE // trace (method invocations)
context:YDBLogContext]; // from YapDatabase
}
return self;
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
DDLogVerbose(@"application:didFinishLaunchingWithOptions: %@", launchOptions);
// Start database & cloudKit (in that order)
[DatabaseManager initialize];
[CloudKitManager initialize];
// Register for push notifications
UNAuthorizationOptions options = UNAuthorizationOptionBadge;
[[UNUserNotificationCenter currentNotificationCenter]
requestAuthorizationWithOptions:options
completionHandler:^(BOOL granted, NSError *_Nullable error)
{
if (granted)
DDLogVerbose(@"UNAuthorizationOptionBadge: granted");
else
DDLogWarn(@"UNAuthorizationOptionBadge: NOT granted !");
dispatch_async(dispatch_get_main_queue(), ^{
[application registerForRemoteNotifications];
});
}];
// Start reachability
reachability = [Reachability reachabilityForInternetConnection];
[reachability startNotifier];
return YES;
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
DDLogVerbose(@"applicationWillEnterForeground:");
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
DDLogVerbose(@"applicationDidBecomeActive:");
}
- (void)applicationWillResignActive:(UIApplication *)application
{
DDLogVerbose(@"applicationWillResignActive:");
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
DDLogVerbose(@"applicationDidEnterBackground:");
}
- (void)applicationWillTerminate:(UIApplication *)application
{
DDLogVerbose(@"applicationWillTerminate:");
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark Push (iOS 8)
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
DDLogVerbose(@"Registered for Push notifications with token: %@", deviceToken);
}
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
{
DDLogVerbose(@"Push subscription failed: %@", error);
}
- (void)application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler
{
DDLogVerbose(@"Push received: %@", userInfo);
__block UIBackgroundFetchResult combinedFetchResult = UIBackgroundFetchResultNoData;
[[CloudKitManager sharedInstance] fetchRecordChangesWithCompletionHandler:
^(UIBackgroundFetchResult fetchResult, BOOL moreComing)
{
if (fetchResult == UIBackgroundFetchResultNewData) {
combinedFetchResult = UIBackgroundFetchResultNewData;
}
else if (fetchResult == UIBackgroundFetchResultFailed && combinedFetchResult == UIBackgroundFetchResultNoData) {
combinedFetchResult = UIBackgroundFetchResultFailed;
}
if (!moreComing) {
completionHandler(combinedFetchResult);
}
}];
}
@end

View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="6751" systemVersion="14D87h" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6736"/>
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB">
<rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=" Copyright (c) 2014 Deusty LLC. All rights reserved." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye">
<rect key="frame" x="20" y="439" width="441" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="CloudKitTodo" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="kId-c2-rCX">
<rect key="frame" x="20" y="140" width="441" height="43"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="kId-c2-rCX" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="bottom" multiplier="1/3" constant="1" id="5cJ-9S-tgC"/>
<constraint firstAttribute="centerX" secondItem="kId-c2-rCX" secondAttribute="centerX" id="Koa-jz-hwk"/>
<constraint firstAttribute="bottom" secondItem="8ie-xW-0ye" secondAttribute="bottom" constant="20" id="Kzo-t9-V3l"/>
<constraint firstItem="8ie-xW-0ye" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="MfP-vx-nX0"/>
<constraint firstAttribute="centerX" secondItem="8ie-xW-0ye" secondAttribute="centerX" id="ZEH-qu-HZ9"/>
<constraint firstItem="kId-c2-rCX" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="fvb-Df-36g"/>
</constraints>
<nil key="simulatedStatusBarMetrics"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<point key="canvasLocation" x="548" y="455"/>
</view>
</objects>
</document>

View File

@ -0,0 +1,373 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="9060" systemVersion="15B42" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="AeC-oa-Ew0">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9051"/>
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
</dependencies>
<scenes>
<!--Navigation Controller-->
<scene sceneID="ZJV-Az-MTO">
<objects>
<navigationController id="AeC-oa-Ew0" sceneMemberID="viewController">
<navigationBar key="navigationBar" contentMode="scaleToFill" id="Y4G-bB-bZZ">
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<animations/>
</navigationBar>
<connections>
<segue destination="ZMP-7o-CDj" kind="relationship" relationship="rootViewController" id="dk8-fM-IxH"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="3d1-7W-dOB" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-68" y="377"/>
</scene>
<!--CloudKitTodo-->
<scene sceneID="YUY-zP-mvy">
<objects>
<viewController id="ZMP-7o-CDj" customClass="RootViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="h36-Bm-gfx"/>
<viewControllerLayoutGuide type="bottom" id="2sE-br-UK9"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="phY-xl-hFk">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" translatesAutoresizingMaskIntoConstraints="NO" id="Yft-Qg-2YH">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<animations/>
<prototypes>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="Todo" id="DEc-iV-D5X" customClass="TodoCell">
<rect key="frame" x="0.0" y="86" width="600" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="DEc-iV-D5X" id="S4Y-Fw-wMI">
<rect key="frame" x="0.0" y="0.0" width="600" height="43"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="GdB-2i-Ayi">
<rect key="frame" x="8" y="7" width="28" height="28"/>
<animations/>
<constraints>
<constraint firstAttribute="height" constant="28" id="Fgt-hn-iBH"/>
<constraint firstAttribute="width" constant="28" id="gY6-Ti-iMM"/>
</constraints>
<state key="normal" image="checkmark-on.png">
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="didTapImageView:" destination="DEc-iV-D5X" eventType="touchUpInside" id="Wp6-kb-ZnM"/>
</connections>
</button>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="todo.title" lineBreakMode="wordWrap" numberOfLines="3" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="p45-y8-7NQ">
<rect key="frame" x="44" y="11" width="548" height="21"/>
<animations/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<animations/>
<constraints>
<constraint firstItem="p45-y8-7NQ" firstAttribute="top" secondItem="S4Y-Fw-wMI" secondAttribute="topMargin" constant="3" id="BCf-jV-ho9"/>
<constraint firstItem="p45-y8-7NQ" firstAttribute="leading" secondItem="GdB-2i-Ayi" secondAttribute="trailing" constant="8" id="I8v-Lt-4JL"/>
<constraint firstItem="p45-y8-7NQ" firstAttribute="trailing" secondItem="S4Y-Fw-wMI" secondAttribute="trailingMargin" id="Uac-UT-IYW"/>
<constraint firstAttribute="centerY" secondItem="GdB-2i-Ayi" secondAttribute="centerY" id="YrZ-F2-Knd"/>
<constraint firstAttribute="bottomMargin" secondItem="p45-y8-7NQ" secondAttribute="bottom" constant="3" id="iCR-pW-7ZL"/>
<constraint firstItem="GdB-2i-Ayi" firstAttribute="leading" secondItem="S4Y-Fw-wMI" secondAttribute="leadingMargin" id="ktZ-QC-b1Z"/>
</constraints>
</tableViewCellContentView>
<animations/>
<connections>
<outlet property="checkmarkButton" destination="GdB-2i-Ayi" id="RJI-fG-Pc1"/>
<outlet property="titleLabel" destination="p45-y8-7NQ" id="jDr-KC-Tqy"/>
</connections>
</tableViewCell>
</prototypes>
<connections>
<outlet property="dataSource" destination="ZMP-7o-CDj" id="Lii-lq-iyd"/>
<outlet property="delegate" destination="ZMP-7o-CDj" id="tuy-Kr-OMv"/>
</connections>
</tableView>
<view alpha="0.84999999999999987" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="TqX-YI-hcf">
<rect key="frame" x="0.0" y="505" width="600" height="95"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="250" misplaced="YES" text="YapDatabaseCloudKit" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="muy-ee-zR0">
<rect key="frame" x="74" y="8" width="457" height="17"/>
<animations/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" misplaced="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="KjR-xN-kmG">
<rect key="frame" x="539" y="4" width="53" height="29"/>
<animations/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<state key="normal" title="Resume">
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="resumeButtonTapped:" destination="ZMP-7o-CDj" eventType="touchUpInside" id="5Ah-rs-sXb"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" misplaced="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="TNj-1O-PFd">
<rect key="frame" x="8" y="4" width="58" height="29"/>
<animations/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<state key="normal" title="Suspend">
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="suspendButtonTapped:" destination="ZMP-7o-CDj" eventType="touchUpInside" id="agt-dv-yPe"/>
</connections>
</button>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Status: Unknown (suspendCount = X)" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="14" translatesAutoresizingMaskIntoConstraints="NO" id="OaA-1V-vVR" userLabel="TopStatusLabel">
<rect key="frame" x="8" y="39" width="584" height="20"/>
<animations/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<color key="textColor" red="0.94117647058823528" green="0.94117647058823528" blue="0.94117647058823528" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Queue: InFlight(X), Queued(Y)" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="14" translatesAutoresizingMaskIntoConstraints="NO" id="5fa-al-XJj" userLabel="BottomStatusLabel">
<rect key="frame" x="8" y="67" width="584" height="20"/>
<animations/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<color key="textColor" red="0.94117647058823528" green="0.94117647058823528" blue="0.94117647058823528" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<animations/>
<color key="backgroundColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="muy-ee-zR0" firstAttribute="top" secondItem="TqX-YI-hcf" secondAttribute="top" constant="8" id="4BI-IS-9nP"/>
<constraint firstItem="KjR-xN-kmG" firstAttribute="top" secondItem="TqX-YI-hcf" secondAttribute="top" constant="4" id="4sW-fT-l7G"/>
<constraint firstItem="muy-ee-zR0" firstAttribute="leading" secondItem="TNj-1O-PFd" secondAttribute="trailing" constant="8" id="5aj-cJ-XsL"/>
<constraint firstItem="5fa-al-XJj" firstAttribute="leading" secondItem="TqX-YI-hcf" secondAttribute="leading" constant="8" id="65z-hg-ftU"/>
<constraint firstItem="OaA-1V-vVR" firstAttribute="leading" secondItem="TqX-YI-hcf" secondAttribute="leading" constant="8" id="8dy-8l-gcv"/>
<constraint firstAttribute="trailing" secondItem="5fa-al-XJj" secondAttribute="trailing" constant="8" id="AUe-6l-Vjc"/>
<constraint firstAttribute="trailing" secondItem="KjR-xN-kmG" secondAttribute="trailing" constant="8" id="BBo-LR-THi"/>
<constraint firstItem="TNj-1O-PFd" firstAttribute="top" secondItem="TqX-YI-hcf" secondAttribute="top" constant="4" id="Cle-Jt-lbO"/>
<constraint firstAttribute="bottom" secondItem="5fa-al-XJj" secondAttribute="bottom" constant="8" id="Gc8-aZ-ijr"/>
<constraint firstItem="5fa-al-XJj" firstAttribute="top" secondItem="OaA-1V-vVR" secondAttribute="bottom" constant="8" id="Jrt-C4-i3n"/>
<constraint firstAttribute="height" constant="95" id="QQb-T0-Jzw"/>
<constraint firstItem="KjR-xN-kmG" firstAttribute="leading" secondItem="muy-ee-zR0" secondAttribute="trailing" constant="8" id="eeR-BQ-hsV"/>
<constraint firstItem="TNj-1O-PFd" firstAttribute="leading" secondItem="TqX-YI-hcf" secondAttribute="leading" constant="8" id="gZz-8R-fHA"/>
<constraint firstAttribute="trailing" secondItem="OaA-1V-vVR" secondAttribute="trailing" constant="8" id="sdL-QQ-2Vf"/>
</constraints>
</view>
</subviews>
<animations/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="Yft-Qg-2YH" firstAttribute="top" secondItem="phY-xl-hFk" secondAttribute="top" id="7oZ-d9-Xaa"/>
<constraint firstAttribute="trailing" secondItem="Yft-Qg-2YH" secondAttribute="trailing" id="I66-q6-PrM"/>
<constraint firstItem="Yft-Qg-2YH" firstAttribute="leading" secondItem="phY-xl-hFk" secondAttribute="leading" id="MUz-Zs-U3o"/>
<constraint firstItem="2sE-br-UK9" firstAttribute="top" secondItem="TqX-YI-hcf" secondAttribute="bottom" id="RlJ-hC-za6"/>
<constraint firstItem="Yft-Qg-2YH" firstAttribute="top" secondItem="h36-Bm-gfx" secondAttribute="bottom" id="SsR-ma-4a4"/>
<constraint firstItem="2sE-br-UK9" firstAttribute="top" secondItem="Yft-Qg-2YH" secondAttribute="bottom" id="bDE-pV-Tio"/>
<constraint firstItem="TqX-YI-hcf" firstAttribute="leading" secondItem="phY-xl-hFk" secondAttribute="leading" id="iU1-jP-3h9"/>
<constraint firstAttribute="trailing" secondItem="TqX-YI-hcf" secondAttribute="trailing" id="vUI-gF-59l"/>
</constraints>
<variation key="default">
<mask key="constraints">
<exclude reference="SsR-ma-4a4"/>
</mask>
</variation>
</view>
<navigationItem key="navigationItem" title="CloudKitTodo" id="DlO-tp-Pgo">
<barButtonItem key="rightBarButtonItem" systemItem="add" id="F8l-sr-wHR">
<connections>
<segue destination="Djq-af-TVZ" kind="show" id="F7i-tx-Hib"/>
</connections>
</barButtonItem>
</navigationItem>
<connections>
<outlet property="ckBottomStatusLabel" destination="5fa-al-XJj" id="XcZ-c8-tMa"/>
<outlet property="ckStatusView" destination="TqX-YI-hcf" id="605-us-SxD"/>
<outlet property="ckTopStatusLabel" destination="OaA-1V-vVR" id="lik-XF-cIr"/>
<outlet property="tableView" destination="Yft-Qg-2YH" id="7hC-jh-ZYc"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="LDj-cP-95A" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="616" y="365"/>
</scene>
<!--Edit View Controller-->
<scene sceneID="Edl-TL-NCx">
<objects>
<viewController storyboardIdentifier="EditViewController" id="Djq-af-TVZ" customClass="EditViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="W48-CL-qfT"/>
<viewControllerLayoutGuide type="bottom" id="AGR-ke-4LO"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="xtZ-Fd-aXi">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="0" translatesAutoresizingMaskIntoConstraints="NO" id="Hxe-hH-R2n">
<rect key="frame" x="212" y="110" width="176" height="29"/>
<animations/>
<segments>
<segment title="Low"/>
<segment title="Normal"/>
<segment title="High"/>
</segments>
</segmentedControl>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="uuid:" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="eCf-kK-soY">
<rect key="frame" x="16" y="170" width="65" height="18"/>
<animations/>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="created:" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="mDG-e8-7zm">
<rect key="frame" x="16" y="196" width="65" height="18"/>
<animations/>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="modified:" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="DTM-os-yIa">
<rect key="frame" x="16" y="222" width="65" height="18"/>
<animations/>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Base CKRecord:" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="iif-aq-YRM">
<rect key="frame" x="16" y="256" width="111" height="18"/>
<animations/>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" horizontalCompressionResistancePriority="250" text="&lt;uuid&gt;" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="WMm-Hf-0CA" userLabel="uuidLabel">
<rect key="frame" x="89" y="170" width="495" height="18"/>
<animations/>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" horizontalCompressionResistancePriority="250" text="&lt;fomatted date&gt;" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="Bpm-ml-r5G" userLabel="creationDateLabel">
<rect key="frame" x="89" y="196" width="495" height="18"/>
<animations/>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" horizontalCompressionResistancePriority="250" text="&lt;formatted date&gt;" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="CcB-Qz-GVQ" userLabel="lastModifiedLabel">
<rect key="frame" x="89" y="222" width="495" height="18"/>
<animations/>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" horizontalCompressionResistancePriority="250" lineBreakMode="tailTruncation" numberOfLines="5" baselineAdjustment="alignBaselines" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="c8d-5n-gpH" userLabel="baseRecordLabel">
<rect key="frame" x="32" y="282" width="552" height="74"/>
<animations/>
<string key="text">&lt;CKRecord: 0x7afb1e10; recordType=todo, recordID=D850F8D1-334E-4F14-B64C-A8504C119BEE:(zone1:__defaultOwner__), recordChangeTag=x, values={}&gt;&lt;CKRecord: 0x7afb1e10; recordType=todo, recordID=D850F8D1-334E-4F14-B64C-A8504C119BEE:(zone1:__defaultOwner__), recordChangeTag=x, values={}&gt;</string>
<fontDescription key="fontDescription" name="CourierNewPSMT" family="Courier New" pointSize="13"/>
<color key="textColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" placeholderIntrinsicWidth="infinite" placeholderIntrinsicHeight="30" text="todo.title" translatesAutoresizingMaskIntoConstraints="NO" id="KGF-p9-dfP" customClass="TodoTextView">
<rect key="frame" x="20" y="72" width="560" height="30"/>
<animations/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="30" id="3Yb-Jy-Wnf"/>
<constraint firstAttribute="height" relation="lessThanOrEqual" constant="120" id="7Xn-vR-qit"/>
<constraint firstAttribute="height" constant="30" id="E9A-nT-yRh"/>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="30" id="uhA-yB-Lf8"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
<variation key="default">
<mask key="constraints">
<exclude reference="3Yb-Jy-Wnf"/>
<exclude reference="E9A-nT-yRh"/>
</mask>
</variation>
</textView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="55O-gs-uHQ">
<rect key="frame" x="20" y="110" width="28" height="28"/>
<animations/>
<constraints>
<constraint firstAttribute="width" constant="28" id="bSw-Rh-V08"/>
<constraint firstAttribute="height" constant="28" id="j3K-qB-b8y"/>
</constraints>
<state key="normal" image="checkmark-on.png">
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="checkmarkButtonTapped:" destination="Djq-af-TVZ" eventType="touchUpInside" id="wlv-GJ-ZYY"/>
</connections>
</button>
</subviews>
<animations/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="iif-aq-YRM" firstAttribute="leading" secondItem="xtZ-Fd-aXi" secondAttribute="leading" constant="16" id="1e8-D9-GEg"/>
<constraint firstItem="Hxe-hH-R2n" firstAttribute="top" secondItem="KGF-p9-dfP" secondAttribute="bottom" constant="8" id="1sU-78-fYB"/>
<constraint firstAttribute="trailing" secondItem="CcB-Qz-GVQ" secondAttribute="trailing" constant="16" id="40g-ge-xFQ"/>
<constraint firstItem="KGF-p9-dfP" firstAttribute="leading" secondItem="xtZ-Fd-aXi" secondAttribute="leadingMargin" id="55m-5S-nCD"/>
<constraint firstItem="eCf-kK-soY" firstAttribute="top" secondItem="Hxe-hH-R2n" secondAttribute="bottom" constant="32" id="5QK-Vj-kiR"/>
<constraint firstItem="55O-gs-uHQ" firstAttribute="centerY" secondItem="Hxe-hH-R2n" secondAttribute="centerY" id="7dt-EN-H8C"/>
<constraint firstItem="55O-gs-uHQ" firstAttribute="leading" secondItem="xtZ-Fd-aXi" secondAttribute="leadingMargin" id="BRC-GU-TyO"/>
<constraint firstAttribute="trailing" secondItem="WMm-Hf-0CA" secondAttribute="trailing" constant="16" id="C0L-s1-4rm"/>
<constraint firstItem="DTM-os-yIa" firstAttribute="baseline" secondItem="CcB-Qz-GVQ" secondAttribute="baseline" id="Ck5-V4-iyz"/>
<constraint firstItem="CcB-Qz-GVQ" firstAttribute="leading" secondItem="DTM-os-yIa" secondAttribute="trailing" constant="8" id="EOG-dZ-S18"/>
<constraint firstItem="eCf-kK-soY" firstAttribute="leading" secondItem="xtZ-Fd-aXi" secondAttribute="leading" constant="16" id="GGd-KP-RRx"/>
<constraint firstItem="DTM-os-yIa" firstAttribute="leading" secondItem="xtZ-Fd-aXi" secondAttribute="leading" constant="16" id="H69-vy-afT"/>
<constraint firstItem="eCf-kK-soY" firstAttribute="baseline" secondItem="WMm-Hf-0CA" secondAttribute="baseline" id="J2I-sB-95S"/>
<constraint firstAttribute="centerX" secondItem="Hxe-hH-R2n" secondAttribute="centerX" id="J7X-l8-ffp"/>
<constraint firstItem="55O-gs-uHQ" firstAttribute="top" secondItem="KGF-p9-dfP" secondAttribute="bottom" constant="7" id="NYH-PS-JOx"/>
<constraint firstItem="c8d-5n-gpH" firstAttribute="leading" secondItem="xtZ-Fd-aXi" secondAttribute="leading" constant="32" id="Nmz-3C-kDz"/>
<constraint firstItem="KGF-p9-dfP" firstAttribute="trailing" secondItem="xtZ-Fd-aXi" secondAttribute="trailingMargin" id="PJ6-n9-IP7"/>
<constraint firstItem="DTM-os-yIa" firstAttribute="top" secondItem="mDG-e8-7zm" secondAttribute="bottom" constant="8" id="Qoz-zg-xAq"/>
<constraint firstItem="mDG-e8-7zm" firstAttribute="baseline" secondItem="Bpm-ml-r5G" secondAttribute="baseline" id="T2u-mV-02h"/>
<constraint firstAttribute="centerX" secondItem="iif-aq-YRM" secondAttribute="centerX" id="XOq-wM-TfU"/>
<constraint firstItem="mDG-e8-7zm" firstAttribute="top" secondItem="eCf-kK-soY" secondAttribute="bottom" constant="8" id="Xet-k1-951"/>
<constraint firstItem="c8d-5n-gpH" firstAttribute="top" secondItem="iif-aq-YRM" secondAttribute="bottom" constant="8" id="YFf-26-Pat"/>
<constraint firstItem="WMm-Hf-0CA" firstAttribute="leading" secondItem="eCf-kK-soY" secondAttribute="trailing" constant="8" id="YnV-r4-zHo"/>
<constraint firstItem="iif-aq-YRM" firstAttribute="top" secondItem="CcB-Qz-GVQ" secondAttribute="bottom" constant="16" id="aVw-Hg-rj2"/>
<constraint firstAttribute="trailing" secondItem="Bpm-ml-r5G" secondAttribute="trailing" constant="16" id="dHo-XS-spi"/>
<constraint firstItem="iif-aq-YRM" firstAttribute="top" secondItem="CcB-Qz-GVQ" secondAttribute="bottom" constant="16" id="eQQ-8n-RTb"/>
<constraint firstItem="Bpm-ml-r5G" firstAttribute="leading" secondItem="mDG-e8-7zm" secondAttribute="trailing" constant="8" id="q6g-hi-JU0"/>
<constraint firstItem="KGF-p9-dfP" firstAttribute="top" secondItem="W48-CL-qfT" secondAttribute="bottom" constant="8" id="ryz-01-zR5"/>
<constraint firstItem="mDG-e8-7zm" firstAttribute="width" secondItem="DTM-os-yIa" secondAttribute="width" id="vU0-hF-uh6"/>
<constraint firstItem="mDG-e8-7zm" firstAttribute="leading" secondItem="xtZ-Fd-aXi" secondAttribute="leading" constant="16" id="xf0-dg-Axi"/>
<constraint firstAttribute="trailing" secondItem="c8d-5n-gpH" secondAttribute="trailing" constant="16" id="y8s-Qh-pox"/>
<constraint firstItem="mDG-e8-7zm" firstAttribute="width" secondItem="eCf-kK-soY" secondAttribute="width" id="yV8-24-HKj"/>
</constraints>
<variation key="default">
<mask key="constraints">
<exclude reference="NYH-PS-JOx"/>
<exclude reference="XOq-wM-TfU"/>
<exclude reference="eQQ-8n-RTb"/>
</mask>
</variation>
</view>
<connections>
<outlet property="baseRecordLabel" destination="c8d-5n-gpH" id="US0-en-TDT"/>
<outlet property="checkmarkButton" destination="55O-gs-uHQ" id="bSj-8e-8cW"/>
<outlet property="creationDateLabel" destination="Bpm-ml-r5G" id="1CY-TE-C3O"/>
<outlet property="lastModifiedLabel" destination="CcB-Qz-GVQ" id="99e-Ch-8we"/>
<outlet property="priority" destination="Hxe-hH-R2n" id="nM5-m6-p6q"/>
<outlet property="titleView" destination="KGF-p9-dfP" id="Xeh-fP-7tB"/>
<outlet property="titleViewHeightConstraint" destination="E9A-nT-yRh" id="ign-dE-WgA"/>
<outlet property="titleViewMaxHeightConstraint" destination="7Xn-vR-qit" id="gjI-EA-i3k"/>
<outlet property="titleViewMinHeightConstraint" destination="3Yb-Jy-Wnf" id="Ok2-0O-NlP"/>
<outlet property="uuidLabel" destination="WMm-Hf-0CA" id="wkX-1O-zgF"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="Ugd-z3-iNa" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1346" y="367"/>
</scene>
</scenes>
<resources>
<image name="checkmark-on.png" width="434" height="435"/>
</resources>
</document>

View File

@ -0,0 +1,69 @@
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@class CloudKitManager;
/**
* You can use this as an alternative to the sharedInstance:
* [[CloudKitManager sharedInstance] foobar] -> MyCloudKitManager.foobar
**/
extern CloudKitManager *MyCloudKitManager;
@interface CloudKitManager : NSObject
/**
* Standard singleton pattern.
* As a shortcut, you can use the global MyCloudKitManager ivar instead.
**/
+ (instancetype)sharedInstance; // Or MyCloudKitManager global ivar
/**
* Invoke me if you get one of the following errors via YapDatabaseCloudKitOperationErrorBlock:
* - CKErrorNetworkUnavailable
* - CKErrorNetworkFailure
**/
- (void)handleNetworkError;
/**
* Invoke me if you get one of the following errors via YapDatabaseCloudKitOperationErrorBlock:
* - CKErrorPartialFailure
**/
- (void)handlePartialFailure;
/**
* Invoke me if you get one of the following errors via YapDatabaseCloudKitOperationErrorBlock:
* - CKErrorNotAuthenticated
**/
- (void)handleNotAuthenticated;
/**
* This method uses CKFetchRecordChangesOperation to fetch changes.
* It continues fetching until it's reported that we're caught up.
*
* This method is invoked once automatically, when the CloudKitManager is initialized.
* After that, one should invoke it anytime a corresponding push notification is received.
**/
- (void)fetchRecordChangesWithCompletionHandler:
(void (^)(UIBackgroundFetchResult result, BOOL moreComing))completionHandler;
/**
* This method forces a re-fetch & merge operation.
* This can be handly for records that have already been fetched via CKFetchRecordChangesOperation,
* however we somehow managed to screw up merging the information into our local object(s).
*
* This is usually due to bugs in the data model implementation, or perhaps your YapDatabaseCloudKitMergeBlock.
* But bugs are a normal and expected part of development.
*
* For example:
* A few new propertie were added to our local object.
* We remembered to add these to the CKRecord(s) upon saving (so the new proerties got uploaded fine).
* But we forgot to update init method that sets the localObject.property from the new CKRecord.propertly. Oops!
* So now we have a few devices that have synced objects that are missing these properties.
*
* So rather than deleting & re-installing the app,
* we provide this method as a way to force another fetch & merge operation.
**/
- (void)refetchMissedRecordIDs:(NSArray *)recordIDs withCompletionHandler:(void (^)(NSError *error))completionHandler;
@end

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>aps-environment</key>
<string>development</string>
<key>com.apple.developer.icloud-container-identifiers</key>
<array>
<string>iCloud.$(CFBundleIdentifier)</string>
</array>
<key>com.apple.developer.icloud-services</key>
<array>
<string>CloudKit</string>
</array>
</dict>
</plist>

View File

@ -0,0 +1,95 @@
#import <Foundation/Foundation.h>
#import <YapDatabase/YapDatabase.h>
#import <YapDatabase/YapDatabaseAutoView.h>
#import <YapDatabase/YapDatabaseCloudKit.h>
@class DatabaseManager;
/**
* The following notifications are automatically posted for the uiDatabaseConnection:
*
* - UIDatabaseConnectionWillUpdateNotification
* - UIDatabaseConnectionDidUpdateNotification
*
* The notifications correspond with the longLivedReadTransaction of the uiDatabaseConnection.
* The DatabaseManager class listens for YapDatabaseModifiedNotification's.
*
* The UIDatabaseConnectionWillUpdateNotification is posted immediately before the uiDatabaseConnection
* is moved to the latest commit. And the UIDatabaseConnectionDidUpdateNotification is posted immediately after
* the uiDatabaseConnection was moved to the latest commit.
*
* These notifications are always posted to the main thread.
*
* The UIDatabaseConnectionDidUpdateNotification will always contain a userInfo dictionary with:
*
* - kNotificationsKey
* Contains the NSArray returned by [uiDatabaseConnection beginLongLivedReadTransaction].
* That is, the array of commit info from each commit the connection jumped.
* This is the information that is fed into the various YapDatabase API's to figure out what changed.
**/
extern NSString *const UIDatabaseConnectionWillUpdateNotification;
extern NSString *const UIDatabaseConnectionDidUpdateNotification;
extern NSString *const kNotificationsKey;
/**
* The following constants are the database collection names.
*
* E.g.: [transaction objectForKey:todoId inCollection:Collection_Todos]
**/
extern NSString *const Collection_Todos;
extern NSString *const Collection_CloudKit;
/**
* The following constants are the database extension names.
*
* E.g.: [[transaction ext:Ext_View_Order] objectAtIndexPath:indexPath withMappings:mappings]
**/
extern NSString *const Ext_View_Order;
extern NSString *const Ext_CloudKit;
/**
* The following constants are the CloudKit zone names.
**/
extern NSString *const CloudKitZoneName;
/**
* You can use this as an alternative to the sharedInstance:
* [[DatabaseManager sharedInstance] uiDatabaseConnection] -> STDatabaseManager.uiDatabaseConnection
**/
extern DatabaseManager *MyDatabaseManager;
@interface DatabaseManager : NSObject
/**
* Standard singleton pattern.
* As a shortcut, you can use the global MyDatabaseManager ivar instead.
**/
+ (instancetype)sharedInstance; // Or MyDatabaseManager global ivar
/**
* The path of the raw database file.
**/
+ (NSString *)databasePath;
/**
* The root database class, and extension(s)
**/
@property (nonatomic, strong, readonly) YapDatabase *database;
@property (nonatomic, strong, readonly) YapDatabaseCloudKit *cloudKitExtension;
/**
* The databaseConnection for the main thread.
* Will throw an exception if:
* - you attempt to use it on a background thread (as that would block a read on the main thread)
* - you attempt an async transaction (as that could also block a later read on the main thread)
**/
@property (nonatomic, strong, readonly) YapDatabaseConnection *uiDatabaseConnection;
/**
* A generic databaseConnection for other asynchronous & background stuff.
**/
@property (nonatomic, strong, readonly) YapDatabaseConnection *bgDatabaseConnection;
@end

View File

@ -0,0 +1,468 @@
#import "DatabaseManager.h"
#import "CloudKitManager.h"
#import "AppDelegate.h"
#import "MyDatabaseObject.h"
#import "MyTodo.h"
#import <CocoaLumberjack/CocoaLumberjack.h>
// Log Levels: off, error, warn, info, verbose
// Log Flags : trace
#if DEBUG
static const NSUInteger ddLogLevel = DDLogLevelAll;
#else
static const NSUInteger ddLogLevel = DDLogLevelAll;
#endif
NSString *const UIDatabaseConnectionWillUpdateNotification = @"UIDatabaseConnectionWillUpdateNotification";
NSString *const UIDatabaseConnectionDidUpdateNotification = @"UIDatabaseConnectionDidUpdateNotification";
NSString *const kNotificationsKey = @"notifications";
NSString *const Collection_Todos = @"todos";
NSString *const Collection_CloudKit = @"cloudKit";
NSString *const Ext_View_Order = @"order";
NSString *const Ext_CloudKit = @"ck";
NSString *const CloudKitZoneName = @"zone1";
DatabaseManager *MyDatabaseManager;
@implementation DatabaseManager
+ (void)initialize
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
MyDatabaseManager = [[DatabaseManager alloc] init];
});
}
+ (instancetype)sharedInstance
{
return MyDatabaseManager;
}
+ (NSString *)databasePath
{
NSString *databaseName = @"MyAwesomeApp.sqlite";
NSURL *baseURL = [[NSFileManager defaultManager] URLForDirectory:NSApplicationSupportDirectory
inDomain:NSUserDomainMask
appropriateForURL:nil
create:YES
error:NULL];
NSURL *databaseURL = [baseURL URLByAppendingPathComponent:databaseName isDirectory:NO];
return databaseURL.filePathURL.path;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark Instance
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@synthesize database = database;
@synthesize cloudKitExtension = cloudKitExtension;
@synthesize uiDatabaseConnection = uiDatabaseConnection;
@synthesize bgDatabaseConnection = bgDatabaseConnection;
- (id)init
{
NSAssert(MyDatabaseManager == nil, @"Must use sharedInstance singleton (global MyDatabaseManager)");
if ((self = [super init]))
{
[self setupDatabase];
}
return self;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark Setup
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- (YapDatabaseSerializer)databaseSerializer
{
// This is actually the default serializer.
// We just included it here for completeness.
YapDatabaseSerializer serializer = ^(NSString *collection, NSString *key, id object){
return [NSKeyedArchiver archivedDataWithRootObject:object];
};
return serializer;
}
- (YapDatabaseDeserializer)databaseDeserializer
{
// Pretty much the default serializer,
// but it also ensures that objects coming out of the database are immutable.
YapDatabaseDeserializer deserializer = ^(NSString *collection, NSString *key, NSData *data){
id object = [NSKeyedUnarchiver unarchiveObjectWithData:data];
if ([object isKindOfClass:[MyDatabaseObject class]])
{
[(MyDatabaseObject *)object makeImmutable];
}
return object;
};
return deserializer;
}
- (YapDatabasePreSanitizer)databasePreSanitizer
{
YapDatabasePreSanitizer preSanitizer = ^(NSString *collection, NSString *key, id object){
if ([object isKindOfClass:[MyDatabaseObject class]])
{
[object makeImmutable];
}
return object;
};
return preSanitizer;
}
- (YapDatabasePostSanitizer)databasePostSanitizer
{
YapDatabasePostSanitizer postSanitizer = ^(NSString *collection, NSString *key, id object){
if ([object isKindOfClass:[MyDatabaseObject class]])
{
[object clearChangedProperties];
}
};
return postSanitizer;
}
- (void)setupDatabase
{
NSString *databasePath = [[self class] databasePath];
DDLogVerbose(@"databasePath: %@", databasePath);
// Configure custom class mappings for NSCoding.
// In a previous version of the app, the "MyTodo" class was named "MyTodoItem".
// We renamed the class in a recent version.
[NSKeyedUnarchiver setClass:[MyTodo class] forClassName:@"MyTodoItem"];
// Create the database
database = [[YapDatabase alloc] initWithPath:databasePath
serializer:[self databaseSerializer]
deserializer:[self databaseDeserializer]
preSanitizer:[self databasePreSanitizer]
postSanitizer:[self databasePostSanitizer]
options:nil];
// FOR ADVANCED USERS ONLY
//
// Do NOT copy this blindly into your app unless you know exactly what you're doing.
// https://github.com/yapstudios/YapDatabase/wiki/Object-Policy
//
database.defaultObjectPolicy = YapDatabasePolicyShare;
database.defaultMetadataPolicy = YapDatabasePolicyShare;
//
// ^^^ FOR ADVANCED USERS ONLY ^^^
// Setup the extensions
[self setupOrderViewExtension];
[self setupCloudKitExtension];
// Setup database connection(s)
uiDatabaseConnection = [database newConnection];
uiDatabaseConnection.objectCacheLimit = 400;
uiDatabaseConnection.metadataCacheEnabled = NO;
#if YapDatabaseEnforcePermittedTransactions
uiDatabaseConnection.permittedTransactions = YDB_SyncReadTransaction | YDB_MainThreadOnly;
#endif
bgDatabaseConnection = [database newConnection];
bgDatabaseConnection.objectCacheLimit = 400;
bgDatabaseConnection.metadataCacheEnabled = NO;
// Start the longLivedReadTransaction on the UI connection.
[uiDatabaseConnection enableExceptionsForImplicitlyEndingLongLivedReadTransaction];
[uiDatabaseConnection beginLongLivedReadTransaction];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(yapDatabaseModified:)
name:YapDatabaseModifiedNotification
object:database];
}
- (void)setupOrderViewExtension
{
//
// What is a YapDatabaseView ?
//
// https://github.com/yapstudios/YapDatabase/wiki/Views
//
// > If you're familiar with Core Data, it's kinda like a NSFetchedResultsController.
// > But you should really read that wiki article, or you're likely to be a bit confused.
//
//
// This view keeps a persistent "list" of MyTodo items sorted by timestamp.
// We use it to drive the tableView.
//
YapDatabaseViewGrouping *orderGrouping = [YapDatabaseViewGrouping withObjectBlock:
^NSString *(YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key, id object)
{
if ([object isKindOfClass:[MyTodo class]])
{
return @""; // include in view
}
return nil; // exclude from view
}];
YapDatabaseViewSorting *orderSorting = [YapDatabaseViewSorting withObjectBlock:
^(YapDatabaseReadTransaction *transaction, NSString *group,
NSString *collection1, NSString *key1, MyTodo *todo1,
NSString *collection2, NSString *key2, MyTodo *todo2)
{
// We want:
// - Most recently created Todo at index 0.
// - Least recent created Todo at the end.
//
// This is descending order (opposite of "standard" in Cocoa) so we swap the normal comparison.
NSComparisonResult cmp = [todo1.creationDate compare:todo2.creationDate];
if (cmp == NSOrderedAscending) return NSOrderedDescending;
if (cmp == NSOrderedDescending) return NSOrderedAscending;
return NSOrderedSame;
}];
YapDatabaseAutoView *orderView =
[[YapDatabaseAutoView alloc] initWithGrouping:orderGrouping
sorting:orderSorting
versionTag:@"sortedByCreationDate"];
[database asyncRegisterExtension:orderView withName:Ext_View_Order completionBlock:^(BOOL ready) {
if (!ready) {
DDLogError(@"Error registering %@ !!!", Ext_View_Order);
}
}];
}
- (void)setupCloudKitExtension
{
YapDatabaseCloudKitRecordHandler *recordHandler = [YapDatabaseCloudKitRecordHandler withObjectBlock:
^(YapDatabaseReadTransaction *transaction, CKRecord *__autoreleasing *inOutRecordPtr,
YDBCKRecordInfo *recordInfo, NSString *collection, NSString *key, MyTodo *todo)
{
CKRecord *record = inOutRecordPtr ? *inOutRecordPtr : nil;
if (record && // not a newly inserted object
!todo.hasChangedCloudProperties && // no sync'd properties changed in the todo
!recordInfo.keysToRestore ) // and we don't need to restore "truth" values
{
// Thus we don't have any changes we need to push to the cloud
return;
}
// The CKRecord will be nil when we first insert an object into the database.
// Or if we've never included this item for syncing before.
//
// Otherwise we'll be handed a bare CKRecord, with only the proper CKRecordID
// and the sync metadata set.
BOOL isNewRecord = NO;
if (record == nil)
{
CKRecordZoneID *zoneID =
[[CKRecordZoneID alloc] initWithZoneName:CloudKitZoneName ownerName:CKCurrentUserDefaultName];
CKRecordID *recordID = [[CKRecordID alloc] initWithRecordName:todo.uuid zoneID:zoneID];
record = [[CKRecord alloc] initWithRecordType:@"todo" recordID:recordID];
*inOutRecordPtr = record;
isNewRecord = YES;
}
id <NSFastEnumeration> cloudKeys = nil;
if (recordInfo.keysToRestore)
{
// We need to restore "truth" values for YapDatabaseCloudKit.
// This happens when the extension is restarted,
// and it needs to restore its change-set queue (to pick up where it left off).
cloudKeys = recordInfo.keysToRestore;
}
else if (isNewRecord)
{
// This is a CKRecord for a newly inserted todo item.
// So we want to get every single property,
// including those that are read-only, and may have been set directly via the init method.
cloudKeys = todo.allCloudProperties;
}
else
{
// We changed one or more properties of our Todo item.
// So we need to copy only these changed values into the CKRecord.
// That way YapDatabaseCloudKit can handle syncing it to the cloud.
cloudKeys = todo.changedCloudProperties;
// We can also instruct YapDatabaseCloudKit to store the originalValues for us.
// This is optional, but comes in handy if we run into conflicts.
recordInfo.originalValues = todo.originalCloudValues;
}
for (NSString *cloudKey in cloudKeys)
{
id cloudValue = [todo cloudValueForCloudKey:cloudKey];
[record setObject:cloudValue forKey:cloudKey];
}
}];
YapDatabaseCloudKitMergeBlock mergeBlock =
^(YapDatabaseReadWriteTransaction *transaction, NSString *collection, NSString *key,
CKRecord *remoteRecord, YDBCKMergeInfo *mergeInfo)
{
if ([remoteRecord.recordType isEqualToString:@"todo"])
{
MyTodo *todo = [transaction objectForKey:key inCollection:collection];
todo = [todo copy]; // make mutable copy
// CloudKit doesn't tell us exactly what changed.
// We're just being given the latest version of the CKRecord.
// So it's up to us to figure out what changed.
NSArray *allKeys = remoteRecord.allKeys;
NSMutableArray *remoteChangedKeys = [NSMutableArray arrayWithCapacity:allKeys.count];
for (NSString *key in allKeys)
{
id remoteValue = [remoteRecord objectForKey:key];
id localValue = [todo cloudValueForCloudKey:key];
if (![remoteValue isEqual:localValue])
{
id originalLocalValue = [mergeInfo.originalValues objectForKey:key];
if (![remoteValue isEqual:originalLocalValue])
{
[remoteChangedKeys addObject:key];
}
}
}
NSMutableSet *localChangedKeys = [NSMutableSet setWithArray:mergeInfo.pendingLocalRecord.changedKeys];
for (NSString *remoteChangedKey in remoteChangedKeys)
{
id remoteChangedValue = [remoteRecord valueForKey:remoteChangedKey];
[todo setLocalValueFromCloudValue:remoteChangedValue forCloudKey:remoteChangedKey];
[localChangedKeys removeObject:remoteChangedKey];
}
for (NSString *localChangedKey in localChangedKeys)
{
id localChangedValue = [mergeInfo.pendingLocalRecord valueForKey:localChangedKey];
[mergeInfo.updatedPendingLocalRecord setObject:localChangedValue forKey:localChangedKey];
}
[transaction setObject:todo forKey:key inCollection:collection];
}
};
YapDatabaseCloudKitOperationErrorBlock opErrorBlock =
^(NSString *databaseIdentifier, NSError *operationError)
{
NSInteger ckErrorCode = operationError.code;
if (ckErrorCode == CKErrorNetworkUnavailable ||
ckErrorCode == CKErrorNetworkFailure )
{
[MyCloudKitManager handleNetworkError];
}
else if (ckErrorCode == CKErrorPartialFailure)
{
[MyCloudKitManager handlePartialFailure];
}
else if (ckErrorCode == CKErrorNotAuthenticated)
{
[MyCloudKitManager handleNotAuthenticated];
}
else
{
// You'll want to add more error handling here.
DDLogError(@"Unhandled ckErrorCode: %ld", (long)ckErrorCode);
}
};
NSSet *todos = [NSSet setWithObject:Collection_Todos];
YapWhitelistBlacklist *whitelist = [[YapWhitelistBlacklist alloc] initWithWhitelist:todos];
YapDatabaseCloudKitOptions *options = [[YapDatabaseCloudKitOptions alloc] init];
options.allowedCollections = whitelist;
cloudKitExtension = [[YapDatabaseCloudKit alloc] initWithRecordHandler:recordHandler
mergeBlock:mergeBlock
operationErrorBlock:opErrorBlock
versionTag:@"1"
versionInfo:nil
options:options];
[cloudKitExtension suspend]; // Create zone(s)
[cloudKitExtension suspend]; // Create zone subscription(s)
[cloudKitExtension suspend]; // Initial fetchRecordChanges operation
[database asyncRegisterExtension:cloudKitExtension withName:Ext_CloudKit completionBlock:^(BOOL ready) {
if (!ready) {
DDLogError(@"Error registering %@ !!!", Ext_CloudKit);
}
}];
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark Notifications
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- (void)yapDatabaseModified:(NSNotification *)ignored
{
// Notify observers we're about to update the database connection
[[NSNotificationCenter defaultCenter] postNotificationName:UIDatabaseConnectionWillUpdateNotification
object:self];
// Move uiDatabaseConnection to the latest commit.
// Do so atomically, and fetch all the notifications for each commit we jump.
NSArray *notifications = [uiDatabaseConnection beginLongLivedReadTransaction];
// Notify observers that the uiDatabaseConnection was updated
NSDictionary *userInfo = @{
kNotificationsKey : notifications,
};
[[NSNotificationCenter defaultCenter] postNotificationName:UIDatabaseConnectionDidUpdateNotification
object:self
userInfo:userInfo];
}
@end

View File

@ -0,0 +1,24 @@
#import <UIKit/UIKit.h>
#import "TodoTextView.h"
@interface EditViewController : UIViewController <UITextViewDelegate>
@property (nonatomic, strong, readwrite) NSString *todoID;
@property (nonatomic, weak) IBOutlet TodoTextView *titleView;
@property (nonatomic, weak) IBOutlet NSLayoutConstraint *titleViewHeightConstraint;
@property (nonatomic, weak) IBOutlet NSLayoutConstraint *titleViewMinHeightConstraint;
@property (nonatomic, weak) IBOutlet NSLayoutConstraint *titleViewMaxHeightConstraint;
@property (nonatomic, weak) IBOutlet UIButton *checkmarkButton;
@property (nonatomic, weak) IBOutlet UISegmentedControl *priority;
@property (nonatomic, weak) IBOutlet UILabel *uuidLabel;
@property (nonatomic, weak) IBOutlet UILabel *creationDateLabel;
@property (nonatomic, weak) IBOutlet UILabel *lastModifiedLabel;
@property (nonatomic, weak) IBOutlet UILabel *baseRecordLabel;
@end

View File

@ -0,0 +1,274 @@
#import "EditViewController.h"
#import "DatabaseManager.h"
#import "MyTodo.h"
@implementation EditViewController
{
YapDatabaseConnection *databaseConnection;
}
@synthesize todoID = todoID;
@synthesize titleView = titleView;
@synthesize titleViewHeightConstraint = titleViewHeightConstraint;
@synthesize titleViewMinHeightConstraint = titleViewMinHeightConstraint;
@synthesize titleViewMaxHeightConstraint = titleViewMaxHeightConstraint;
@synthesize checkmarkButton = checkmarkButton;
@synthesize priority = priority;
@synthesize uuidLabel = uuidLabel;
@synthesize creationDateLabel = creationDateLabel;
@synthesize lastModifiedLabel = lastModifiedLabel;
@synthesize baseRecordLabel = baseRecordLabel;
- (void)viewDidLoad
{
[super viewDidLoad];
titleView.textColor = [UIColor colorWithRed:0.1 green:0.1 blue:0.1 alpha:1.0];
titleView.layer.borderColor = [UIColor colorWithRed:0.9 green:0.9 blue:0.9 alpha:1.0].CGColor;
titleView.layer.borderWidth = 1.75;
titleView.layer.cornerRadius = 5.5;
titleView.delegate = self;
UIEdgeInsets modifiedInsets = titleView.textContainerInset;
modifiedInsets.top -= 2;
modifiedInsets.bottom -= 2;
titleView.textContainerInset = modifiedInsets;
self.navigationItem.leftBarButtonItem =
[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel
target:self
action:@selector(cancelButtonTapped:)];
self.navigationItem.rightBarButtonItem =
[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemSave
target:self
action:@selector(saveButtonTapped:)];
databaseConnection = MyDatabaseManager.uiDatabaseConnection;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(databaseConnectionDidUpdate:)
name:UIDatabaseConnectionDidUpdateNotification
object:nil];
[self updateView];
}
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
dispatch_async(dispatch_get_main_queue(), ^{
[self textViewDidChange:titleView];
});
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[titleView becomeFirstResponder];
}
- (void)setTodoID:(NSString *)newTodoID
{
todoID = newTodoID;
if (self.isViewLoaded) {
[self updateView];
}
}
- (void)databaseConnectionDidUpdate:(NSNotification *)notification
{
NSArray *notifications = [notification.userInfo objectForKey:kNotificationsKey];
if ([databaseConnection hasChangeForKey:todoID inCollection:Collection_Todos inNotifications:notifications])
{
[self updateView];
}
}
- (void)updateView
{
__block MyTodo *todo = nil;
__block CKRecord *record = nil;
if (todoID)
{
[databaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
todo = [transaction objectForKey:todoID inCollection:Collection_Todos];
record = [[transaction ext:Ext_CloudKit] recordForKey:todoID inCollection:Collection_Todos];
}];
}
if (todo)
{
titleView.text = todo.title;
if (todo.isDone)
{
checkmarkButton.tag = 1;
[checkmarkButton setImage:[UIImage imageNamed:@"checkmark-on"] forState:UIControlStateNormal];
}
else
{
checkmarkButton.tag = 0;
[checkmarkButton setImage:[UIImage imageNamed:@"checkmark-off"] forState:UIControlStateNormal];
}
if (todo.priority == TodoPriorityLow)
priority.selectedSegmentIndex = 0;
else if (todo.priority == TodoPriorityHigh)
priority.selectedSegmentIndex = 2;
else
priority.selectedSegmentIndex = 1;
uuidLabel.text = todo.uuid;
NSDateFormatter *df = [[NSDateFormatter alloc] init];
df.dateStyle = NSDateFormatterMediumStyle;
df.timeStyle = NSDateFormatterMediumStyle;
creationDateLabel.text = [df stringFromDate:todo.creationDate];
lastModifiedLabel.text = [df stringFromDate:todo.lastModified];
baseRecordLabel.text = [record description];
}
else
{
titleView.text = nil;
checkmarkButton.tag = 0;
[checkmarkButton setImage:[UIImage imageNamed:@"checkmark-off"] forState:UIControlStateNormal];
priority.selectedSegmentIndex = 1;
uuidLabel.text = [[NSUUID UUID] UUIDString];
creationDateLabel.text = @"<now>";
lastModifiedLabel.text = @"<now>";
baseRecordLabel.text = @"<New CKRecord>";
}
if (self.isViewLoaded) {
[self textViewDidChange:titleView];
}
}
- (IBAction)checkmarkButtonTapped:(id)sender
{
if (checkmarkButton.tag == 1)
{
checkmarkButton.tag = 0;
[checkmarkButton setImage:[UIImage imageNamed:@"checkmark-off"] forState:UIControlStateNormal];
}
else
{
checkmarkButton.tag = 1;
[checkmarkButton setImage:[UIImage imageNamed:@"checkmark-on"] forState:UIControlStateNormal];
}
}
- (void)cancelButtonTapped:(id)sender
{
[self.navigationController popViewControllerAnimated:YES];
}
- (void)saveButtonTapped:(id)sender
{
NSString *newTitle = titleView.text;
BOOL newIsDone = (checkmarkButton.tag == 1);
TodoPriority newPriority;
if (priority.selectedSegmentIndex == 0)
newPriority = TodoPriorityLow;
else if (priority.selectedSegmentIndex == 2)
newPriority = TodoPriorityHigh;
else
newPriority = TodoPriorityNormal;
[MyDatabaseManager.bgDatabaseConnection asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
MyTodo *todo = [transaction objectForKey:todoID inCollection:Collection_Todos];
if (todo == nil)
{
todo = [[MyTodo alloc] initWithUUID:uuidLabel.text];
todo.title = newTitle;
todo.isDone = newIsDone;
todo.priority = newPriority;
[transaction setObject:todo forKey:todo.uuid inCollection:Collection_Todos];
}
else
{
todo = [todo copy]; // mutable copy
// If the user didn't effectively make any changes,
// we're going to try to avoid updating the properties.
// Which, in turn, avoids uploading unchanged properties.
if (![todo.title isEqualToString:newTitle]) {
todo.title = newTitle;
}
if (todo.isDone != newIsDone) {
todo.isDone = newIsDone;
}
if (todo.priority != newPriority) {
todo.priority = newPriority;
}
if (todo.hasChangedProperties)
{
todo.lastModified = [NSDate date];
[transaction setObject:todo forKey:todo.uuid inCollection:Collection_Todos];
}
}
}];
[self.navigationController popViewControllerAnimated:YES];
}
- (void)textViewDidChange:(UITextView *)sender
{
CGFloat intrinsicHeight = [titleView intrinsicContentSize].height;
CGFloat currentHeight = titleView.frame.size.height;
BOOL needsUpdate = NO;
if (intrinsicHeight != currentHeight)
{
if ((intrinsicHeight > currentHeight) && (currentHeight != titleViewMaxHeightConstraint.constant))
{
needsUpdate = YES;
}
if ((intrinsicHeight < currentHeight) && (currentHeight != titleViewMinHeightConstraint.constant))
{
needsUpdate = YES;
}
}
if (needsUpdate)
{
[UIView animateWithDuration:0.1 animations:^{
titleView.needsScrollIfNeeded = YES;
[titleView invalidateIntrinsicContentSize];
[self.view layoutIfNeeded];
}];
}
}
@end

View File

@ -0,0 +1,98 @@
{
"images" : [
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "3x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "83.5x83.5",
"scale" : "2x"
},
{
"idiom" : "ios-marketing",
"size" : "1024x1024",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIBackgroundModes</key>
<array>
<string>remote-notification</string>
</array>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>

View File

@ -0,0 +1,152 @@
#import <Foundation/Foundation.h>
/**
* This is an example base class that demonstrates certain concepts you'll likely find useful when using YapDatabase.
*
* **** You do NOT have to use this base class. ****
*
* If you thought, for a moment, that YapDatabase enforces a base class like NSManagedObject (gag)
* please banish that thought from your mind now.
*
* Truth be told, YapDatabase doesn't care what your objects look like.
* Just so long as you're able to properly serialize & deserialize them.
* Which means that you're more than welcome to use plain old NSObject subclasses.
* Or maybe even an open source project like one of these:
*
* - https://github.com/Mantle/Mantle
* - https://github.com/nicklockwood/FastCoding
*
* It's completely up to you!
*
* That being said, I think you'll find some of the concepts demonstrated here to be useful.
* So feel free to copy & modify anything in this class. Meld it to fit your needs.
* Maybe you'll even merge some of the concepts in this class with other popular open source projects
* to create your own super base class. :)
*
* ***** Concept #1 *****
*
* With a highly concurrent database (like YapDatabase), thread-safety becomes important.
* But you don't want thread-safety to become burdensome. What you really want is something so simple and
* straight-forward that you don't have to think about it (yet it's automatically thread-safe).
*
* I touch on several thread-safety issues in the "Thread Safety" wiki article:
* https://github.com/yapstudios/YapDatabase/wiki/Thread-Safety
*
* But you can make life really easy on yourself if you use immutable objects.
* Of course, you must be thinking, "easier said than done" right?
* Or perhaps "that sounds like a pain in the ass"?
*
* Surprisingly, it only takes a few lines of code!
* I explain the concept in depth here (along with a bonus performance improvement you can get from it):
* https://github.com/yapstudios/YapDatabase/wiki/Object-Policy
*
* But here's a 10,000 foot summary:
* - Your model objects extend this one (or you rip off this class - feel free)
* - You simply call [object makeImmutable]
* - Voilà, you've got yourself an immutable thread-safe object,
* ready to go in the database and be passed around from thread-to-thread like a ... well behaved object.
*
* ***** Concept #2 *****
*
* Tracking which properties of an object have been changed.
*
* This has a variety of useful applications.
* You can use it distinguish UI fields which have been changed.
* Or to mark a window as dirty when the corresponding object has unsaved changes.
*
* It can also simplify code by allowing you to directly pass an object to another method for mutation.
* And the caller can simply check the object afterwards to see if it needs to be saved.
*
* ***** Concept #3 *****
*
* Syncing the object with a cloud-based service.
*
* There are often differences between the object that you store locally, and the object that's stored in the cloud.
* For example:
*
* - Locally you store a UIColor object, but in the cloud you store a string (r,g,b,a)
* - Locally your variable is named 'isComplete', but in the cloud it's unfortunately misspelled as 'isCompete'.
*
* These changes accumulate over time.
* And this class provides several easy techniques to provide easy mapping between local & remote (keys/values).
*
* This technique is recommended for the YapDatabaseCloudKit extension:
* https://github.com/yapstudios/YapDatabase/wiki/YapDatabaseCloudKit
**/
@interface MyDatabaseObject : NSObject <NSCopying>
#pragma mark Class configuration
+ (NSMutableSet *)monitoredProperties;
@property (nonatomic, readonly) NSSet *monitoredProperties;
+ (NSMutableDictionary *)mappings_localKeyToCloudKey;
@property (nonatomic, readonly) NSDictionary *mappings_localKeyToCloudKey;
+ (NSMutableDictionary *)mappings_cloudKeyToLocalKey;
@property (nonatomic, readonly) NSDictionary *mappings_cloudKeyToLocalKey;
+ (BOOL)storesOriginalCloudValues;
#pragma mark Immutability
@property (nonatomic, readonly) BOOL isImmutable;
- (void)makeImmutable;
- (NSException *)immutableExceptionForKey:(NSString *)key;
#pragma mark Monitoring (local)
@property (nonatomic, readonly) NSSet *changedProperties;
@property (nonatomic, readonly) BOOL hasChangedProperties;
- (void)clearChangedProperties;
#pragma mark Monitoring (cloud)
@property (nonatomic, readonly) NSSet *allCloudProperties;
@property (nonatomic, readonly) NSSet *changedCloudProperties;
@property (nonatomic, readonly) BOOL hasChangedCloudProperties;
@property (nonatomic, readonly) NSDictionary *originalCloudValues;
#pragma mark Getters & Setters (cloud)
- (NSString *)cloudKeyForLocalKey:(NSString *)localKey;
- (NSString *)localKeyForCloudKey:(NSString *)cloudKey;
- (id)cloudValueForCloudKey:(NSString *)key;
- (id)cloudValueForLocalKey:(NSString *)key;
- (id)localValueForCloudKey:(NSString *)key;
- (id)localValueForLocalKey:(NSString *)key;
- (void)setLocalValueFromCloudValue:(id)cloudValue forCloudKey:(NSString *)cloudKey;
/**
* You can use this macro WITHIN SUBCLASSES to fetch the CloudKey for a given property.
* For example, say your class is configured with the following mappings_localKeyToCloudKey:
* @{ @"uuid" : @"uuid"
* @"foo" : @"bar"
* }
*
* Then:
* - CloudKey(uuid) => [self.mappings_localKeyToCloudKey objectForKey:@"uuid"] => @"uuid"
* - CloudKey(foo) => [self.mappings_localKeyToCloudKey objectForKey:@"foo"] => @"bar"
*
* If using Apple's CloudKit framework,
* then this macro returns the name of the corresponding property within the CKRecord.
**/
#define CloudKey(ivar) [self.mappings_localKeyToCloudKey objectForKey:@"" # ivar]
// translation ==> [self.mappings_localKeyToCloudKey objectForKey:@"ivar"]
@end

View File

@ -0,0 +1,585 @@
#import "MyDatabaseObject.h"
#import <objc/runtime.h>
@implementation MyDatabaseObject {
@private
BOOL isImmutable;
NSMutableSet *changedProperties;
NSMutableDictionary *originalCloudValues;
}
/**
* Make sure all your subclasses call this method ([super init]).
**/
- (instancetype)init
{
if ((self = [super init]))
{
// Turn on KVO for object.
// We do this so we can get notified if the user is about to make changes to one of the object's properties.
//
// Don't worry, this doesn't create a retain cycle.
[self addObserver:self forKeyPath:@"isImmutable" options:0 context:NULL];
if ([[self class] storesOriginalCloudValues]) {
originalCloudValues = [[NSMutableDictionary alloc] init];
}
}
return self;
}
- (void)dealloc
{
[self removeObserver:self forKeyPath:@"isImmutable" context:NULL];
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark NSCopying
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* In this example, all copies are automatically mutable.
* So all you have to do in your code is something like this:
*
* [databaseConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction]{
*
* Car *car = [transaction objectForKey:carId inCollection:@"cars"];
* car = [car copy]; // make mutable copy
* car.speed = newSpeed;
*
* [transaction setObject:car forKey:carId inCollection:@"cars"];
* }];
*
* Which means all you have to do is implement the copyWithZone method in your model classes.
**/
- (id)copyWithZone:(NSZone *)zone
{
// Subclasses should call this method via [super copyWithZone:zone].
// For example:
//
// MySubclass *copy = [super copyWithZone:zone];
// copy->ivar1 = [ivar1 copy];
// copy->ivar2 = ivar2;
// return copy;
MyDatabaseObject *copy = [[[self class] alloc] init];
copy->isImmutable = NO;
copy->changedProperties = [self->changedProperties mutableCopy];
copy->originalCloudValues = [self->originalCloudValues mutableCopy];
return copy;
}
/**
* An alternative is to have [object copy] return an immutable copy,
* and [object mutableCopy] to return a mutable copy.
*
* Some people prefer it like this. If so then:
* - uncomment this method
* - change 'copy->isImmutable = NO' to 'copy->isImmutable = YES' in copyWithZone
* - and add NSMutableCopying to the list of protocols in the header file
*
* Note: The implemenation below just uses a regular copy, and then sets the isImmutable flag to NO.
* So if you go this route, you don't have to implement mutableCopyWithZone (just copyWithZone).
**/
//- (instancetype)mutableCopyWithZone:(NSZone *)zone
//{
// MyDatabaseObject *copy = [self copy];
// copy->isImmutable = NO;
//
// return copy;
//}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark Class Configuration
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* This method returns a list of all properties that should be monitored.
* That is, these properties should show up in the changedProperties set if they are modified.
* And they should be considered immutable once the makeImmutable method has been invoked.
*
* By default this method returns a list of all properties in each subclass in the
* hierarchy leading to "[self class]".
*
* However, this is not always exactly what you want.
* For example, you may have properties which are simply used for caching:
*
* @property (nonatomic, strong, readwrite) UIImage *avatarImage;
* @property (nonatomic, strong, readwrite) UIImage *cachedTransformedAvatarImage;
*
* In this example, you store the user's plain avatar image.
* However, your code transforms the avatar in various ways for display in the UI.
* So to reduce overhead, you'd like to cache these transformed images in the user object.
* Thus the 'cachedTransformedAvatarImage' property doesn't actually mutate the user object. It's just a temp cache.
*
* So your subclass would override this method like so:
*
* + (NSMutableSet *)monitoredProperties
* {
* NSMutableSet *monitoredProperties = [super immutableProperties];
* [monitoredProperties removeObject:@"cachedTransformedAvatarImage"];
*
* return monitoredProperties;
* }
**/
+ (NSMutableSet *)monitoredProperties
{
// Steps to override me (if needed):
//
// - Invoke [super monitoredProperties]
// - Modify resulting mutable set
// - Return modified set
NSMutableSet *properties = nil;
Class rootClass = [MyDatabaseObject class];
Class subClass = [self class];
while (subClass != rootClass)
{
unsigned int count = 0;
objc_property_t *propertyList = class_copyPropertyList(subClass, &count);
if (propertyList)
{
if (properties == nil)
properties = [NSMutableSet setWithCapacity:count];
for (unsigned int i = 0; i < count; i++)
{
const char *name = property_getName(propertyList[i]);
NSString *property = [NSString stringWithUTF8String:name];
[properties addObject:property];
}
free(propertyList);
}
subClass = [subClass superclass];
}
return properties;
}
/**
* Generally you should NOT override this method.
* Just override the class version of this method (above).
**/
- (NSSet *)monitoredProperties
{
NSSet *cached = objc_getAssociatedObject([self class], _cmd);
if (cached) return cached;
NSSet *monitoredProperties = [[[self class] monitoredProperties] copy];
objc_setAssociatedObject([self class], _cmd, monitoredProperties, OBJC_ASSOCIATION_RETAIN);
return monitoredProperties;
}
/**
* This method returns a mapping from localPropertyName to cloudPropertyName.
*
* By default this method returns a dictionary including everything in [self monitoredProperties],
* where the key is equal to the value for every item.
*
* For example:
* @{ @"title" : @"title",
* @"isComplete" : @"isComplete",
* @"creationDate" : @"creationDate",
* @"lastModified" : @"lastModified",
* @"isSeen" : @"isSeen"
* }
*
* However, this is not always exactly what you want.
* For example, you may not want to sync the 'isSeen' property because it's device-specific.
*
* Additionally you discover that CKRecord has a built-in creationDate property,
* and so CKRecord doesn't allow you to use that key for your own purposes. (It's reserved.)
*
* You can still name your own property "creationDate",
* but you'll be forced to use a different name for the CKRecord.
* So let's say we decide to use "created" as the corresponding key in the CKRecord.
*
* Thus your subclass overrides this method like so:
*
* + (NSMutableDictionary *)mappings_localKeyToCloudKey
* {
* NSMutableDictionary *mappings_localKeyToCloudKey = [super mappings_localKeyToCloudKey];
*
* [mappings_localKeyToCloudKey removeObjectForKey:@"isSeen"];
* [mappings_localKeyToCloudKey setObject:@"created" forKey:@"creationDate"];
*
* return mappings_localKeyToCloudKey;
* }
**/
+ (NSMutableDictionary *)mappings_localKeyToCloudKey
{
// Steps to override me (if needed):
//
// - Invoke [super mappings_localKeyToCloudKey]
// - Modify resulting mutable dictionary
// - Return modified dictionary
NSMutableSet *properties = [self monitoredProperties];
NSMutableDictionary *mappings_localKeyToCloudKey = [NSMutableDictionary dictionaryWithCapacity:properties.count];
for (NSString *propertyName in properties)
{
[mappings_localKeyToCloudKey setObject:propertyName forKey:propertyName];
}
return mappings_localKeyToCloudKey;
}
/**
* Generally you should NOT override this method.
* Just override the class version of this method (above).
**/
- (NSDictionary *)mappings_localKeyToCloudKey
{
NSDictionary *cached = objc_getAssociatedObject([self class], _cmd);
if (cached) return cached;
NSDictionary *mappings_localKeyToCloudKey = [[[self class] mappings_localKeyToCloudKey] copy];
objc_setAssociatedObject([self class], _cmd, mappings_localKeyToCloudKey, OBJC_ASSOCIATION_RETAIN);
return mappings_localKeyToCloudKey;
}
/**
* This method is the inverse of mappings_localKeyToCloudKey.
* There is generally no need to override this method.
**/
+ (NSMutableDictionary *)mappings_cloudKeyToLocalKey
{
NSMutableDictionary *mappings_localKeyToCloudKey = [self mappings_localKeyToCloudKey];
NSUInteger capacity = mappings_localKeyToCloudKey.count;
NSMutableDictionary *mappings_cloudKeyToLocalKey = [NSMutableDictionary dictionaryWithCapacity:capacity];
[mappings_localKeyToCloudKey enumerateKeysAndObjectsUsingBlock:^(id localKey, id cloudKey, BOOL *stop) {
mappings_cloudKeyToLocalKey[cloudKey] = localKey;
}];
return mappings_cloudKeyToLocalKey;
}
/**
* There is generally no need to override this method.
**/
- (NSDictionary *)mappings_cloudKeyToLocalKey
{
NSDictionary *cached = objc_getAssociatedObject([self class], _cmd);
if (cached) return cached;
NSDictionary *mappings_cloudKeyToLocalKey = [[[self class] mappings_cloudKeyToLocalKey] copy];
objc_setAssociatedObject([self class], _cmd, mappings_cloudKeyToLocalKey, OBJC_ASSOCIATION_RETAIN);
return mappings_cloudKeyToLocalKey;
}
/**
* If storesOriginalCloudValues is enabled, then in addition to monitoring which properties change,
* the object will also keep a dictionary of the original cloudValues that have changed.
*
* This is disabled by default.
* So you'll need to "opt-in" for those classes where you want this feature.
**/
+ (BOOL)storesOriginalCloudValues
{
// Override me (and return YES), if you want to store originalCloudValues.
// These are cleared when clearChangedProperties is invoked.
return NO;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark Immutability
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@synthesize isImmutable = isImmutable;
- (void)makeImmutable
{
if (!isImmutable)
{
// Set immutable flag
isImmutable = YES;
}
}
- (NSException *)immutableExceptionForKey:(NSString *)key
{
NSString *reason;
if (key)
reason = [NSString stringWithFormat:
@"Attempting to mutate immutable object. Class = %@, property = %@", NSStringFromClass([self class]), key];
else
reason = [NSString stringWithFormat:
@"Attempting to mutate immutable object. Class = %@", NSStringFromClass([self class])];
NSDictionary *userInfo = @{ NSLocalizedRecoverySuggestionErrorKey:
@"To make modifications you should create a copy via [object copy]."
@" You may then make changes to the copy before saving it back to the database."};
return [NSException exceptionWithName:@"STDatabaseObjectException" reason:reason userInfo:userInfo];
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark Monitoring (local)
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- (NSSet *)changedProperties
{
if ([changedProperties count] == 0) return nil;
// Remove untracked properties from the list.
[changedProperties intersectSet:[self monitoredProperties]];
// And return immutable copy
return [changedProperties copy];
}
- (BOOL)hasChangedProperties
{
return ([changedProperties count] > 0);
}
- (void)clearChangedProperties
{
changedProperties = nil;
[originalCloudValues removeAllObjects];
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark Monitoring (cloud)
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- (NSSet *)allCloudProperties
{
NSSet *cached = objc_getAssociatedObject([self class], _cmd);
if (cached) return cached;
NSDictionary *mappings_localKeyToCloudKey = self.mappings_localKeyToCloudKey;
NSUInteger capacity = mappings_localKeyToCloudKey.count;
NSMutableSet *allCloudProperties = [NSMutableSet setWithCapacity:capacity];
for (NSString *cloudKey in [mappings_localKeyToCloudKey objectEnumerator])
{
[allCloudProperties addObject:cloudKey];
}
NSSet *result = [allCloudProperties copy];
objc_setAssociatedObject([self class], _cmd, result, OBJC_ASSOCIATION_RETAIN);
return result;
}
- (NSSet *)changedCloudProperties
{
if ([changedProperties count] == 0) return nil;
NSMutableSet *changedCloudProperties = [NSMutableSet setWithCapacity:changedProperties.count];
NSDictionary *mappings_localKeyToCloudKey = self.mappings_localKeyToCloudKey;
for (NSString *localKey in changedProperties)
{
NSString *cloudKey = mappings_localKeyToCloudKey[localKey];
if (cloudKey) {
[changedCloudProperties addObject:cloudKey];
}
}
return changedCloudProperties;
}
- (BOOL)hasChangedCloudProperties
{
if ([changedProperties count] == 0) return NO;
NSDictionary *mappings_localKeyToCloudKey = self.mappings_localKeyToCloudKey;
for (NSString *localKey in changedProperties)
{
NSString *cloudKey = mappings_localKeyToCloudKey[localKey];
if (cloudKey) {
return YES;
}
}
return NO;
}
- (NSDictionary *)originalCloudValues
{
return [originalCloudValues copy];
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark Getters & Setters (cloud)
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- (NSString *)cloudKeyForLocalKey:(NSString *)localKey
{
return self.mappings_localKeyToCloudKey[localKey];
}
- (NSString *)localKeyForCloudKey:(NSString *)cloudKey
{
return self.mappings_cloudKeyToLocalKey[cloudKey];
}
- (id)cloudValueForCloudKey:(NSString *)cloudKey
{
// Override me if needed.
// For example:
//
// - (id)cloudValueForCloudKey:(NSString *)cloudKey
// {
// if ([cloudKey isEqualToString:@"color"])
// {
// // We store UIColor in the cloud as a string (r,g,b,a)
// return ConvertUIColorToNSString(self.color);
// }
// else
// {
// return [super cloudValueForCloudKey:cloudKey];
// }
// }
return [self localValueForCloudKey:cloudKey];
}
- (id)cloudValueForLocalKey:(NSString *)localKey
{
NSString *cloudKey = [self cloudKeyForLocalKey:localKey];
return [self cloudValueForCloudKey:cloudKey];
}
- (id)localValueForCloudKey:(NSString *)cloudKey
{
NSString *localKey = [self localKeyForCloudKey:cloudKey];
return [self valueForKey:localKey];
}
- (id)localValueForLocalKey:(NSString *)localKey
{
return [self valueForKey:localKey];
}
- (void)setLocalValueFromCloudValue:(id)cloudValue forCloudKey:(NSString *)cloudKey
{
// Override me if needed.
// For example:
//
// - (void)setLocalValueFromCloudValue:(id)cloudValue forCloudKey:(NSString *)cloudKey
// {
// if ([cloudKey isEqualToString:@"color"])
// {
// // We store UIColor in the cloud as a string (r,g,b,a)
// self.color = ConvertNSStringToUIColor(cloudValue);
// }
// else
// {
// return [super setLocalValueForCloudValue:cloudValue cloudKey:cloudKey];
// }
// }
NSString *localKey = [self localKeyForCloudKey:cloudKey];
if (localKey)
{
[self setValue:cloudValue forKey:localKey];
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark KVO
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key
{
if ([key isEqualToString:@"isImmutable"])
return YES;
else
return [super automaticallyNotifiesObserversForKey:key];
}
+ (NSSet *)keyPathsForValuesAffectingIsImmutable
{
// In order for the KVO magic to work, we specify that the isImmutable property is dependent
// upon all other properties in the class that should become immutable.
//
// The code below ** attempts ** to do this automatically.
// It does so by creating a list of all the properties in the class.
//
// Obviously this will not work for every situation.
// In particular:
//
// - if you have custom setter methods that aren't specified as properties
// - if you have other custom methods that modify the object
//
// To cover these edge cases, simply add code like the following at the beginning of such methods:
//
// - (void)recalculateFoo
// {
// if (self.isImmutable) {
// @throw [self immutableExceptionForKey:@"foo"];
// }
//
// // ... normal code that modifies foo ivar ...
// }
return [self monitoredProperties];
}
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
// Nothing to do (but method is required to exist)
}
- (void)willChangeValueForKey:(NSString *)key
{
if (isImmutable)
{
@throw [self immutableExceptionForKey:key];
}
if (originalCloudValues)
{
NSString *cloudKey = [self cloudKeyForLocalKey:key];
if ([self.allCloudProperties containsObject:cloudKey])
{
if (!CFDictionaryContainsKey((CFDictionaryRef)originalCloudValues, (const void *)cloudKey))
{
id originalCloudValue = [self cloudValueForCloudKey:cloudKey];
if (originalCloudValue) {
[originalCloudValues setObject:originalCloudValue forKey:cloudKey];
}
}
}
}
[super willChangeValueForKey:key];
}
- (void)didChangeValueForKey:(NSString *)key
{
if (changedProperties == nil)
changedProperties = [[NSMutableSet alloc] init];
[changedProperties addObject:key];
[super didChangeValueForKey:key];
}
@end

View File

@ -0,0 +1,27 @@
#import <Foundation/Foundation.h>
#import <CloudKit/CloudKit.h>
#import "MyDatabaseObject.h"
typedef NS_ENUM(NSInteger, TodoPriority) {
TodoPriorityLow = -1,
TodoPriorityNormal = 0,
TodoPriorityHigh = 1,
};
@interface MyTodo : MyDatabaseObject <NSCoding, NSCopying>
- (instancetype)init;
- (instancetype)initWithUUID:(NSString *)uuid;
- (instancetype)initWithRecord:(CKRecord *)record;
@property (nonatomic, copy, readonly) NSString *uuid;
@property (nonatomic, copy, readwrite) NSString *title;
@property (nonatomic, assign, readwrite) TodoPriority priority;
@property (nonatomic, assign, readwrite) BOOL isDone;
@property (nonatomic, strong, readwrite) NSDate *creationDate;
@property (nonatomic, strong, readwrite) NSDate *lastModified;
@end

View File

@ -0,0 +1,191 @@
#import "MyTodo.h"
/**
* Keys for encoding / decoding (to avoid typos)
**/
static NSString *const k_version = @"version";
static NSString *const k_uuid = @"uuid";
static NSString *const k_title = @"title";
static NSString *const k_priority = @"priority";
static NSString *const k_isDone = @"isDone";
static NSString *const k_creationDate = @"created";
static NSString *const k_lastModified = @"lastModified";
@implementation MyTodo
@synthesize uuid = uuid;
@synthesize title = title;
@synthesize priority = priority;
@synthesize isDone = isDone;
@synthesize creationDate = creationDate;
@synthesize lastModified = lastModified;
- (instancetype)init
{
return [self initWithUUID:[[NSUUID UUID] UUIDString]];
}
- (instancetype)initWithUUID:(NSString *)inUUID
{
if ((self = [super init]))
{
if (inUUID)
uuid = [inUUID copy];
else
uuid = [[NSUUID UUID] UUIDString];
priority = TodoPriorityNormal;
NSDate *now = [NSDate date];
creationDate = now;
lastModified = now;
}
return self;
}
- (instancetype)initWithRecord:(CKRecord *)record
{
if (![record.recordType isEqualToString:@"todo"])
{
NSAssert(NO, @"Attempting to create todo from non-todo record"); // For debug builds
return nil; // For release builds
}
if ((self = [super init]))
{
uuid = record.recordID.recordName;
NSSet *cloudKeys = self.allCloudProperties;
for (NSString *cloudKey in cloudKeys)
{
if (![cloudKey isEqualToString:@"uuid"])
{
[self setLocalValueFromCloudValue:[record objectForKey:cloudKey] forCloudKey:cloudKey];
}
}
}
return self;
}
#pragma mark NSCoding
- (instancetype)initWithCoder:(NSCoder *)decoder
{
if ((self = [super init]))
{
// The version can be used to handle on-the-fly upgrades to objects as they're decoded.
// For more information, see the wiki article:
// https://github.com/yapstudios/YapDatabase/wiki/Storing-Objects
// int version = [decoder decodeIntForKey:k_version];
uuid = [decoder decodeObjectForKey:k_uuid];
title = [decoder decodeObjectForKey:k_title];
priority = [decoder decodeIntegerForKey:k_priority];
isDone = [decoder decodeBoolForKey:k_isDone];
creationDate = [decoder decodeObjectForKey:k_creationDate];
lastModified = [decoder decodeObjectForKey:k_lastModified];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)coder
{
[coder encodeInt:1 forKey:k_version];
[coder encodeObject:uuid forKey:k_uuid];
[coder encodeObject:title forKey:k_title];
[coder encodeInteger:priority forKey:k_priority];
[coder encodeBool:isDone forKey:k_isDone];
[coder encodeObject:creationDate forKey:k_creationDate];
[coder encodeObject:lastModified forKey:k_lastModified];
}
#pragma mark NSCopying
- (id)copyWithZone:(NSZone *)zone
{
MyTodo *copy = [super copyWithZone:zone]; // Be sure to invoke [MyDatabaseObject copyWithZone:] !
copy->uuid = uuid;
copy->title = title;
copy->priority = priority;
copy->isDone = isDone;
copy->creationDate = creationDate;
copy->lastModified = lastModified;
return copy;
}
#pragma mark MyDatabaseObject overrides
+ (BOOL)storesOriginalCloudValues
{
return YES;
}
+ (NSMutableDictionary *)mappings_localKeyToCloudKey
{
NSMutableDictionary *mappings_localKeyToCloudKey = [super mappings_localKeyToCloudKey];
mappings_localKeyToCloudKey[@"creationDate"] = @"created";
return mappings_localKeyToCloudKey;
}
- (id)cloudValueForCloudKey:(NSString *)cloudKey
{
// Override me if needed.
// For example:
//
// - (id)cloudValueForCloudKey:(NSString *)cloudKey
// {
// if ([cloudKey isEqualToString:@"color"])
// {
// // We store UIColor in the cloud as a string (r,g,b,a)
// return ConvertUIColorToNSString(self.color);
// }
// else
// {
// return [super cloudValueForCloudKey:cloudKey];
// }
// }
return [super cloudValueForCloudKey:cloudKey];
}
- (void)setLocalValueFromCloudValue:(id)cloudValue forCloudKey:(NSString *)cloudKey
{
// Override me if needed.
// For example:
//
// - (void)setLocalValueFromCloudValue:(id)cloudValue forCloudKey:(NSString *)cloudKey
// {
// if ([cloudKey isEqualToString:@"color"])
// {
// // We store UIColor in the cloud as a string (r,g,b,a)
// self.color = ConvertNSStringToUIColor(cloudValue);
// }
// else
// {
// return [super setLocalValueForCloudValue:cloudValue cloudKey:cloudKey];
// }
// }
return [super setLocalValueFromCloudValue:cloudValue forCloudKey:cloudKey];
}
#pragma mark KVO overrides
- (void)setNilValueForKey:(NSString *)key
{
if ([key isEqualToString:@"priority"]) {
self.priority = TodoPriorityNormal;
}
if ([key isEqualToString:@"isDone"]) {
self.isDone = NO;
}
else {
[super setNilValueForKey:key];
}
}
@end

View File

@ -0,0 +1,15 @@
#import <UIKit/UIKit.h>
@interface RootViewController : UIViewController
@property (nonatomic, weak) IBOutlet UITableView *tableView;
@property (nonatomic, weak) IBOutlet UIView *ckStatusView;
@property (nonatomic, weak) IBOutlet UILabel *ckTopStatusLabel;
@property (nonatomic, weak) IBOutlet UILabel *ckBottomStatusLabel;
- (IBAction)suspendButtonTapped:(id)sender;
- (IBAction)resumeButtonTapped:(id)sender;
@end

View File

@ -0,0 +1,342 @@
#import "RootViewController.h"
#import "EditViewController.h"
#import "TodoCell.h"
#import "DatabaseManager.h"
#import "CloudKitManager.h"
#import "MyTodo.h"
#import <CocoaLumberjack/CocoaLumberjack.h>
// Log Levels: off, error, warn, info, verbose
#if DEBUG
static const NSUInteger ddLogLevel = DDLogLevelAll;
#else
static const NSUInteger ddLogLevel = DDLogLevelAll;
#endif
static NSString *const TodoCellIdentifier = @"Todo";
@implementation RootViewController
{
YapDatabaseConnection *databaseConnection;
YapDatabaseViewMappings *mappings;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Configure tableView
self.tableView.rowHeight = UITableViewAutomaticDimension;
self.tableView.estimatedRowHeight = 44.0;
CGRect ckViewFrame = self.ckStatusView.frame;
UIEdgeInsets insets = self.tableView.scrollIndicatorInsets;
insets.bottom = ckViewFrame.size.height;
self.tableView.contentInset = insets;
self.tableView.scrollIndicatorInsets = insets;
// Configure database stuff
databaseConnection = MyDatabaseManager.uiDatabaseConnection;
[self initializeMappings];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(databaseConnectionDidUpdate:)
name:UIDatabaseConnectionDidUpdateNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(cloudKitSuspendCountChanged:)
name:YapDatabaseCloudKitSuspendCountChangedNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(cloudKitInFlightChangeSetChanged:)
name:YapDatabaseCloudKitInFlightChangeSetChangedNotification
object:nil];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self updateStatusLabels];
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark Database Stuff
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- (void)initializeMappings
{
[databaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
if ([transaction ext:Ext_View_Order])
{
mappings = [[YapDatabaseViewMappings alloc] initWithGroups:@[@""] view:Ext_View_Order];
[mappings updateWithTransaction:transaction];
}
else
{
// The view isn't ready yet.
// We'll try again when we get a databaseConnectionDidUpdate notification.
}
}];
}
- (void)databaseConnectionDidUpdate:(NSNotification *)notification
{
[self updateStatusLabels];
if (mappings == nil)
{
[self initializeMappings];
[self.tableView reloadData];
return;
}
NSArray *notifications = [notification.userInfo objectForKey:kNotificationsKey];
NSArray *rowChanges = nil;
[[databaseConnection ext:Ext_View_Order] getSectionChanges:NULL
rowChanges:&rowChanges
forNotifications:notifications
withMappings:mappings];
if ([rowChanges count] == 0)
{
// There aren't any changes that affect our tableView
return;
}
[self.tableView beginUpdates];
for (YapDatabaseViewRowChange *rowChange in rowChanges)
{
switch (rowChange.type)
{
case YapDatabaseViewChangeDelete :
{
[self.tableView deleteRowsAtIndexPaths:@[ rowChange.indexPath ]
withRowAnimation:UITableViewRowAnimationFade];
break;
}
case YapDatabaseViewChangeInsert :
{
[self.tableView insertRowsAtIndexPaths:@[ rowChange.newIndexPath ]
withRowAnimation:UITableViewRowAnimationFade];
break;
}
case YapDatabaseViewChangeMove :
{
[self.tableView deleteRowsAtIndexPaths:@[ rowChange.indexPath ]
withRowAnimation:UITableViewRowAnimationFade];
[self.tableView insertRowsAtIndexPaths:@[ rowChange.newIndexPath ]
withRowAnimation:UITableViewRowAnimationFade];
break;
}
case YapDatabaseViewChangeUpdate :
{
[self.tableView reloadRowsAtIndexPaths:@[ rowChange.indexPath ]
withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
}
[self.tableView endUpdates];
}
- (void)cloudKitSuspendCountChanged:(NSNotification *)notification
{
[self updateStatusLabels];
}
- (void)cloudKitInFlightChangeSetChanged:(NSNotification *)notification
{
[self updateStatusLabels];
}
- (MyTodo *)todoAtIndexPath:(NSIndexPath *)indexPath
{
__block MyTodo *todo = nil;
[databaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
todo = [[transaction ext:Ext_View_Order] objectAtIndexPath:indexPath withMappings:mappings];
}];
return todo;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark Status
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- (void)updateStatusLabels
{
NSUInteger suspendCount = [MyDatabaseManager.cloudKitExtension suspendCount];
if (suspendCount > 0)
{
self.ckTopStatusLabel.text =
[NSString stringWithFormat:@"Status: Suspended (suspendCount = %lu)", (unsigned long)suspendCount];
}
else
{
self.ckTopStatusLabel.text = @"Status: Resumed";
}
NSUInteger inFlightCount = 0;
NSUInteger queuedCount = 0;
[MyDatabaseManager.cloudKitExtension getNumberOfInFlightChangeSets:&inFlightCount queuedChangeSets:&queuedCount];
self.ckBottomStatusLabel.text =
[NSString stringWithFormat:@"ChangeSets: InFlight(%lu), Queued(%lu)",
(unsigned long)inFlightCount,
(unsigned long)queuedCount];
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark Actions
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- (IBAction)suspendButtonTapped:(id)sender
{
DDLogVerbose(@"RootViewController - suspendButtonTapped:");
[MyDatabaseManager.cloudKitExtension suspend];
}
- (IBAction)resumeButtonTapped:(id)sender
{
DDLogVerbose(@"RootViewController - resumeButtonTapped:");
[MyDatabaseManager.cloudKitExtension resume];
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark UITableView
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- (NSInteger)numberOfSectionsInTableView:(UITableView *)sender
{
return 1;
}
- (NSInteger)tableView:(UITableView *)sender numberOfRowsInSection:(NSInteger)section
{
return [mappings numberOfItemsInSection:section];
}
- (UITableViewCell *)tableView:(UITableView *)sender cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
TodoCell *cell = (TodoCell *)[self.tableView dequeueReusableCellWithIdentifier:TodoCellIdentifier];
MyTodo *todo = [self todoAtIndexPath:indexPath];
NSString *title = todo.title;
if (title == nil)
title = @"< missing title >";
if (todo.isDone)
{
UIImage *image = [UIImage imageNamed:@"checkmark-on"];
[cell.checkmarkButton setImage:image forState:UIControlStateNormal];
NSDictionary *attr = @{NSStrikethroughStyleAttributeName: @(NSUnderlineStyleSingle)};
NSAttributedString *attrStr = [[NSAttributedString alloc] initWithString:title attributes:attr];
cell.titleLabel.attributedText = attrStr;
}
else
{
UIImage *image = [UIImage imageNamed:@"checkmark-off"];
[cell.checkmarkButton setImage:image forState:UIControlStateNormal];
cell.titleLabel.text = title;
}
switch (todo.priority)
{
case TodoPriorityLow : cell.titleLabel.textColor = [UIColor darkGrayColor]; break;
case TodoPriorityHigh : cell.titleLabel.textColor = [UIColor redColor]; break;
default : cell.titleLabel.textColor = [UIColor blackColor]; break;
}
cell.delegate = self;
[cell setNeedsUpdateConstraints];
[cell updateConstraintsIfNeeded];
return cell;
}
- (void)tableView:(UITableView *)sender didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
MyTodo *todo = [self todoAtIndexPath:indexPath];
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
EditViewController *evc = [storyboard instantiateViewControllerWithIdentifier:@"EditViewController"];
evc.todoID = todo.uuid;
[self.navigationController pushViewController:evc animated:YES];
[self.tableView deselectRowAtIndexPath:indexPath animated:YES];
}
- (NSArray *)tableView:(UITableView *)sender editActionsForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewRowAction *deleteAction =
[UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDestructive
title:@"Delete"
handler:^(UITableViewRowAction *action, NSIndexPath *indexPath)
{
MyTodo *todo = [self todoAtIndexPath:indexPath];
YapDatabaseConnection *rwDatabaseConnection = MyDatabaseManager.bgDatabaseConnection;
[rwDatabaseConnection asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
[transaction removeObjectForKey:todo.uuid inCollection:Collection_Todos];
} completionBlock:^{
[self updateStatusLabels];
}];
}];
return @[ deleteAction ];
}
- (void)tableView:(UITableView *)sender commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
forRowAtIndexPath:(NSIndexPath *)indexPath
{
// No statement or algorithm is needed in here. Just the implementation
}
- (void)didTapImageViewInCell:(TodoCell *)sender
{
NSIndexPath *indexPath = [self.tableView indexPathForCell:sender];
MyTodo *originalTodo = [self todoAtIndexPath:indexPath];
NSString *todoID = originalTodo.uuid;
BOOL newIsDone = originalTodo.isDone ? NO : YES;
[MyDatabaseManager.bgDatabaseConnection asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
MyTodo *todo = [transaction objectForKey:todoID inCollection:Collection_Todos];
todo = [todo copy]; // make mutable copy
todo.isDone = newIsDone;
todo.lastModified = [NSDate date];
[transaction setObject:todo forKey:todoID inCollection:Collection_Todos];
}];
}
@end

View File

@ -0,0 +1,18 @@
#import <UIKit/UIKit.h>
@interface TodoCell : UITableViewCell
@property (nonatomic, weak) id <NSObject> delegate;
@property (nonatomic, weak) IBOutlet UIButton *checkmarkButton;
@property (nonatomic, weak) IBOutlet UILabel *titleLabel;
@end
@protocol TodoCellDelegate
@optional
- (void)didTapImageViewInCell:(TodoCell *)sender;
@end

View File

@ -0,0 +1,20 @@
#import "TodoCell.h"
@implementation TodoCell
@synthesize delegate = _weak_delegate;
@synthesize checkmarkButton = checkmarkButton;
@synthesize titleLabel = titleLabel;
- (IBAction)didTapImageView:(id)sender
{
id <NSObject> delegate = self.delegate;
if ([delegate respondsToSelector:@selector(didTapImageViewInCell:)]) {
[(id <TodoCellDelegate>)delegate didTapImageViewInCell:self];
}
}
@end

View File

@ -0,0 +1,8 @@
#import <UIKit/UIKit.h>
@interface TodoTextView : UITextView
@property (nonatomic, readwrite) BOOL needsScrollIfNeeded;
@end

View File

@ -0,0 +1,37 @@
#import "TodoTextView.h"
@implementation TodoTextView
@synthesize needsScrollIfNeeded;
- (CGSize)intrinsicContentSize
{
CGSize maxSize = self.frame.size;
maxSize.height = 9999;
CGSize size = [self sizeThatFits:maxSize];
return size;
}
- (void)layoutSubviews
{
[super layoutSubviews];
if (self.needsScrollIfNeeded)
{
self.needsScrollIfNeeded = NO;
if (self.contentSize.height > self.frame.size.height)
{
CGFloat y = self.contentSize.height - self.frame.size.height;
[self setContentOffset:CGPointMake(0, y) animated:YES];
}
else
{
[self setContentOffset:CGPointMake(0, 0) animated:YES];
}
}
}
@end

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -0,0 +1,16 @@
//
// main.m
// CloudKitTodo
//
// Created by Robbie Hanson on 12/3/14.
// Copyright (c) 2014 Deusty LLC. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}

View File

@ -0,0 +1,6 @@
platform :ios, '10.0'
target 'CloudKitTodo' do
pod 'Reachability', '3.2'
pod "YapDatabase", path: '../../'
end

View File

@ -0,0 +1,85 @@
PODS:
- CocoaLumberjack (3.2.1):
- CocoaLumberjack/Default (= 3.2.1)
- CocoaLumberjack/Extensions (= 3.2.1)
- CocoaLumberjack/Default (3.2.1)
- CocoaLumberjack/Extensions (3.2.1):
- CocoaLumberjack/Default
- Reachability (3.2)
- YapDatabase (3.0.1):
- YapDatabase/Standard (= 3.0.1)
- YapDatabase/Standard (3.0.1):
- YapDatabase/Standard/Core (= 3.0.1)
- YapDatabase/Standard/Extensions (= 3.0.1)
- YapDatabase/Standard/Core (3.0.1):
- CocoaLumberjack
- YapDatabase/Standard/Extensions (3.0.1):
- YapDatabase/Standard/Core
- YapDatabase/Standard/Extensions/ActionManager (= 3.0.1)
- YapDatabase/Standard/Extensions/AutoView (= 3.0.1)
- YapDatabase/Standard/Extensions/CloudCore (= 3.0.1)
- YapDatabase/Standard/Extensions/CloudKit (= 3.0.1)
- YapDatabase/Standard/Extensions/ConnectionProxy (= 3.0.1)
- YapDatabase/Standard/Extensions/CrossProcessNotification (= 3.0.1)
- YapDatabase/Standard/Extensions/FilteredView (= 3.0.1)
- YapDatabase/Standard/Extensions/FullTextSearch (= 3.0.1)
- YapDatabase/Standard/Extensions/Hooks (= 3.0.1)
- YapDatabase/Standard/Extensions/ManualView (= 3.0.1)
- YapDatabase/Standard/Extensions/Relationships (= 3.0.1)
- YapDatabase/Standard/Extensions/RTreeIndex (= 3.0.1)
- YapDatabase/Standard/Extensions/SearchResultsView (= 3.0.1)
- YapDatabase/Standard/Extensions/SecondaryIndex (= 3.0.1)
- YapDatabase/Standard/Extensions/View (= 3.0.1)
- YapDatabase/Standard/Extensions/ActionManager (3.0.1):
- YapDatabase/Standard/Core
- YapDatabase/Standard/Extensions/AutoView
- YapDatabase/Standard/Extensions/AutoView (3.0.1):
- YapDatabase/Standard/Core
- YapDatabase/Standard/Extensions/View
- YapDatabase/Standard/Extensions/CloudCore (3.0.1):
- YapDatabase/Standard/Core
- YapDatabase/Standard/Extensions/CloudKit (3.0.1):
- YapDatabase/Standard/Core
- YapDatabase/Standard/Extensions/ConnectionProxy (3.0.1):
- YapDatabase/Standard/Core
- YapDatabase/Standard/Extensions/CrossProcessNotification (3.0.1):
- YapDatabase/Standard/Core
- YapDatabase/Standard/Extensions/FilteredView (3.0.1):
- YapDatabase/Standard/Core
- YapDatabase/Standard/Extensions/View
- YapDatabase/Standard/Extensions/FullTextSearch (3.0.1):
- YapDatabase/Standard/Core
- YapDatabase/Standard/Extensions/Hooks (3.0.1):
- YapDatabase/Standard/Core
- YapDatabase/Standard/Extensions/ManualView (3.0.1):
- YapDatabase/Standard/Core
- YapDatabase/Standard/Extensions/View
- YapDatabase/Standard/Extensions/Relationships (3.0.1):
- YapDatabase/Standard/Core
- YapDatabase/Standard/Extensions/RTreeIndex (3.0.1):
- YapDatabase/Standard/Core
- YapDatabase/Standard/Extensions/SearchResultsView (3.0.1):
- YapDatabase/Standard/Core
- YapDatabase/Standard/Extensions/AutoView
- YapDatabase/Standard/Extensions/FullTextSearch
- YapDatabase/Standard/Extensions/SecondaryIndex (3.0.1):
- YapDatabase/Standard/Core
- YapDatabase/Standard/Extensions/View (3.0.1):
- YapDatabase/Standard/Core
DEPENDENCIES:
- Reachability (= 3.2)
- YapDatabase (from `../../`)
EXTERNAL SOURCES:
YapDatabase:
:path: ../../
SPEC CHECKSUMS:
CocoaLumberjack: 2800c03334042fe80589423c8d80e582dcaec482
Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96
YapDatabase: 69ca88a2dfee305fde4412cf670c76f75aa7ccd0
PODFILE CHECKSUM: 39de1b3e71c8e5fd8a2fd5205a886ee12a55be4a
COCOAPODS: 1.3.1

View File

@ -0,0 +1,86 @@
// Software License Agreement (BSD License)
//
// Copyright (c) 2010-2016, Deusty, LLC
// All rights reserved.
//
// Redistribution and use of this software in source and binary forms,
// with or without modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Neither the name of Deusty nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific
// prior written permission of Deusty, LLC.
/**
* Welcome to CocoaLumberjack!
*
* The project page has a wealth of documentation if you have any questions.
* https://github.com/CocoaLumberjack/CocoaLumberjack
*
* If you're new to the project you may wish to read "Getting Started" at:
* Documentation/GettingStarted.md
*
* Otherwise, here is a quick refresher.
* There are three steps to using the macros:
*
* Step 1:
* Import the header in your implementation or prefix file:
*
* #import <CocoaLumberjack/CocoaLumberjack.h>
*
* Step 2:
* Define your logging level in your implementation file:
*
* // Log levels: off, error, warn, info, verbose
* static const DDLogLevel ddLogLevel = DDLogLevelVerbose;
*
* Step 2 [3rd party frameworks]:
*
* Define your LOG_LEVEL_DEF to a different variable/function than ddLogLevel:
*
* // #undef LOG_LEVEL_DEF // Undefine first only if needed
* #define LOG_LEVEL_DEF myLibLogLevel
*
* Define your logging level in your implementation file:
*
* // Log levels: off, error, warn, info, verbose
* static const DDLogLevel myLibLogLevel = DDLogLevelVerbose;
*
* Step 3:
* Replace your NSLog statements with DDLog statements according to the severity of the message.
*
* NSLog(@"Fatal error, no dohickey found!"); -> DDLogError(@"Fatal error, no dohickey found!");
*
* DDLog works exactly the same as NSLog.
* This means you can pass it multiple variables just like NSLog.
**/
#import <Foundation/Foundation.h>
// Disable legacy macros
#ifndef DD_LEGACY_MACROS
#define DD_LEGACY_MACROS 0
#endif
// Core
#import "DDLog.h"
// Main macros
#import "DDLogMacros.h"
#import "DDAssertMacros.h"
// Capture ASL
#import "DDASLLogCapture.h"
// Loggers
#import "DDTTYLogger.h"
#import "DDASLLogger.h"
#import "DDFileLogger.h"
#import "DDOSLogger.h"
// CLI
#if __has_include("CLIColor.h") && TARGET_OS_OSX
#import "CLIColor.h"
#endif

View File

@ -0,0 +1,95 @@
// Software License Agreement (BSD License)
//
// Copyright (c) 2014-2016, Deusty, LLC
// All rights reserved.
//
// Redistribution and use of this software in source and binary forms,
// with or without modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Neither the name of Deusty nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific
// prior written permission of Deusty, LLC.
import Foundation
extension DDLogFlag {
public static func from(_ logLevel: DDLogLevel) -> DDLogFlag {
return DDLogFlag(rawValue: logLevel.rawValue)
}
public init(_ logLevel: DDLogLevel) {
self = DDLogFlag(rawValue: logLevel.rawValue)
}
///returns the log level, or the lowest equivalant.
public func toLogLevel() -> DDLogLevel {
if let ourValid = DDLogLevel(rawValue: rawValue) {
return ourValid
} else {
if contains(.verbose) {
return .verbose
} else if contains(.debug) {
return .debug
} else if contains(.info) {
return .info
} else if contains(.warning) {
return .warning
} else if contains(.error) {
return .error
} else {
return .off
}
}
}
}
public var defaultDebugLevel = DDLogLevel.verbose
public func resetDefaultDebugLevel() {
defaultDebugLevel = DDLogLevel.verbose
}
public func _DDLogMessage(_ message: @autoclosure () -> String, level: DDLogLevel, flag: DDLogFlag, context: Int, file: StaticString, function: StaticString, line: UInt, tag: Any?, asynchronous: Bool, ddlog: DDLog) {
if level.rawValue & flag.rawValue != 0 {
// Tell the DDLogMessage constructor to copy the C strings that get passed to it.
let logMessage = DDLogMessage(message: message(), level: level, flag: flag, context: context, file: String(describing: file), function: String(describing: function), line: line, tag: tag, options: [.copyFile, .copyFunction], timestamp: nil)
ddlog.log(asynchronous: asynchronous, message: logMessage)
}
}
public func DDLogDebug(_ message: @autoclosure () -> String, level: DDLogLevel = defaultDebugLevel, context: Int = 0, file: StaticString = #file, function: StaticString = #function, line: UInt = #line, tag: Any? = nil, asynchronous async: Bool = true, ddlog: DDLog = DDLog.sharedInstance) {
_DDLogMessage(message, level: level, flag: .debug, context: context, file: file, function: function, line: line, tag: tag, asynchronous: async, ddlog: ddlog)
}
public func DDLogInfo(_ message: @autoclosure () -> String, level: DDLogLevel = defaultDebugLevel, context: Int = 0, file: StaticString = #file, function: StaticString = #function, line: UInt = #line, tag: Any? = nil, asynchronous async: Bool = true, ddlog: DDLog = DDLog.sharedInstance) {
_DDLogMessage(message, level: level, flag: .info, context: context, file: file, function: function, line: line, tag: tag, asynchronous: async, ddlog: ddlog)
}
public func DDLogWarn(_ message: @autoclosure () -> String, level: DDLogLevel = defaultDebugLevel, context: Int = 0, file: StaticString = #file, function: StaticString = #function, line: UInt = #line, tag: Any? = nil, asynchronous async: Bool = true, ddlog: DDLog = DDLog.sharedInstance) {
_DDLogMessage(message, level: level, flag: .warning, context: context, file: file, function: function, line: line, tag: tag, asynchronous: async, ddlog: ddlog)
}
public func DDLogVerbose(_ message: @autoclosure () -> String, level: DDLogLevel = defaultDebugLevel, context: Int = 0, file: StaticString = #file, function: StaticString = #function, line: UInt = #line, tag: Any? = nil, asynchronous async: Bool = true, ddlog: DDLog = DDLog.sharedInstance) {
_DDLogMessage(message, level: level, flag: .verbose, context: context, file: file, function: function, line: line, tag: tag, asynchronous: async, ddlog: ddlog)
}
public func DDLogError(_ message: @autoclosure () -> String, level: DDLogLevel = defaultDebugLevel, context: Int = 0, file: StaticString = #file, function: StaticString = #function, line: UInt = #line, tag: Any? = nil, asynchronous async: Bool = false, ddlog: DDLog = DDLog.sharedInstance) {
_DDLogMessage(message, level: level, flag: .error, context: context, file: file, function: function, line: line, tag: tag, asynchronous: async, ddlog: ddlog)
}
/// Returns a String of the current filename, without full path or extension.
///
/// Analogous to the C preprocessor macro `THIS_FILE`.
public func CurrentFileName(_ fileName: StaticString = #file) -> String {
var str = String(describing: fileName)
if let idx = str.range(of: "/", options: .backwards)?.upperBound {
str = str.substring(from: idx)
}
if let idx = str.range(of: ".", options: .backwards)?.lowerBound {
str = str.substring(to: idx)
}
return str
}

View File

@ -0,0 +1,41 @@
// Software License Agreement (BSD License)
//
// Copyright (c) 2010-2016, Deusty, LLC
// All rights reserved.
//
// Redistribution and use of this software in source and binary forms,
// with or without modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Neither the name of Deusty nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific
// prior written permission of Deusty, LLC.
#import "DDASLLogger.h"
@protocol DDLogger;
/**
* This class provides the ability to capture the ASL (Apple System Logs)
*/
@interface DDASLLogCapture : NSObject
/**
* Start capturing logs
*/
+ (void)start;
/**
* Stop capturing logs
*/
+ (void)stop;
/**
* The current capture level.
* @note Default log level: DDLogLevelVerbose (i.e. capture all ASL messages).
*/
@property (class) DDLogLevel captureLevel;
@end

View File

@ -0,0 +1,230 @@
// Software License Agreement (BSD License)
//
// Copyright (c) 2010-2016, Deusty, LLC
// All rights reserved.
//
// Redistribution and use of this software in source and binary forms,
// with or without modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Neither the name of Deusty nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific
// prior written permission of Deusty, LLC.
#import "DDASLLogCapture.h"
// Disable legacy macros
#ifndef DD_LEGACY_MACROS
#define DD_LEGACY_MACROS 0
#endif
#import "DDLog.h"
#include <asl.h>
#include <notify.h>
#include <notify_keys.h>
#include <sys/time.h>
static BOOL _cancel = YES;
static DDLogLevel _captureLevel = DDLogLevelVerbose;
#ifdef __IPHONE_8_0
#define DDASL_IOS_PIVOT_VERSION __IPHONE_8_0
#endif
#ifdef __MAC_10_10
#define DDASL_OSX_PIVOT_VERSION __MAC_10_10
#endif
@implementation DDASLLogCapture
static aslmsg (*dd_asl_next)(aslresponse obj);
static void (*dd_asl_release)(aslresponse obj);
+ (void)initialize
{
#if (defined(DDASL_IOS_PIVOT_VERSION) && __IPHONE_OS_VERSION_MAX_ALLOWED >= DDASL_IOS_PIVOT_VERSION) || (defined(DDASL_OSX_PIVOT_VERSION) && __MAC_OS_X_VERSION_MAX_ALLOWED >= DDASL_OSX_PIVOT_VERSION)
#if __IPHONE_OS_VERSION_MIN_REQUIRED < DDASL_IOS_PIVOT_VERSION || __MAC_OS_X_VERSION_MIN_REQUIRED < DDASL_OSX_PIVOT_VERSION
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
// Building on falsely advertised SDK, targeting deprecated API
dd_asl_next = &aslresponse_next;
dd_asl_release = &aslresponse_free;
#pragma GCC diagnostic pop
#else
// Building on lastest, correct SDK, targeting latest API
dd_asl_next = &asl_next;
dd_asl_release = &asl_release;
#endif
#else
// Building on old SDKs, targeting deprecated API
dd_asl_next = &aslresponse_next;
dd_asl_release = &aslresponse_free;
#endif
}
+ (void)start {
// Ignore subsequent calls
if (!_cancel) {
return;
}
_cancel = NO;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
[self captureAslLogs];
});
}
+ (void)stop {
_cancel = YES;
}
+ (DDLogLevel)captureLevel {
return _captureLevel;
}
+ (void)setCaptureLevel:(DDLogLevel)level {
_captureLevel = level;
}
#pragma mark - Private methods
+ (void)configureAslQuery:(aslmsg)query {
const char param[] = "7"; // ASL_LEVEL_DEBUG, which is everything. We'll rely on regular DDlog log level to filter
asl_set_query(query, ASL_KEY_LEVEL, param, ASL_QUERY_OP_LESS_EQUAL | ASL_QUERY_OP_NUMERIC);
// Don't retrieve logs from our own DDASLLogger
asl_set_query(query, kDDASLKeyDDLog, kDDASLDDLogValue, ASL_QUERY_OP_NOT_EQUAL);
#if !TARGET_OS_IPHONE || TARGET_SIMULATOR
int processId = [[NSProcessInfo processInfo] processIdentifier];
char pid[16];
sprintf(pid, "%d", processId);
asl_set_query(query, ASL_KEY_PID, pid, ASL_QUERY_OP_EQUAL | ASL_QUERY_OP_NUMERIC);
#endif
}
+ (void)aslMessageReceived:(aslmsg)msg {
const char* messageCString = asl_get( msg, ASL_KEY_MSG );
if ( messageCString == NULL )
return;
int flag;
BOOL async;
const char* levelCString = asl_get(msg, ASL_KEY_LEVEL);
switch (levelCString? atoi(levelCString) : 0) {
// By default all NSLog's with a ASL_LEVEL_WARNING level
case ASL_LEVEL_EMERG :
case ASL_LEVEL_ALERT :
case ASL_LEVEL_CRIT : flag = DDLogFlagError; async = NO; break;
case ASL_LEVEL_ERR : flag = DDLogFlagWarning; async = YES; break;
case ASL_LEVEL_WARNING : flag = DDLogFlagInfo; async = YES; break;
case ASL_LEVEL_NOTICE : flag = DDLogFlagDebug; async = YES; break;
case ASL_LEVEL_INFO :
case ASL_LEVEL_DEBUG :
default : flag = DDLogFlagVerbose; async = YES; break;
}
if (!(_captureLevel & flag)) {
return;
}
// NSString * sender = [NSString stringWithCString:asl_get(msg, ASL_KEY_SENDER) encoding:NSUTF8StringEncoding];
NSString *message = @(messageCString);
const char* secondsCString = asl_get( msg, ASL_KEY_TIME );
const char* nanoCString = asl_get( msg, ASL_KEY_TIME_NSEC );
NSTimeInterval seconds = secondsCString ? strtod(secondsCString, NULL) : [NSDate timeIntervalSinceReferenceDate] - NSTimeIntervalSince1970;
double nanoSeconds = nanoCString? strtod(nanoCString, NULL) : 0;
NSTimeInterval totalSeconds = seconds + (nanoSeconds / 1e9);
NSDate *timeStamp = [NSDate dateWithTimeIntervalSince1970:totalSeconds];
DDLogMessage *logMessage = [[DDLogMessage alloc]initWithMessage:message
level:_captureLevel
flag:flag
context:0
file:@"DDASLLogCapture"
function:0
line:0
tag:nil
options:0
timestamp:timeStamp];
[DDLog log:async message:logMessage];
}
+ (void)captureAslLogs {
@autoreleasepool
{
/*
We use ASL_KEY_MSG_ID to see each message once, but there's no
obvious way to get the "next" ID. To bootstrap the process, we'll
search by timestamp until we've seen a message.
*/
struct timeval timeval = {
.tv_sec = 0
};
gettimeofday(&timeval, NULL);
unsigned long long startTime = timeval.tv_sec;
__block unsigned long long lastSeenID = 0;
/*
syslogd posts kNotifyASLDBUpdate (com.apple.system.logger.message)
through the notify API when it saves messages to the ASL database.
There is some coalescing - currently it is sent at most twice per
second - but there is no documented guarantee about this. In any
case, there may be multiple messages per notification.
Notify notifications don't carry any payload, so we need to search
for the messages.
*/
int notifyToken = 0; // Can be used to unregister with notify_cancel().
notify_register_dispatch(kNotifyASLDBUpdate, &notifyToken, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^(int token)
{
// At least one message has been posted; build a search query.
@autoreleasepool
{
aslmsg query = asl_new(ASL_TYPE_QUERY);
char stringValue[64];
if (lastSeenID > 0) {
snprintf(stringValue, sizeof stringValue, "%llu", lastSeenID);
asl_set_query(query, ASL_KEY_MSG_ID, stringValue, ASL_QUERY_OP_GREATER | ASL_QUERY_OP_NUMERIC);
} else {
snprintf(stringValue, sizeof stringValue, "%llu", startTime);
asl_set_query(query, ASL_KEY_TIME, stringValue, ASL_QUERY_OP_GREATER_EQUAL | ASL_QUERY_OP_NUMERIC);
}
[self configureAslQuery:query];
// Iterate over new messages.
aslmsg msg;
aslresponse response = asl_search(NULL, query);
while ((msg = dd_asl_next(response)))
{
[self aslMessageReceived:msg];
// Keep track of which messages we've seen.
lastSeenID = atoll(asl_get(msg, ASL_KEY_MSG_ID));
}
dd_asl_release(response);
asl_free(query);
if (_cancel) {
notify_cancel(token);
return;
}
}
});
}
}
@end

View File

@ -0,0 +1,58 @@
// Software License Agreement (BSD License)
//
// Copyright (c) 2010-2016, Deusty, LLC
// All rights reserved.
//
// Redistribution and use of this software in source and binary forms,
// with or without modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Neither the name of Deusty nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific
// prior written permission of Deusty, LLC.
#import <Foundation/Foundation.h>
// Disable legacy macros
#ifndef DD_LEGACY_MACROS
#define DD_LEGACY_MACROS 0
#endif
#import "DDLog.h"
// Custom key set on messages sent to ASL
extern const char* const kDDASLKeyDDLog;
// Value set for kDDASLKeyDDLog
extern const char* const kDDASLDDLogValue;
/**
* This class provides a logger for the Apple System Log facility.
*
* As described in the "Getting Started" page,
* the traditional NSLog() function directs its output to two places:
*
* - Apple System Log
* - StdErr (if stderr is a TTY) so log statements show up in Xcode console
*
* To duplicate NSLog() functionality you can simply add this logger and a tty logger.
* However, if you instead choose to use file logging (for faster performance),
* you may choose to use a file logger and a tty logger.
**/
@interface DDASLLogger : DDAbstractLogger <DDLogger>
/**
* Singleton method
*
* @return the shared instance
*/
@property (class, readonly, strong) DDASLLogger *sharedInstance;
// Inherited from DDAbstractLogger
// - (id <DDLogFormatter>)logFormatter;
// - (void)setLogFormatter:(id <DDLogFormatter>)formatter;
@end

View File

@ -0,0 +1,121 @@
// Software License Agreement (BSD License)
//
// Copyright (c) 2010-2016, Deusty, LLC
// All rights reserved.
//
// Redistribution and use of this software in source and binary forms,
// with or without modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Neither the name of Deusty nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific
// prior written permission of Deusty, LLC.
#import "DDASLLogger.h"
#import <asl.h>
#if !__has_feature(objc_arc)
#error This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
#endif
const char* const kDDASLKeyDDLog = "DDLog";
const char* const kDDASLDDLogValue = "1";
static DDASLLogger *sharedInstance;
@interface DDASLLogger () {
aslclient _client;
}
@end
@implementation DDASLLogger
+ (instancetype)sharedInstance {
static dispatch_once_t DDASLLoggerOnceToken;
dispatch_once(&DDASLLoggerOnceToken, ^{
sharedInstance = [[[self class] alloc] init];
});
return sharedInstance;
}
- (instancetype)init {
if (sharedInstance != nil) {
return nil;
}
if ((self = [super init])) {
// A default asl client is provided for the main thread,
// but background threads need to create their own client.
_client = asl_open(NULL, "com.apple.console", 0);
}
return self;
}
- (void)logMessage:(DDLogMessage *)logMessage {
// Skip captured log messages
if ([logMessage->_fileName isEqualToString:@"DDASLLogCapture"]) {
return;
}
NSString * message = _logFormatter ? [_logFormatter formatLogMessage:logMessage] : logMessage->_message;
if (message) {
const char *msg = [message UTF8String];
size_t aslLogLevel;
switch (logMessage->_flag) {
// Note: By default ASL will filter anything above level 5 (Notice).
// So our mappings shouldn't go above that level.
case DDLogFlagError : aslLogLevel = ASL_LEVEL_CRIT; break;
case DDLogFlagWarning : aslLogLevel = ASL_LEVEL_ERR; break;
case DDLogFlagInfo : aslLogLevel = ASL_LEVEL_WARNING; break; // Regular NSLog's level
case DDLogFlagDebug :
case DDLogFlagVerbose :
default : aslLogLevel = ASL_LEVEL_NOTICE; break;
}
static char const *const level_strings[] = { "0", "1", "2", "3", "4", "5", "6", "7" };
// NSLog uses the current euid to set the ASL_KEY_READ_UID.
uid_t const readUID = geteuid();
char readUIDString[16];
#ifndef NS_BLOCK_ASSERTIONS
size_t l = snprintf(readUIDString, sizeof(readUIDString), "%d", readUID);
#else
snprintf(readUIDString, sizeof(readUIDString), "%d", readUID);
#endif
NSAssert(l < sizeof(readUIDString),
@"Formatted euid is too long.");
NSAssert(aslLogLevel < (sizeof(level_strings) / sizeof(level_strings[0])),
@"Unhandled ASL log level.");
aslmsg m = asl_new(ASL_TYPE_MSG);
if (m != NULL) {
if (asl_set(m, ASL_KEY_LEVEL, level_strings[aslLogLevel]) == 0 &&
asl_set(m, ASL_KEY_MSG, msg) == 0 &&
asl_set(m, ASL_KEY_READ_UID, readUIDString) == 0 &&
asl_set(m, kDDASLKeyDDLog, kDDASLDDLogValue) == 0) {
asl_send(_client, m);
}
asl_free(m);
}
//TODO handle asl_* failures non-silently?
}
}
- (NSString *)loggerName {
return @"cocoa.lumberjack.aslLogger";
}
@end

View File

@ -1,102 +1,123 @@
#import <Foundation/Foundation.h>
// Software License Agreement (BSD License)
//
// Copyright (c) 2010-2016, Deusty, LLC
// All rights reserved.
//
// Redistribution and use of this software in source and binary forms,
// with or without modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Neither the name of Deusty nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific
// prior written permission of Deusty, LLC.
// Disable legacy macros
#ifndef DD_LEGACY_MACROS
#define DD_LEGACY_MACROS 0
#endif
#import "DDLog.h"
/**
* Welcome to Cocoa Lumberjack!
*
* The project page has a wealth of documentation if you have any questions.
* https://github.com/robbiehanson/CocoaLumberjack
*
* If you're new to the project you may wish to read the "Getting Started" wiki.
* https://github.com/robbiehanson/CocoaLumberjack/wiki/GettingStarted
*
*
* This class provides an abstract implementation of a database logger.
*
*
* That is, it provides the base implementation for a database logger to build atop of.
* All that is needed for a concrete database logger is to extend this class
* and override the methods in the implementation file that are prefixed with "db_".
**/
**/
@interface DDAbstractDatabaseLogger : DDAbstractLogger {
@protected
NSUInteger saveThreshold;
NSTimeInterval saveInterval;
NSTimeInterval maxAge;
NSTimeInterval deleteInterval;
BOOL deleteOnEverySave;
BOOL saveTimerSuspended;
NSUInteger unsavedCount;
dispatch_time_t unsavedTime;
dispatch_source_t saveTimer;
dispatch_time_t lastDeleteTime;
dispatch_source_t deleteTimer;
NSUInteger _saveThreshold;
NSTimeInterval _saveInterval;
NSTimeInterval _maxAge;
NSTimeInterval _deleteInterval;
BOOL _deleteOnEverySave;
BOOL _saveTimerSuspended;
NSUInteger _unsavedCount;
dispatch_time_t _unsavedTime;
dispatch_source_t _saveTimer;
dispatch_time_t _lastDeleteTime;
dispatch_source_t _deleteTimer;
}
/**
* Specifies how often to save the data to disk.
* Since saving is an expensive operation (disk io) it is not done after every log statement.
* These properties allow you to configure how/when the logger saves to disk.
*
*
* A save is done when either (whichever happens first):
*
*
* - The number of unsaved log entries reaches saveThreshold
* - The amount of time since the oldest unsaved log entry was created reaches saveInterval
*
*
* You can optionally disable the saveThreshold by setting it to zero.
* If you disable the saveThreshold you are entirely dependent on the saveInterval.
*
*
* You can optionally disable the saveInterval by setting it to zero (or a negative value).
* If you disable the saveInterval you are entirely dependent on the saveThreshold.
*
*
* It's not wise to disable both saveThreshold and saveInterval.
*
*
* The default saveThreshold is 500.
* The default saveInterval is 60 seconds.
**/
**/
@property (assign, readwrite) NSUInteger saveThreshold;
/**
* See the description for the `saveThreshold` property
*/
@property (assign, readwrite) NSTimeInterval saveInterval;
/**
* It is likely you don't want the log entries to persist forever.
* Doing so would allow the database to grow infinitely large over time.
*
*
* The maxAge property provides a way to specify how old a log statement can get
* before it should get deleted from the database.
*
*
* The deleteInterval specifies how often to sweep for old log entries.
* Since deleting is an expensive operation (disk io) is is done on a fixed interval.
*
*
* An alternative to the deleteInterval is the deleteOnEverySave option.
* This specifies that old log entries should be deleted during every save operation.
*
*
* You can optionally disable the maxAge by setting it to zero (or a negative value).
* If you disable the maxAge then old log statements are not deleted.
*
*
* You can optionally disable the deleteInterval by setting it to zero (or a negative value).
*
*
* If you disable both deleteInterval and deleteOnEverySave then old log statements are not deleted.
*
*
* It's not wise to enable both deleteInterval and deleteOnEverySave.
*
*
* The default maxAge is 7 days.
* The default deleteInterval is 5 minutes.
* The default deleteOnEverySave is NO.
**/
**/
@property (assign, readwrite) NSTimeInterval maxAge;
/**
* See the description for the `maxAge` property
*/
@property (assign, readwrite) NSTimeInterval deleteInterval;
/**
* See the description for the `maxAge` property
*/
@property (assign, readwrite) BOOL deleteOnEverySave;
/**
* Forces a save of any pending log entries (flushes log entries to disk).
**/
**/
- (void)savePendingLogEntries;
/**
* Removes any log entries that are older than maxAge.
**/
**/
- (void)deleteOldLogEntries;
@end

View File

@ -0,0 +1,660 @@
// Software License Agreement (BSD License)
//
// Copyright (c) 2010-2016, Deusty, LLC
// All rights reserved.
//
// Redistribution and use of this software in source and binary forms,
// with or without modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Neither the name of Deusty nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific
// prior written permission of Deusty, LLC.
#import "DDAbstractDatabaseLogger.h"
#import <math.h>
#if !__has_feature(objc_arc)
#error This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
#endif
@interface DDAbstractDatabaseLogger ()
- (void)destroySaveTimer;
- (void)destroyDeleteTimer;
@end
#pragma mark -
@implementation DDAbstractDatabaseLogger
- (instancetype)init {
if ((self = [super init])) {
_saveThreshold = 500;
_saveInterval = 60; // 60 seconds
_maxAge = (60 * 60 * 24 * 7); // 7 days
_deleteInterval = (60 * 5); // 5 minutes
}
return self;
}
- (void)dealloc {
[self destroySaveTimer];
[self destroyDeleteTimer];
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark Override Me
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- (BOOL)db_log:(DDLogMessage *)logMessage {
// Override me and add your implementation.
//
// Return YES if an item was added to the buffer.
// Return NO if the logMessage was ignored.
return NO;
}
- (void)db_save {
// Override me and add your implementation.
}
- (void)db_delete {
// Override me and add your implementation.
}
- (void)db_saveAndDelete {
// Override me and add your implementation.
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark Private API
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- (void)performSaveAndSuspendSaveTimer {
if (_unsavedCount > 0) {
if (_deleteOnEverySave) {
[self db_saveAndDelete];
} else {
[self db_save];
}
}
_unsavedCount = 0;
_unsavedTime = 0;
if (_saveTimer && !_saveTimerSuspended) {
dispatch_suspend(_saveTimer);
_saveTimerSuspended = YES;
}
}
- (void)performDelete {
if (_maxAge > 0.0) {
[self db_delete];
_lastDeleteTime = dispatch_time(DISPATCH_TIME_NOW, 0);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark Timers
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- (void)destroySaveTimer {
if (_saveTimer) {
dispatch_source_cancel(_saveTimer);
if (_saveTimerSuspended) {
// Must resume a timer before releasing it (or it will crash)
dispatch_resume(_saveTimer);
_saveTimerSuspended = NO;
}
#if !OS_OBJECT_USE_OBJC
dispatch_release(_saveTimer);
#endif
_saveTimer = NULL;
}
}
- (void)updateAndResumeSaveTimer {
if ((_saveTimer != NULL) && (_saveInterval > 0.0) && (_unsavedTime > 0.0)) {
uint64_t interval = (uint64_t)(_saveInterval * (NSTimeInterval) NSEC_PER_SEC);
dispatch_time_t startTime = dispatch_time(_unsavedTime, interval);
dispatch_source_set_timer(_saveTimer, startTime, interval, 1ull * NSEC_PER_SEC);
if (_saveTimerSuspended) {
dispatch_resume(_saveTimer);
_saveTimerSuspended = NO;
}
}
}
- (void)createSuspendedSaveTimer {
if ((_saveTimer == NULL) && (_saveInterval > 0.0)) {
_saveTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, self.loggerQueue);
dispatch_source_set_event_handler(_saveTimer, ^{ @autoreleasepool {
[self performSaveAndSuspendSaveTimer];
} });
_saveTimerSuspended = YES;
}
}
- (void)destroyDeleteTimer {
if (_deleteTimer) {
dispatch_source_cancel(_deleteTimer);
#if !OS_OBJECT_USE_OBJC
dispatch_release(_deleteTimer);
#endif
_deleteTimer = NULL;
}
}
- (void)updateDeleteTimer {
if ((_deleteTimer != NULL) && (_deleteInterval > 0.0) && (_maxAge > 0.0)) {
uint64_t interval = (uint64_t)(_deleteInterval * (NSTimeInterval) NSEC_PER_SEC);
dispatch_time_t startTime;
if (_lastDeleteTime > 0) {
startTime = dispatch_time(_lastDeleteTime, interval);
} else {
startTime = dispatch_time(DISPATCH_TIME_NOW, interval);
}
dispatch_source_set_timer(_deleteTimer, startTime, interval, 1ull * NSEC_PER_SEC);
}
}
- (void)createAndStartDeleteTimer {
if ((_deleteTimer == NULL) && (_deleteInterval > 0.0) && (_maxAge > 0.0)) {
_deleteTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, self.loggerQueue);
if (_deleteTimer != NULL) {
dispatch_source_set_event_handler(_deleteTimer, ^{ @autoreleasepool {
[self performDelete];
} });
[self updateDeleteTimer];
if (_deleteTimer != NULL) {
dispatch_resume(_deleteTimer);
}
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark Configuration
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- (NSUInteger)saveThreshold {
// The design of this method is taken from the DDAbstractLogger implementation.
// For extensive documentation please refer to the DDAbstractLogger implementation.
// Note: The internal implementation MUST access the colorsEnabled variable directly,
// This method is designed explicitly for external access.
//
// Using "self." syntax to go through this method will cause immediate deadlock.
// This is the intended result. Fix it by accessing the ivar directly.
// Great strides have been take to ensure this is safe to do. Plus it's MUCH faster.
NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");
dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
__block NSUInteger result;
dispatch_sync(globalLoggingQueue, ^{
dispatch_sync(self.loggerQueue, ^{
result = _saveThreshold;
});
});
return result;
}
- (void)setSaveThreshold:(NSUInteger)threshold {
dispatch_block_t block = ^{
@autoreleasepool {
if (_saveThreshold != threshold) {
_saveThreshold = threshold;
// Since the saveThreshold has changed,
// we check to see if the current unsavedCount has surpassed the new threshold.
//
// If it has, we immediately save the log.
if ((_unsavedCount >= _saveThreshold) && (_saveThreshold > 0)) {
[self performSaveAndSuspendSaveTimer];
}
}
}
};
// The design of the setter logic below is taken from the DDAbstractLogger implementation.
// For documentation please refer to the DDAbstractLogger implementation.
if ([self isOnInternalLoggerQueue]) {
block();
} else {
dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
dispatch_async(globalLoggingQueue, ^{
dispatch_async(self.loggerQueue, block);
});
}
}
- (NSTimeInterval)saveInterval {
// The design of this method is taken from the DDAbstractLogger implementation.
// For extensive documentation please refer to the DDAbstractLogger implementation.
// Note: The internal implementation MUST access the colorsEnabled variable directly,
// This method is designed explicitly for external access.
//
// Using "self." syntax to go through this method will cause immediate deadlock.
// This is the intended result. Fix it by accessing the ivar directly.
// Great strides have been take to ensure this is safe to do. Plus it's MUCH faster.
NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");
dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
__block NSTimeInterval result;
dispatch_sync(globalLoggingQueue, ^{
dispatch_sync(self.loggerQueue, ^{
result = _saveInterval;
});
});
return result;
}
- (void)setSaveInterval:(NSTimeInterval)interval {
dispatch_block_t block = ^{
@autoreleasepool {
// C99 recommended floating point comparison macro
// Read: isLessThanOrGreaterThan(floatA, floatB)
if (/* saveInterval != interval */ islessgreater(_saveInterval, interval)) {
_saveInterval = interval;
// There are several cases we need to handle here.
//
// 1. If the saveInterval was previously enabled and it just got disabled,
// then we need to stop the saveTimer. (And we might as well release it.)
//
// 2. If the saveInterval was previously disabled and it just got enabled,
// then we need to setup the saveTimer. (Plus we might need to do an immediate save.)
//
// 3. If the saveInterval increased, then we need to reset the timer so that it fires at the later date.
//
// 4. If the saveInterval decreased, then we need to reset the timer so that it fires at an earlier date.
// (Plus we might need to do an immediate save.)
if (_saveInterval > 0.0) {
if (_saveTimer == NULL) {
// Handles #2
//
// Since the saveTimer uses the unsavedTime to calculate it's first fireDate,
// if a save is needed the timer will fire immediately.
[self createSuspendedSaveTimer];
[self updateAndResumeSaveTimer];
} else {
// Handles #3
// Handles #4
//
// Since the saveTimer uses the unsavedTime to calculate it's first fireDate,
// if a save is needed the timer will fire immediately.
[self updateAndResumeSaveTimer];
}
} else if (_saveTimer) {
// Handles #1
[self destroySaveTimer];
}
}
}
};
// The design of the setter logic below is taken from the DDAbstractLogger implementation.
// For documentation please refer to the DDAbstractLogger implementation.
if ([self isOnInternalLoggerQueue]) {
block();
} else {
dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
dispatch_async(globalLoggingQueue, ^{
dispatch_async(self.loggerQueue, block);
});
}
}
- (NSTimeInterval)maxAge {
// The design of this method is taken from the DDAbstractLogger implementation.
// For extensive documentation please refer to the DDAbstractLogger implementation.
// Note: The internal implementation MUST access the colorsEnabled variable directly,
// This method is designed explicitly for external access.
//
// Using "self." syntax to go through this method will cause immediate deadlock.
// This is the intended result. Fix it by accessing the ivar directly.
// Great strides have been take to ensure this is safe to do. Plus it's MUCH faster.
NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");
dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
__block NSTimeInterval result;
dispatch_sync(globalLoggingQueue, ^{
dispatch_sync(self.loggerQueue, ^{
result = _maxAge;
});
});
return result;
}
- (void)setMaxAge:(NSTimeInterval)interval {
dispatch_block_t block = ^{
@autoreleasepool {
// C99 recommended floating point comparison macro
// Read: isLessThanOrGreaterThan(floatA, floatB)
if (/* maxAge != interval */ islessgreater(_maxAge, interval)) {
NSTimeInterval oldMaxAge = _maxAge;
NSTimeInterval newMaxAge = interval;
_maxAge = interval;
// There are several cases we need to handle here.
//
// 1. If the maxAge was previously enabled and it just got disabled,
// then we need to stop the deleteTimer. (And we might as well release it.)
//
// 2. If the maxAge was previously disabled and it just got enabled,
// then we need to setup the deleteTimer. (Plus we might need to do an immediate delete.)
//
// 3. If the maxAge was increased,
// then we don't need to do anything.
//
// 4. If the maxAge was decreased,
// then we should do an immediate delete.
BOOL shouldDeleteNow = NO;
if (oldMaxAge > 0.0) {
if (newMaxAge <= 0.0) {
// Handles #1
[self destroyDeleteTimer];
} else if (oldMaxAge > newMaxAge) {
// Handles #4
shouldDeleteNow = YES;
}
} else if (newMaxAge > 0.0) {
// Handles #2
shouldDeleteNow = YES;
}
if (shouldDeleteNow) {
[self performDelete];
if (_deleteTimer) {
[self updateDeleteTimer];
} else {
[self createAndStartDeleteTimer];
}
}
}
}
};
// The design of the setter logic below is taken from the DDAbstractLogger implementation.
// For documentation please refer to the DDAbstractLogger implementation.
if ([self isOnInternalLoggerQueue]) {
block();
} else {
dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
dispatch_async(globalLoggingQueue, ^{
dispatch_async(self.loggerQueue, block);
});
}
}
- (NSTimeInterval)deleteInterval {
// The design of this method is taken from the DDAbstractLogger implementation.
// For extensive documentation please refer to the DDAbstractLogger implementation.
// Note: The internal implementation MUST access the colorsEnabled variable directly,
// This method is designed explicitly for external access.
//
// Using "self." syntax to go through this method will cause immediate deadlock.
// This is the intended result. Fix it by accessing the ivar directly.
// Great strides have been take to ensure this is safe to do. Plus it's MUCH faster.
NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");
dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
__block NSTimeInterval result;
dispatch_sync(globalLoggingQueue, ^{
dispatch_sync(self.loggerQueue, ^{
result = _deleteInterval;
});
});
return result;
}
- (void)setDeleteInterval:(NSTimeInterval)interval {
dispatch_block_t block = ^{
@autoreleasepool {
// C99 recommended floating point comparison macro
// Read: isLessThanOrGreaterThan(floatA, floatB)
if (/* deleteInterval != interval */ islessgreater(_deleteInterval, interval)) {
_deleteInterval = interval;
// There are several cases we need to handle here.
//
// 1. If the deleteInterval was previously enabled and it just got disabled,
// then we need to stop the deleteTimer. (And we might as well release it.)
//
// 2. If the deleteInterval was previously disabled and it just got enabled,
// then we need to setup the deleteTimer. (Plus we might need to do an immediate delete.)
//
// 3. If the deleteInterval increased, then we need to reset the timer so that it fires at the later date.
//
// 4. If the deleteInterval decreased, then we need to reset the timer so that it fires at an earlier date.
// (Plus we might need to do an immediate delete.)
if (_deleteInterval > 0.0) {
if (_deleteTimer == NULL) {
// Handles #2
//
// Since the deleteTimer uses the lastDeleteTime to calculate it's first fireDate,
// if a delete is needed the timer will fire immediately.
[self createAndStartDeleteTimer];
} else {
// Handles #3
// Handles #4
//
// Since the deleteTimer uses the lastDeleteTime to calculate it's first fireDate,
// if a save is needed the timer will fire immediately.
[self updateDeleteTimer];
}
} else if (_deleteTimer) {
// Handles #1
[self destroyDeleteTimer];
}
}
}
};
// The design of the setter logic below is taken from the DDAbstractLogger implementation.
// For documentation please refer to the DDAbstractLogger implementation.
if ([self isOnInternalLoggerQueue]) {
block();
} else {
dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
dispatch_async(globalLoggingQueue, ^{
dispatch_async(self.loggerQueue, block);
});
}
}
- (BOOL)deleteOnEverySave {
// The design of this method is taken from the DDAbstractLogger implementation.
// For extensive documentation please refer to the DDAbstractLogger implementation.
// Note: The internal implementation MUST access the colorsEnabled variable directly,
// This method is designed explicitly for external access.
//
// Using "self." syntax to go through this method will cause immediate deadlock.
// This is the intended result. Fix it by accessing the ivar directly.
// Great strides have been take to ensure this is safe to do. Plus it's MUCH faster.
NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");
dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
__block BOOL result;
dispatch_sync(globalLoggingQueue, ^{
dispatch_sync(self.loggerQueue, ^{
result = _deleteOnEverySave;
});
});
return result;
}
- (void)setDeleteOnEverySave:(BOOL)flag {
dispatch_block_t block = ^{
_deleteOnEverySave = flag;
};
// The design of the setter logic below is taken from the DDAbstractLogger implementation.
// For documentation please refer to the DDAbstractLogger implementation.
if ([self isOnInternalLoggerQueue]) {
block();
} else {
dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
dispatch_async(globalLoggingQueue, ^{
dispatch_async(self.loggerQueue, block);
});
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark Public API
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- (void)savePendingLogEntries {
dispatch_block_t block = ^{
@autoreleasepool {
[self performSaveAndSuspendSaveTimer];
}
};
if ([self isOnInternalLoggerQueue]) {
block();
} else {
dispatch_async(self.loggerQueue, block);
}
}
- (void)deleteOldLogEntries {
dispatch_block_t block = ^{
@autoreleasepool {
[self performDelete];
}
};
if ([self isOnInternalLoggerQueue]) {
block();
} else {
dispatch_async(self.loggerQueue, block);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark DDLogger
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- (void)didAddLogger {
// If you override me be sure to invoke [super didAddLogger];
[self createSuspendedSaveTimer];
[self createAndStartDeleteTimer];
}
- (void)willRemoveLogger {
// If you override me be sure to invoke [super willRemoveLogger];
[self performSaveAndSuspendSaveTimer];
[self destroySaveTimer];
[self destroyDeleteTimer];
}
- (void)logMessage:(DDLogMessage *)logMessage {
if ([self db_log:logMessage]) {
BOOL firstUnsavedEntry = (++_unsavedCount == 1);
if ((_unsavedCount >= _saveThreshold) && (_saveThreshold > 0)) {
[self performSaveAndSuspendSaveTimer];
} else if (firstUnsavedEntry) {
_unsavedTime = dispatch_time(DISPATCH_TIME_NOW, 0);
[self updateAndResumeSaveTimer];
}
}
}
- (void)flush {
// This method is invoked by DDLog's flushLog method.
//
// It is called automatically when the application quits,
// or if the developer invokes DDLog's flushLog method prior to crashing or something.
[self performSaveAndSuspendSaveTimer];
}
@end

View File

@ -0,0 +1,26 @@
// Software License Agreement (BSD License)
//
// Copyright (c) 2010-2016, Deusty, LLC
// All rights reserved.
//
// Redistribution and use of this software in source and binary forms,
// with or without modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Neither the name of Deusty nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific
// prior written permission of Deusty, LLC.
/**
* NSAsset replacement that will output a log message even when assertions are disabled.
**/
#define DDAssert(condition, frmt, ...) \
if (!(condition)) { \
NSString *description = [NSString stringWithFormat:frmt, ## __VA_ARGS__]; \
DDLogError(@"%@", description); \
NSAssert(NO, description); \
}
#define DDAssertCondition(condition) DDAssert(condition, @"Condition not satisfied: %s", #condition)

View File

@ -0,0 +1,512 @@
// Software License Agreement (BSD License)
//
// Copyright (c) 2010-2016, Deusty, LLC
// All rights reserved.
//
// Redistribution and use of this software in source and binary forms,
// with or without modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Neither the name of Deusty nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific
// prior written permission of Deusty, LLC.
// Disable legacy macros
#ifndef DD_LEGACY_MACROS
#define DD_LEGACY_MACROS 0
#endif
#import "DDLog.h"
@class DDLogFileInfo;
/**
* This class provides a logger to write log statements to a file.
**/
// Default configuration and safety/sanity values.
//
// maximumFileSize -> kDDDefaultLogMaxFileSize
// rollingFrequency -> kDDDefaultLogRollingFrequency
// maximumNumberOfLogFiles -> kDDDefaultLogMaxNumLogFiles
// logFilesDiskQuota -> kDDDefaultLogFilesDiskQuota
//
// You should carefully consider the proper configuration values for your application.
extern unsigned long long const kDDDefaultLogMaxFileSize;
extern NSTimeInterval const kDDDefaultLogRollingFrequency;
extern NSUInteger const kDDDefaultLogMaxNumLogFiles;
extern unsigned long long const kDDDefaultLogFilesDiskQuota;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* The LogFileManager protocol is designed to allow you to control all aspects of your log files.
*
* The primary purpose of this is to allow you to do something with the log files after they have been rolled.
* Perhaps you want to compress them to save disk space.
* Perhaps you want to upload them to an FTP server.
* Perhaps you want to run some analytics on the file.
*
* A default LogFileManager is, of course, provided.
* The default LogFileManager simply deletes old log files according to the maximumNumberOfLogFiles property.
*
* This protocol provides various methods to fetch the list of log files.
*
* There are two variants: sorted and unsorted.
* If sorting is not necessary, the unsorted variant is obviously faster.
* The sorted variant will return an array sorted by when the log files were created,
* with the most recently created log file at index 0, and the oldest log file at the end of the array.
*
* You can fetch only the log file paths (full path including name), log file names (name only),
* or an array of `DDLogFileInfo` objects.
* The `DDLogFileInfo` class is documented below, and provides a handy wrapper that
* gives you easy access to various file attributes such as the creation date or the file size.
*/
@protocol DDLogFileManager <NSObject>
@required
// Public properties
/**
* The maximum number of archived log files to keep on disk.
* For example, if this property is set to 3,
* then the LogFileManager will only keep 3 archived log files (plus the current active log file) on disk.
* Once the active log file is rolled/archived, then the oldest of the existing 3 rolled/archived log files is deleted.
*
* You may optionally disable this option by setting it to zero.
**/
@property (readwrite, assign, atomic) NSUInteger maximumNumberOfLogFiles;
/**
* The maximum space that logs can take. On rolling logfile all old logfiles that exceed logFilesDiskQuota will
* be deleted.
*
* You may optionally disable this option by setting it to zero.
**/
@property (readwrite, assign, atomic) unsigned long long logFilesDiskQuota;
// Public methods
/**
* Returns the logs directory (path)
*/
@property (nonatomic, readonly, copy) NSString *logsDirectory;
/**
* Returns an array of `NSString` objects,
* each of which is the filePath to an existing log file on disk.
**/
@property (nonatomic, readonly, strong) NSArray<NSString *> *unsortedLogFilePaths;
/**
* Returns an array of `NSString` objects,
* each of which is the fileName of an existing log file on disk.
**/
@property (nonatomic, readonly, strong) NSArray<NSString *> *unsortedLogFileNames;
/**
* Returns an array of `DDLogFileInfo` objects,
* each representing an existing log file on disk,
* and containing important information about the log file such as it's modification date and size.
**/
@property (nonatomic, readonly, strong) NSArray<DDLogFileInfo *> *unsortedLogFileInfos;
/**
* Just like the `unsortedLogFilePaths` method, but sorts the array.
* The items in the array are sorted by creation date.
* The first item in the array will be the most recently created log file.
**/
@property (nonatomic, readonly, strong) NSArray<NSString *> *sortedLogFilePaths;
/**
* Just like the `unsortedLogFileNames` method, but sorts the array.
* The items in the array are sorted by creation date.
* The first item in the array will be the most recently created log file.
**/
@property (nonatomic, readonly, strong) NSArray<NSString *> *sortedLogFileNames;
/**
* Just like the `unsortedLogFileInfos` method, but sorts the array.
* The items in the array are sorted by creation date.
* The first item in the array will be the most recently created log file.
**/
@property (nonatomic, readonly, strong) NSArray<DDLogFileInfo *> *sortedLogFileInfos;
// Private methods (only to be used by DDFileLogger)
/**
* Generates a new unique log file path, and creates the corresponding log file.
**/
- (NSString *)createNewLogFile;
@optional
// Notifications from DDFileLogger
/**
* Called when a log file was archieved
*/
- (void)didArchiveLogFile:(NSString *)logFilePath NS_SWIFT_NAME(didArchiveLogFile(atPath:));
/**
* Called when the roll action was executed and the log was archieved
*/
- (void)didRollAndArchiveLogFile:(NSString *)logFilePath NS_SWIFT_NAME(didRollAndArchiveLogFile(atPath:));
@end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Default log file manager.
*
* All log files are placed inside the logsDirectory.
* If a specific logsDirectory isn't specified, the default directory is used.
* On Mac, this is in `~/Library/Logs/<Application Name>`.
* On iPhone, this is in `~/Library/Caches/Logs`.
*
* Log files are named `"<bundle identifier> <date> <time>.log"`
* Example: `com.organization.myapp 2013-12-03 17-14.log`
*
* Archived log files are automatically deleted according to the `maximumNumberOfLogFiles` property.
**/
@interface DDLogFileManagerDefault : NSObject <DDLogFileManager>
/**
* Default initializer
*/
- (instancetype)init;
/**
* Designated initialized, requires the logs directory
*/
- (instancetype)initWithLogsDirectory:(NSString *)logsDirectory NS_DESIGNATED_INITIALIZER;
#if TARGET_OS_IPHONE
/*
* Calling this constructor you can override the default "automagically" chosen NSFileProtection level.
* Useful if you are writing a command line utility / CydiaSubstrate addon for iOS that has no NSBundle
* or like SpringBoard no BackgroundModes key in the NSBundle:
* iPhone:~ root# cycript -p SpringBoard
* cy# [NSBundle mainBundle]
* #"NSBundle </System/Library/CoreServices/SpringBoard.app> (loaded)"
* cy# [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UIBackgroundModes"];
* null
* cy#
**/
- (instancetype)initWithLogsDirectory:(NSString *)logsDirectory defaultFileProtectionLevel:(NSFileProtectionType)fileProtectionLevel;
#endif
/*
* Methods to override.
*
* Log files are named `"<bundle identifier> <date> <time>.log"`
* Example: `com.organization.myapp 2013-12-03 17-14.log`
*
* If you wish to change default filename, you can override following two methods.
* - `newLogFileName` method would be called on new logfile creation.
* - `isLogFile:` method would be called to filter logfiles from all other files in logsDirectory.
* You have to parse given filename and return YES if it is logFile.
*
* **NOTE**
* `newLogFileName` returns filename. If appropriate file already exists, number would be added
* to filename before extension. You have to handle this case in isLogFile: method.
*
* Example:
* - newLogFileName returns `"com.organization.myapp 2013-12-03.log"`,
* file `"com.organization.myapp 2013-12-03.log"` would be created.
* - after some time `"com.organization.myapp 2013-12-03.log"` is archived
* - newLogFileName again returns `"com.organization.myapp 2013-12-03.log"`,
* file `"com.organization.myapp 2013-12-03 2.log"` would be created.
* - after some time `"com.organization.myapp 2013-12-03 1.log"` is archived
* - newLogFileName again returns `"com.organization.myapp 2013-12-03.log"`,
* file `"com.organization.myapp 2013-12-03 3.log"` would be created.
**/
/**
* Generates log file name with default format `"<bundle identifier> <date> <time>.log"`
* Example: `MobileSafari 2013-12-03 17-14.log`
*
* You can change it by overriding `newLogFileName` and `isLogFile:` methods.
**/
@property (readonly, copy) NSString *newLogFileName;
/**
* Default log file name is `"<bundle identifier> <date> <time>.log"`.
* Example: `MobileSafari 2013-12-03 17-14.log`
*
* You can change it by overriding `newLogFileName` and `isLogFile:` methods.
**/
- (BOOL)isLogFile:(NSString *)fileName NS_SWIFT_NAME(isLogFile(withName:));
/* Inherited from DDLogFileManager protocol:
@property (readwrite, assign, atomic) NSUInteger maximumNumberOfLogFiles;
@property (readwrite, assign, atomic) NSUInteger logFilesDiskQuota;
- (NSString *)logsDirectory;
- (NSArray *)unsortedLogFilePaths;
- (NSArray *)unsortedLogFileNames;
- (NSArray *)unsortedLogFileInfos;
- (NSArray *)sortedLogFilePaths;
- (NSArray *)sortedLogFileNames;
- (NSArray *)sortedLogFileInfos;
*/
@end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Most users will want file log messages to be prepended with the date and time.
* Rather than forcing the majority of users to write their own formatter,
* we will supply a logical default formatter.
* Users can easily replace this formatter with their own by invoking the `setLogFormatter:` method.
* It can also be removed by calling `setLogFormatter:`, and passing a nil parameter.
*
* In addition to the convenience of having a logical default formatter,
* it will also provide a template that makes it easy for developers to copy and change.
**/
@interface DDLogFileFormatterDefault : NSObject <DDLogFormatter>
/**
* Default initializer
*/
- (instancetype)init;
/**
* Designated initializer, requires a date formatter
*/
- (instancetype)initWithDateFormatter:(NSDateFormatter *)dateFormatter NS_DESIGNATED_INITIALIZER;
@end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* The standard implementation for a file logger
*/
@interface DDFileLogger : DDAbstractLogger <DDLogger> {
DDLogFileInfo *_currentLogFileInfo;
}
/**
* Default initializer
*/
- (instancetype)init;
/**
* Designated initializer, requires a `DDLogFileManager` instance
*/
- (instancetype)initWithLogFileManager:(id <DDLogFileManager>)logFileManager NS_DESIGNATED_INITIALIZER;
/**
* Called when the logger is about to write message. Call super before your implementation.
*/
- (void)willLogMessage NS_REQUIRES_SUPER;
/**
* Called when the logger wrote message. Call super after your implementation.
*/
- (void)didLogMessage NS_REQUIRES_SUPER;
/**
* Called when the logger checks archive or not current log file.
* Override this method to exdend standart behavior. By default returns NO.
*/
- (BOOL)shouldArchiveRecentLogFileInfo:(DDLogFileInfo *)recentLogFileInfo;
/**
* Log File Rolling:
*
* `maximumFileSize`:
* The approximate maximum size (in bytes) to allow log files to grow.
* If a log file is larger than this value after a log statement is appended,
* then the log file is rolled.
*
* `rollingFrequency`
* How often to roll the log file.
* The frequency is given as an `NSTimeInterval`, which is a double that specifies the interval in seconds.
* Once the log file gets to be this old, it is rolled.
*
* `doNotReuseLogFiles`
* When set, will always create a new log file at application launch.
*
* Both the `maximumFileSize` and the `rollingFrequency` are used to manage rolling.
* Whichever occurs first will cause the log file to be rolled.
*
* For example:
* The `rollingFrequency` is 24 hours,
* but the log file surpasses the `maximumFileSize` after only 20 hours.
* The log file will be rolled at that 20 hour mark.
* A new log file will be created, and the 24 hour timer will be restarted.
*
* You may optionally disable rolling due to filesize by setting `maximumFileSize` to zero.
* If you do so, rolling is based solely on `rollingFrequency`.
*
* You may optionally disable rolling due to time by setting `rollingFrequency` to zero (or any non-positive number).
* If you do so, rolling is based solely on `maximumFileSize`.
*
* If you disable both `maximumFileSize` and `rollingFrequency`, then the log file won't ever be rolled.
* This is strongly discouraged.
**/
@property (readwrite, assign) unsigned long long maximumFileSize;
/**
* See description for `maximumFileSize`
*/
@property (readwrite, assign) NSTimeInterval rollingFrequency;
/**
* See description for `maximumFileSize`
*/
@property (readwrite, assign, atomic) BOOL doNotReuseLogFiles;
/**
* The DDLogFileManager instance can be used to retrieve the list of log files,
* and configure the maximum number of archived log files to keep.
*
* @see DDLogFileManager.maximumNumberOfLogFiles
**/
@property (strong, nonatomic, readonly) id <DDLogFileManager> logFileManager;
/**
* When using a custom formatter you can set the `logMessage` method not to append
* `\n` character after each output. This allows for some greater flexibility with
* custom formatters. Default value is YES.
**/
@property (nonatomic, readwrite, assign) BOOL automaticallyAppendNewlineForCustomFormatters;
/**
* You can optionally force the current log file to be rolled with this method.
* CompletionBlock will be called on main queue.
*/
- (void)rollLogFileWithCompletionBlock:(void (^)(void))completionBlock NS_SWIFT_NAME(rollLogFile(withCompletion:));
/**
* Method is deprecated.
* @deprecated Use `rollLogFileWithCompletionBlock:` method instead.
*/
- (void)rollLogFile __attribute((deprecated));
// Inherited from DDAbstractLogger
// - (id <DDLogFormatter>)logFormatter;
// - (void)setLogFormatter:(id <DDLogFormatter>)formatter;
/**
* Returns the log file that should be used.
* If there is an existing log file that is suitable,
* within the constraints of `maximumFileSize` and `rollingFrequency`, then it is returned.
*
* Otherwise a new file is created and returned.
**/
@property (nonatomic, readonly, strong) DDLogFileInfo *currentLogFileInfo;
@end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* `DDLogFileInfo` is a simple class that provides access to various file attributes.
* It provides good performance as it only fetches the information if requested,
* and it caches the information to prevent duplicate fetches.
*
* It was designed to provide quick snapshots of the current state of log files,
* and to help sort log files in an array.
*
* This class does not monitor the files, or update it's cached attribute values if the file changes on disk.
* This is not what the class was designed for.
*
* If you absolutely must get updated values,
* you can invoke the reset method which will clear the cache.
**/
@interface DDLogFileInfo : NSObject
@property (strong, nonatomic, readonly) NSString *filePath;
@property (strong, nonatomic, readonly) NSString *fileName;
#if FOUNDATION_SWIFT_SDK_EPOCH_AT_LEAST(8)
@property (strong, nonatomic, readonly) NSDictionary<NSFileAttributeKey, id> *fileAttributes;
#else
@property (strong, nonatomic, readonly) NSDictionary<NSString *, id> *fileAttributes;
#endif
@property (strong, nonatomic, readonly) NSDate *creationDate;
@property (strong, nonatomic, readonly) NSDate *modificationDate;
@property (nonatomic, readonly) unsigned long long fileSize;
@property (nonatomic, readonly) NSTimeInterval age;
@property (nonatomic, readwrite) BOOL isArchived;
+ (instancetype)logFileWithPath:(NSString *)filePath NS_SWIFT_UNAVAILABLE("Use init(filePath:)");
- (instancetype)init NS_UNAVAILABLE;
- (instancetype)initWithFilePath:(NSString *)filePath NS_DESIGNATED_INITIALIZER;
- (void)reset;
- (void)renameFile:(NSString *)newFileName NS_SWIFT_NAME(renameFile(to:));
#if TARGET_IPHONE_SIMULATOR
// So here's the situation.
// Extended attributes are perfect for what we're trying to do here (marking files as archived).
// This is exactly what extended attributes were designed for.
//
// But Apple screws us over on the simulator.
// Everytime you build-and-go, they copy the application into a new folder on the hard drive,
// and as part of the process they strip extended attributes from our log files.
// Normally, a copy of a file preserves extended attributes.
// So obviously Apple has gone to great lengths to piss us off.
//
// Thus we use a slightly different tactic for marking log files as archived in the simulator.
// That way it "just works" and there's no confusion when testing.
//
// The difference in method names is indicative of the difference in functionality.
// On the simulator we add an attribute by appending a filename extension.
//
// For example:
// "mylog.txt" -> "mylog.archived.txt"
// "mylog" -> "mylog.archived"
- (BOOL)hasExtensionAttributeWithName:(NSString *)attrName;
- (void)addExtensionAttributeWithName:(NSString *)attrName;
- (void)removeExtensionAttributeWithName:(NSString *)attrName;
#else /* if TARGET_IPHONE_SIMULATOR */
// Normal use of extended attributes used everywhere else,
// such as on Macs and on iPhone devices.
- (BOOL)hasExtendedAttributeWithName:(NSString *)attrName;
- (void)addExtendedAttributeWithName:(NSString *)attrName;
- (void)removeExtendedAttributeWithName:(NSString *)attrName;
#endif /* if TARGET_IPHONE_SIMULATOR */
- (NSComparisonResult)reverseCompareByCreationDate:(DDLogFileInfo *)another;
- (NSComparisonResult)reverseCompareByModificationDate:(DDLogFileInfo *)another;
@end

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,75 @@
// Software License Agreement (BSD License)
//
// Copyright (c) 2010-2016, Deusty, LLC
// All rights reserved.
//
// Redistribution and use of this software in source and binary forms,
// with or without modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Neither the name of Deusty nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific
// prior written permission of Deusty, LLC.
/**
* Legacy macros used for 1.9.x backwards compatibility.
*
* Imported by default when importing a DDLog.h directly and DD_LEGACY_MACROS is not defined and set to 0.
**/
#if DD_LEGACY_MACROS
#warning CocoaLumberjack 1.9.x legacy macros enabled. \
Disable legacy macros by importing CocoaLumberjack.h or DDLogMacros.h instead of DDLog.h or add `#define DD_LEGACY_MACROS 0` before importing DDLog.h.
#ifndef LOG_LEVEL_DEF
#define LOG_LEVEL_DEF ddLogLevel
#endif
#define LOG_FLAG_ERROR DDLogFlagError
#define LOG_FLAG_WARN DDLogFlagWarning
#define LOG_FLAG_INFO DDLogFlagInfo
#define LOG_FLAG_DEBUG DDLogFlagDebug
#define LOG_FLAG_VERBOSE DDLogFlagVerbose
#define LOG_LEVEL_OFF DDLogLevelOff
#define LOG_LEVEL_ERROR DDLogLevelError
#define LOG_LEVEL_WARN DDLogLevelWarning
#define LOG_LEVEL_INFO DDLogLevelInfo
#define LOG_LEVEL_DEBUG DDLogLevelDebug
#define LOG_LEVEL_VERBOSE DDLogLevelVerbose
#define LOG_LEVEL_ALL DDLogLevelAll
#define LOG_ASYNC_ENABLED YES
#define LOG_ASYNC_ERROR ( NO && LOG_ASYNC_ENABLED)
#define LOG_ASYNC_WARN (YES && LOG_ASYNC_ENABLED)
#define LOG_ASYNC_INFO (YES && LOG_ASYNC_ENABLED)
#define LOG_ASYNC_DEBUG (YES && LOG_ASYNC_ENABLED)
#define LOG_ASYNC_VERBOSE (YES && LOG_ASYNC_ENABLED)
#define LOG_MACRO(isAsynchronous, lvl, flg, ctx, atag, fnct, frmt, ...) \
[DDLog log : isAsynchronous \
level : lvl \
flag : flg \
context : ctx \
file : __FILE__ \
function : fnct \
line : __LINE__ \
tag : atag \
format : (frmt), ## __VA_ARGS__]
#define LOG_MAYBE(async, lvl, flg, ctx, fnct, frmt, ...) \
do { if(lvl & flg) LOG_MACRO(async, lvl, flg, ctx, nil, fnct, frmt, ##__VA_ARGS__); } while(0)
#define LOG_OBJC_MAYBE(async, lvl, flg, ctx, frmt, ...) \
LOG_MAYBE(async, lvl, flg, ctx, __PRETTY_FUNCTION__, frmt, ## __VA_ARGS__)
#define DDLogError(frmt, ...) LOG_OBJC_MAYBE(LOG_ASYNC_ERROR, LOG_LEVEL_DEF, LOG_FLAG_ERROR, 0, frmt, ##__VA_ARGS__)
#define DDLogWarn(frmt, ...) LOG_OBJC_MAYBE(LOG_ASYNC_WARN, LOG_LEVEL_DEF, LOG_FLAG_WARN, 0, frmt, ##__VA_ARGS__)
#define DDLogInfo(frmt, ...) LOG_OBJC_MAYBE(LOG_ASYNC_INFO, LOG_LEVEL_DEF, LOG_FLAG_INFO, 0, frmt, ##__VA_ARGS__)
#define DDLogDebug(frmt, ...) LOG_OBJC_MAYBE(LOG_ASYNC_DEBUG, LOG_LEVEL_DEF, LOG_FLAG_DEBUG, 0, frmt, ##__VA_ARGS__)
#define DDLogVerbose(frmt, ...) LOG_OBJC_MAYBE(LOG_ASYNC_VERBOSE, LOG_LEVEL_DEF, LOG_FLAG_VERBOSE, 0, frmt, ##__VA_ARGS__)
#endif

View File

@ -0,0 +1,83 @@
// Software License Agreement (BSD License)
//
// Copyright (c) 2010-2016, Deusty, LLC
// All rights reserved.
//
// Redistribution and use of this software in source and binary forms,
// with or without modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Neither the name of Deusty nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific
// prior written permission of Deusty, LLC.
// Disable legacy macros
#ifndef DD_LEGACY_MACROS
#define DD_LEGACY_MACROS 0
#endif
#import "DDLog.h"
/**
* The constant/variable/method responsible for controlling the current log level.
**/
#ifndef LOG_LEVEL_DEF
#define LOG_LEVEL_DEF ddLogLevel
#endif
/**
* Whether async should be used by log messages, excluding error messages that are always sent sync.
**/
#ifndef LOG_ASYNC_ENABLED
#define LOG_ASYNC_ENABLED YES
#endif
/**
* This is the single macro that all other macros below compile into.
* This big multiline macro makes all the other macros easier to read.
**/
#define LOGV_MACRO(isAsynchronous, lvl, flg, ctx, atag, fnct, frmt, avalist) \
[DDLog log : isAsynchronous \
level : lvl \
flag : flg \
context : ctx \
file : __FILE__ \
function : fnct \
line : __LINE__ \
tag : atag \
format : frmt \
args : avalist]
/**
* Define version of the macro that only execute if the log level is above the threshold.
* The compiled versions essentially look like this:
*
* if (logFlagForThisLogMsg & ddLogLevel) { execute log message }
*
* When LOG_LEVEL_DEF is defined as ddLogLevel.
*
* As shown further below, Lumberjack actually uses a bitmask as opposed to primitive log levels.
* This allows for a great amount of flexibility and some pretty advanced fine grained logging techniques.
*
* Note that when compiler optimizations are enabled (as they are for your release builds),
* the log messages above your logging threshold will automatically be compiled out.
*
* (If the compiler sees LOG_LEVEL_DEF/ddLogLevel declared as a constant, the compiler simply checks to see
* if the 'if' statement would execute, and if not it strips it from the binary.)
*
* We also define shorthand versions for asynchronous and synchronous logging.
**/
#define LOGV_MAYBE(async, lvl, flg, ctx, tag, fnct, frmt, avalist) \
do { if(lvl & flg) LOGV_MACRO(async, lvl, flg, ctx, tag, fnct, frmt, avalist); } while(0)
/**
* Ready to use log macros with no context or tag.
**/
#define DDLogVError(frmt, avalist) LOGV_MAYBE(NO, LOG_LEVEL_DEF, DDLogFlagError, 0, nil, __PRETTY_FUNCTION__, frmt, avalist)
#define DDLogVWarn(frmt, avalist) LOGV_MAYBE(LOG_ASYNC_ENABLED, LOG_LEVEL_DEF, DDLogFlagWarning, 0, nil, __PRETTY_FUNCTION__, frmt, avalist)
#define DDLogVInfo(frmt, avalist) LOGV_MAYBE(LOG_ASYNC_ENABLED, LOG_LEVEL_DEF, DDLogFlagInfo, 0, nil, __PRETTY_FUNCTION__, frmt, avalist)
#define DDLogVDebug(frmt, avalist) LOGV_MAYBE(LOG_ASYNC_ENABLED, LOG_LEVEL_DEF, DDLogFlagDebug, 0, nil, __PRETTY_FUNCTION__, frmt, avalist)
#define DDLogVVerbose(frmt, avalist) LOGV_MAYBE(LOG_ASYNC_ENABLED, LOG_LEVEL_DEF, DDLogFlagVerbose, 0, nil, __PRETTY_FUNCTION__, frmt, avalist)

View File

@ -0,0 +1,909 @@
// Software License Agreement (BSD License)
//
// Copyright (c) 2010-2016, Deusty, LLC
// All rights reserved.
//
// Redistribution and use of this software in source and binary forms,
// with or without modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Neither the name of Deusty nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific
// prior written permission of Deusty, LLC.
#import <Foundation/Foundation.h>
// Enable 1.9.x legacy macros if imported directly
#ifndef DD_LEGACY_MACROS
#define DD_LEGACY_MACROS 1
#endif
// DD_LEGACY_MACROS is checked in the file itself
#import "DDLegacyMacros.h"
#if OS_OBJECT_USE_OBJC
#define DISPATCH_QUEUE_REFERENCE_TYPE strong
#else
#define DISPATCH_QUEUE_REFERENCE_TYPE assign
#endif
@class DDLogMessage;
@class DDLoggerInformation;
@protocol DDLogger;
@protocol DDLogFormatter;
/**
* Define the standard options.
*
* We default to only 4 levels because it makes it easier for beginners
* to make the transition to a logging framework.
*
* More advanced users may choose to completely customize the levels (and level names) to suite their needs.
* For more information on this see the "Custom Log Levels" page:
* Documentation/CustomLogLevels.md
*
* Advanced users may also notice that we're using a bitmask.
* This is to allow for custom fine grained logging:
* Documentation/FineGrainedLogging.md
*
* -- Flags --
*
* Typically you will use the LOG_LEVELS (see below), but the flags may be used directly in certain situations.
* For example, say you have a lot of warning log messages, and you wanted to disable them.
* However, you still needed to see your error and info log messages.
* You could accomplish that with the following:
*
* static const DDLogLevel ddLogLevel = DDLogFlagError | DDLogFlagInfo;
*
* When LOG_LEVEL_DEF is defined as ddLogLevel.
*
* Flags may also be consulted when writing custom log formatters,
* as the DDLogMessage class captures the individual flag that caused the log message to fire.
*
* -- Levels --
*
* Log levels are simply the proper bitmask of the flags.
*
* -- Booleans --
*
* The booleans may be used when your logging code involves more than one line.
* For example:
*
* if (LOG_VERBOSE) {
* for (id sprocket in sprockets)
* DDLogVerbose(@"sprocket: %@", [sprocket description])
* }
*
* -- Async --
*
* Defines the default asynchronous options.
* The default philosophy for asynchronous logging is very simple:
*
* Log messages with errors should be executed synchronously.
* After all, an error just occurred. The application could be unstable.
*
* All other log messages, such as debug output, are executed asynchronously.
* After all, if it wasn't an error, then it was just informational output,
* or something the application was easily able to recover from.
*
* -- Changes --
*
* You are strongly discouraged from modifying this file.
* If you do, you make it more difficult on yourself to merge future bug fixes and improvements from the project.
* Instead, create your own MyLogging.h or ApplicationNameLogging.h or CompanyLogging.h
*
* For an example of customizing your logging experience, see the "Custom Log Levels" page:
* Documentation/CustomLogLevels.md
**/
/**
* Flags accompany each log. They are used together with levels to filter out logs.
*/
typedef NS_OPTIONS(NSUInteger, DDLogFlag){
/**
* 0...00001 DDLogFlagError
*/
DDLogFlagError = (1 << 0),
/**
* 0...00010 DDLogFlagWarning
*/
DDLogFlagWarning = (1 << 1),
/**
* 0...00100 DDLogFlagInfo
*/
DDLogFlagInfo = (1 << 2),
/**
* 0...01000 DDLogFlagDebug
*/
DDLogFlagDebug = (1 << 3),
/**
* 0...10000 DDLogFlagVerbose
*/
DDLogFlagVerbose = (1 << 4)
};
/**
* Log levels are used to filter out logs. Used together with flags.
*/
typedef NS_ENUM(NSUInteger, DDLogLevel){
/**
* No logs
*/
DDLogLevelOff = 0,
/**
* Error logs only
*/
DDLogLevelError = (DDLogFlagError),
/**
* Error and warning logs
*/
DDLogLevelWarning = (DDLogLevelError | DDLogFlagWarning),
/**
* Error, warning and info logs
*/
DDLogLevelInfo = (DDLogLevelWarning | DDLogFlagInfo),
/**
* Error, warning, info and debug logs
*/
DDLogLevelDebug = (DDLogLevelInfo | DDLogFlagDebug),
/**
* Error, warning, info, debug and verbose logs
*/
DDLogLevelVerbose = (DDLogLevelDebug | DDLogFlagVerbose),
/**
* All logs (1...11111)
*/
DDLogLevelAll = NSUIntegerMax
};
NS_ASSUME_NONNULL_BEGIN
/**
* Extracts just the file name, no path or extension
*
* @param filePath input file path
* @param copy YES if we want the result to be copied
*
* @return the file name
*/
NSString * __nullable DDExtractFileNameWithoutExtension(const char *filePath, BOOL copy);
/**
* The THIS_FILE macro gives you an NSString of the file name.
* For simplicity and clarity, the file name does not include the full path or file extension.
*
* For example: DDLogWarn(@"%@: Unable to find thingy", THIS_FILE) -> @"MyViewController: Unable to find thingy"
**/
#define THIS_FILE (DDExtractFileNameWithoutExtension(__FILE__, NO))
/**
* The THIS_METHOD macro gives you the name of the current objective-c method.
*
* For example: DDLogWarn(@"%@ - Requires non-nil strings", THIS_METHOD) -> @"setMake:model: requires non-nil strings"
*
* Note: This does NOT work in straight C functions (non objective-c).
* Instead you should use the predefined __FUNCTION__ macro.
**/
#define THIS_METHOD NSStringFromSelector(_cmd)
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* The main class, exposes all logging mechanisms, loggers, ...
* For most of the users, this class is hidden behind the logging functions like `DDLogInfo`
*/
@interface DDLog : NSObject
/**
* Returns the singleton `DDLog`.
* The instance is used by `DDLog` class methods.
*/
@property (class, nonatomic, strong, readonly) DDLog *sharedInstance;
/**
* Provides access to the underlying logging queue.
* This may be helpful to Logger classes for things like thread synchronization.
**/
@property (class, nonatomic, DISPATCH_QUEUE_REFERENCE_TYPE, readonly) dispatch_queue_t loggingQueue;
/**
* Logging Primitive.
*
* This method is used by the macros or logging functions.
* It is suggested you stick with the macros as they're easier to use.
*
* @param asynchronous YES if the logging is done async, NO if you want to force sync
* @param level the log level
* @param flag the log flag
* @param context the context (if any is defined)
* @param file the current file
* @param function the current function
* @param line the current code line
* @param tag potential tag
* @param format the log format
*/
+ (void)log:(BOOL)asynchronous
level:(DDLogLevel)level
flag:(DDLogFlag)flag
context:(NSInteger)context
file:(const char *)file
function:(const char *)function
line:(NSUInteger)line
tag:(id __nullable)tag
format:(NSString *)format, ... NS_FORMAT_FUNCTION(9,10);
/**
* Logging Primitive.
*
* This method is used by the macros or logging functions.
* It is suggested you stick with the macros as they're easier to use.
*
* @param asynchronous YES if the logging is done async, NO if you want to force sync
* @param level the log level
* @param flag the log flag
* @param context the context (if any is defined)
* @param file the current file
* @param function the current function
* @param line the current code line
* @param tag potential tag
* @param format the log format
*/
- (void)log:(BOOL)asynchronous
level:(DDLogLevel)level
flag:(DDLogFlag)flag
context:(NSInteger)context
file:(const char *)file
function:(const char *)function
line:(NSUInteger)line
tag:(id __nullable)tag
format:(NSString *)format, ... NS_FORMAT_FUNCTION(9,10);
/**
* Logging Primitive.
*
* This method can be used if you have a prepared va_list.
* Similar to `log:level:flag:context:file:function:line:tag:format:...`
*
* @param asynchronous YES if the logging is done async, NO if you want to force sync
* @param level the log level
* @param flag the log flag
* @param context the context (if any is defined)
* @param file the current file
* @param function the current function
* @param line the current code line
* @param tag potential tag
* @param format the log format
* @param argList the arguments list as a va_list
*/
+ (void)log:(BOOL)asynchronous
level:(DDLogLevel)level
flag:(DDLogFlag)flag
context:(NSInteger)context
file:(const char *)file
function:(const char *)function
line:(NSUInteger)line
tag:(id __nullable)tag
format:(NSString *)format
args:(va_list)argList NS_SWIFT_NAME(log(asynchronous:level:flag:context:file:function:line:tag:format:arguments:));
/**
* Logging Primitive.
*
* This method can be used if you have a prepared va_list.
* Similar to `log:level:flag:context:file:function:line:tag:format:...`
*
* @param asynchronous YES if the logging is done async, NO if you want to force sync
* @param level the log level
* @param flag the log flag
* @param context the context (if any is defined)
* @param file the current file
* @param function the current function
* @param line the current code line
* @param tag potential tag
* @param format the log format
* @param argList the arguments list as a va_list
*/
- (void)log:(BOOL)asynchronous
level:(DDLogLevel)level
flag:(DDLogFlag)flag
context:(NSInteger)context
file:(const char *)file
function:(const char *)function
line:(NSUInteger)line
tag:(id __nullable)tag
format:(NSString *)format
args:(va_list)argList NS_SWIFT_NAME(log(asynchronous:level:flag:context:file:function:line:tag:format:arguments:));
/**
* Logging Primitive.
*
* This method can be used if you manualy prepared DDLogMessage.
*
* @param asynchronous YES if the logging is done async, NO if you want to force sync
* @param logMessage the log message stored in a `DDLogMessage` model object
*/
+ (void)log:(BOOL)asynchronous
message:(DDLogMessage *)logMessage NS_SWIFT_NAME(log(asynchronous:message:));
/**
* Logging Primitive.
*
* This method can be used if you manualy prepared DDLogMessage.
*
* @param asynchronous YES if the logging is done async, NO if you want to force sync
* @param logMessage the log message stored in a `DDLogMessage` model object
*/
- (void)log:(BOOL)asynchronous
message:(DDLogMessage *)logMessage NS_SWIFT_NAME(log(asynchronous:message:));
/**
* Since logging can be asynchronous, there may be times when you want to flush the logs.
* The framework invokes this automatically when the application quits.
**/
+ (void)flushLog;
/**
* Since logging can be asynchronous, there may be times when you want to flush the logs.
* The framework invokes this automatically when the application quits.
**/
- (void)flushLog;
/**
* Loggers
*
* In order for your log statements to go somewhere, you should create and add a logger.
*
* You can add multiple loggers in order to direct your log statements to multiple places.
* And each logger can be configured separately.
* So you could have, for example, verbose logging to the console, but a concise log file with only warnings & errors.
**/
/**
* Adds the logger to the system.
*
* This is equivalent to invoking `[DDLog addLogger:logger withLogLevel:DDLogLevelAll]`.
**/
+ (void)addLogger:(id <DDLogger>)logger;
/**
* Adds the logger to the system.
*
* This is equivalent to invoking `[DDLog addLogger:logger withLogLevel:DDLogLevelAll]`.
**/
- (void)addLogger:(id <DDLogger>)logger;
/**
* Adds the logger to the system.
*
* The level that you provide here is a preemptive filter (for performance).
* That is, the level specified here will be used to filter out logMessages so that
* the logger is never even invoked for the messages.
*
* More information:
* When you issue a log statement, the logging framework iterates over each logger,
* and checks to see if it should forward the logMessage to the logger.
* This check is done using the level parameter passed to this method.
*
* For example:
*
* `[DDLog addLogger:consoleLogger withLogLevel:DDLogLevelVerbose];`
* `[DDLog addLogger:fileLogger withLogLevel:DDLogLevelWarning];`
*
* `DDLogError(@"oh no");` => gets forwarded to consoleLogger & fileLogger
* `DDLogInfo(@"hi");` => gets forwarded to consoleLogger only
*
* It is important to remember that Lumberjack uses a BITMASK.
* Many developers & third party frameworks may define extra log levels & flags.
* For example:
*
* `#define SOME_FRAMEWORK_LOG_FLAG_TRACE (1 << 6) // 0...1000000`
*
* So if you specify `DDLogLevelVerbose` to this method, you won't see the framework's trace messages.
*
* `(SOME_FRAMEWORK_LOG_FLAG_TRACE & DDLogLevelVerbose) => (01000000 & 00011111) => NO`
*
* Consider passing `DDLogLevelAll` to this method, which has all bits set.
* You can also use the exclusive-or bitwise operator to get a bitmask that has all flags set,
* except the ones you explicitly don't want. For example, if you wanted everything except verbose & debug:
*
* `((DDLogLevelAll ^ DDLogLevelVerbose) | DDLogLevelInfo)`
**/
+ (void)addLogger:(id <DDLogger>)logger withLevel:(DDLogLevel)level;
/**
* Adds the logger to the system.
*
* The level that you provide here is a preemptive filter (for performance).
* That is, the level specified here will be used to filter out logMessages so that
* the logger is never even invoked for the messages.
*
* More information:
* When you issue a log statement, the logging framework iterates over each logger,
* and checks to see if it should forward the logMessage to the logger.
* This check is done using the level parameter passed to this method.
*
* For example:
*
* `[DDLog addLogger:consoleLogger withLogLevel:DDLogLevelVerbose];`
* `[DDLog addLogger:fileLogger withLogLevel:DDLogLevelWarning];`
*
* `DDLogError(@"oh no");` => gets forwarded to consoleLogger & fileLogger
* `DDLogInfo(@"hi");` => gets forwarded to consoleLogger only
*
* It is important to remember that Lumberjack uses a BITMASK.
* Many developers & third party frameworks may define extra log levels & flags.
* For example:
*
* `#define SOME_FRAMEWORK_LOG_FLAG_TRACE (1 << 6) // 0...1000000`
*
* So if you specify `DDLogLevelVerbose` to this method, you won't see the framework's trace messages.
*
* `(SOME_FRAMEWORK_LOG_FLAG_TRACE & DDLogLevelVerbose) => (01000000 & 00011111) => NO`
*
* Consider passing `DDLogLevelAll` to this method, which has all bits set.
* You can also use the exclusive-or bitwise operator to get a bitmask that has all flags set,
* except the ones you explicitly don't want. For example, if you wanted everything except verbose & debug:
*
* `((DDLogLevelAll ^ DDLogLevelVerbose) | DDLogLevelInfo)`
**/
- (void)addLogger:(id <DDLogger>)logger withLevel:(DDLogLevel)level;
/**
* Remove the logger from the system
*/
+ (void)removeLogger:(id <DDLogger>)logger;
/**
* Remove the logger from the system
*/
- (void)removeLogger:(id <DDLogger>)logger;
/**
* Remove all the current loggers
*/
+ (void)removeAllLoggers;
/**
* Remove all the current loggers
*/
- (void)removeAllLoggers;
/**
* Return all the current loggers
*/
@property (class, nonatomic, copy, readonly) NSArray<id<DDLogger>> *allLoggers;
/**
* Return all the current loggers
*/
@property (nonatomic, copy, readonly) NSArray<id<DDLogger>> *allLoggers;
/**
* Return all the current loggers with their level (aka DDLoggerInformation).
*/
@property (class, nonatomic, copy, readonly) NSArray<DDLoggerInformation *> *allLoggersWithLevel;
/**
* Return all the current loggers with their level (aka DDLoggerInformation).
*/
@property (nonatomic, copy, readonly) NSArray<DDLoggerInformation *> *allLoggersWithLevel;
/**
* Registered Dynamic Logging
*
* These methods allow you to obtain a list of classes that are using registered dynamic logging,
* and also provides methods to get and set their log level during run time.
**/
/**
* Returns an array with the classes that are using registered dynamic logging
*/
@property (class, nonatomic, copy, readonly) NSArray<Class> *registeredClasses;
/**
* Returns an array with the classes names that are using registered dynamic logging
*/
@property (class, nonatomic, copy, readonly) NSArray<NSString*> *registeredClassNames;
/**
* Returns the current log level for a certain class
*
* @param aClass `Class` param
*/
+ (DDLogLevel)levelForClass:(Class)aClass;
/**
* Returns the current log level for a certain class
*
* @param aClassName string param
*/
+ (DDLogLevel)levelForClassWithName:(NSString *)aClassName;
/**
* Set the log level for a certain class
*
* @param level the new level
* @param aClass `Class` param
*/
+ (void)setLevel:(DDLogLevel)level forClass:(Class)aClass;
/**
* Set the log level for a certain class
*
* @param level the new level
* @param aClassName string param
*/
+ (void)setLevel:(DDLogLevel)level forClassWithName:(NSString *)aClassName;
@end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* This protocol describes a basic logger behavior.
* Basically, it can log messages, store a logFormatter plus a bunch of optional behaviors.
* (i.e. flush, get its loggerQueue, get its name, ...
*/
@protocol DDLogger <NSObject>
/**
* The log message method
*
* @param logMessage the message (model)
*/
- (void)logMessage:(DDLogMessage *)logMessage NS_SWIFT_NAME(log(message:));
/**
* Formatters may optionally be added to any logger.
*
* If no formatter is set, the logger simply logs the message as it is given in logMessage,
* or it may use its own built in formatting style.
**/
@property (nonatomic, strong) id <DDLogFormatter> logFormatter;
@optional
/**
* Since logging is asynchronous, adding and removing loggers is also asynchronous.
* In other words, the loggers are added and removed at appropriate times with regards to log messages.
*
* - Loggers will not receive log messages that were executed prior to when they were added.
* - Loggers will not receive log messages that were executed after they were removed.
*
* These methods are executed in the logging thread/queue.
* This is the same thread/queue that will execute every logMessage: invocation.
* Loggers may use these methods for thread synchronization or other setup/teardown tasks.
**/
- (void)didAddLogger;
/**
* Since logging is asynchronous, adding and removing loggers is also asynchronous.
* In other words, the loggers are added and removed at appropriate times with regards to log messages.
*
* - Loggers will not receive log messages that were executed prior to when they were added.
* - Loggers will not receive log messages that were executed after they were removed.
*
* These methods are executed in the logging thread/queue given in parameter.
* This is the same thread/queue that will execute every logMessage: invocation.
* Loggers may use the queue parameter to set specific values on the queue with dispatch_set_specific() function.
**/
- (void)didAddLoggerInQueue:(dispatch_queue_t)queue;
/**
* See the above description for `didAddLoger`
*/
- (void)willRemoveLogger;
/**
* Some loggers may buffer IO for optimization purposes.
* For example, a database logger may only save occasionaly as the disk IO is slow.
* In such loggers, this method should be implemented to flush any pending IO.
*
* This allows invocations of DDLog's flushLog method to be propogated to loggers that need it.
*
* Note that DDLog's flushLog method is invoked automatically when the application quits,
* and it may be also invoked manually by the developer prior to application crashes, or other such reasons.
**/
- (void)flush;
/**
* Each logger is executed concurrently with respect to the other loggers.
* Thus, a dedicated dispatch queue is used for each logger.
* Logger implementations may optionally choose to provide their own dispatch queue.
**/
@property (nonatomic, DISPATCH_QUEUE_REFERENCE_TYPE, readonly) dispatch_queue_t loggerQueue;
/**
* If the logger implementation does not choose to provide its own queue,
* one will automatically be created for it.
* The created queue will receive its name from this method.
* This may be helpful for debugging or profiling reasons.
**/
@property (nonatomic, readonly) NSString *loggerName;
@end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* This protocol describes the behavior of a log formatter
*/
@protocol DDLogFormatter <NSObject>
@required
/**
* Formatters may optionally be added to any logger.
* This allows for increased flexibility in the logging environment.
* For example, log messages for log files may be formatted differently than log messages for the console.
*
* For more information about formatters, see the "Custom Formatters" page:
* Documentation/CustomFormatters.md
*
* The formatter may also optionally filter the log message by returning nil,
* in which case the logger will not log the message.
**/
- (NSString * __nullable)formatLogMessage:(DDLogMessage *)logMessage NS_SWIFT_NAME(format(message:));
@optional
/**
* A single formatter instance can be added to multiple loggers.
* These methods provides hooks to notify the formatter of when it's added/removed.
*
* This is primarily for thread-safety.
* If a formatter is explicitly not thread-safe, it may wish to throw an exception if added to multiple loggers.
* Or if a formatter has potentially thread-unsafe code (e.g. NSDateFormatter),
* it could possibly use these hooks to switch to thread-safe versions of the code.
**/
- (void)didAddToLogger:(id <DDLogger>)logger;
/**
* A single formatter instance can be added to multiple loggers.
* These methods provides hooks to notify the formatter of when it's added/removed.
*
* This is primarily for thread-safety.
* If a formatter is explicitly not thread-safe, it may wish to throw an exception if added to multiple loggers.
* Or if a formatter has potentially thread-unsafe code (e.g. NSDateFormatter),
* it could possibly use these hooks to switch to thread-safe versions of the code or use dispatch_set_specific()
.* to add its own specific values.
**/
- (void)didAddToLogger:(id <DDLogger>)logger inQueue:(dispatch_queue_t)queue;
/**
* See the above description for `didAddToLogger:`
*/
- (void)willRemoveFromLogger:(id <DDLogger>)logger;
@end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* This protocol describes a dynamic logging component
*/
@protocol DDRegisteredDynamicLogging
/**
* Implement these methods to allow a file's log level to be managed from a central location.
*
* This is useful if you'd like to be able to change log levels for various parts
* of your code from within the running application.
*
* Imagine pulling up the settings for your application,
* and being able to configure the logging level on a per file basis.
*
* The implementation can be very straight-forward:
*
* ```
* + (int)ddLogLevel
* {
* return ddLogLevel;
* }
*
* + (void)ddSetLogLevel:(DDLogLevel)level
* {
* ddLogLevel = level;
* }
* ```
**/
@property (class, nonatomic, readwrite, setter=ddSetLogLevel:) DDLogLevel ddLogLevel;
@end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifndef NS_DESIGNATED_INITIALIZER
#define NS_DESIGNATED_INITIALIZER
#endif
/**
* Log message options, allow copying certain log elements
*/
typedef NS_OPTIONS(NSInteger, DDLogMessageOptions){
/**
* Use this to use a copy of the file path
*/
DDLogMessageCopyFile = 1 << 0,
/**
* Use this to use a copy of the function name
*/
DDLogMessageCopyFunction = 1 << 1,
/**
* Use this to use avoid a copy of the message
*/
DDLogMessageDontCopyMessage = 1 << 2
};
/**
* The `DDLogMessage` class encapsulates information about the log message.
* If you write custom loggers or formatters, you will be dealing with objects of this class.
**/
@interface DDLogMessage : NSObject <NSCopying>
{
// Direct accessors to be used only for performance
@public
NSString *_message;
DDLogLevel _level;
DDLogFlag _flag;
NSInteger _context;
NSString *_file;
NSString *_fileName;
NSString *_function;
NSUInteger _line;
id _tag;
DDLogMessageOptions _options;
NSDate *_timestamp;
NSString *_threadID;
NSString *_threadName;
NSString *_queueLabel;
}
/**
* Default `init` for empty messages.
*/
- (instancetype)init NS_DESIGNATED_INITIALIZER;
/**
* Standard init method for a log message object.
* Used by the logging primitives. (And the macros use the logging primitives.)
*
* If you find need to manually create logMessage objects, there is one thing you should be aware of:
*
* If no flags are passed, the method expects the file and function parameters to be string literals.
* That is, it expects the given strings to exist for the duration of the object's lifetime,
* and it expects the given strings to be immutable.
* In other words, it does not copy these strings, it simply points to them.
* This is due to the fact that __FILE__ and __FUNCTION__ are usually used to specify these parameters,
* so it makes sense to optimize and skip the unnecessary allocations.
* However, if you need them to be copied you may use the options parameter to specify this.
*
* @param message the message
* @param level the log level
* @param flag the log flag
* @param context the context (if any is defined)
* @param file the current file
* @param function the current function
* @param line the current code line
* @param tag potential tag
* @param options a bitmask which supports DDLogMessageCopyFile and DDLogMessageCopyFunction.
* @param timestamp the log timestamp
*
* @return a new instance of a log message model object
*/
- (instancetype)initWithMessage:(NSString *)message
level:(DDLogLevel)level
flag:(DDLogFlag)flag
context:(NSInteger)context
file:(NSString *)file
function:(NSString * __nullable)function
line:(NSUInteger)line
tag:(id __nullable)tag
options:(DDLogMessageOptions)options
timestamp:(NSDate * __nullable)timestamp NS_DESIGNATED_INITIALIZER;
/**
* Read-only properties
**/
/**
* The log message
*/
@property (readonly, nonatomic) NSString *message;
@property (readonly, nonatomic) DDLogLevel level;
@property (readonly, nonatomic) DDLogFlag flag;
@property (readonly, nonatomic) NSInteger context;
@property (readonly, nonatomic) NSString *file;
@property (readonly, nonatomic) NSString *fileName;
@property (readonly, nonatomic) NSString * __nullable function;
@property (readonly, nonatomic) NSUInteger line;
@property (readonly, nonatomic) id __nullable tag;
@property (readonly, nonatomic) DDLogMessageOptions options;
@property (readonly, nonatomic) NSDate *timestamp;
@property (readonly, nonatomic) NSString *threadID; // ID as it appears in NSLog calculated from the machThreadID
@property (readonly, nonatomic) NSString *threadName;
@property (readonly, nonatomic) NSString *queueLabel;
@end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* The `DDLogger` protocol specifies that an optional formatter can be added to a logger.
* Most (but not all) loggers will want to support formatters.
*
* However, writting getters and setters in a thread safe manner,
* while still maintaining maximum speed for the logging process, is a difficult task.
*
* To do it right, the implementation of the getter/setter has strict requiremenets:
* - Must NOT require the `logMessage:` method to acquire a lock.
* - Must NOT require the `logMessage:` method to access an atomic property (also a lock of sorts).
*
* To simplify things, an abstract logger is provided that implements the getter and setter.
*
* Logger implementations may simply extend this class,
* and they can ACCESS THE FORMATTER VARIABLE DIRECTLY from within their `logMessage:` method!
**/
@interface DDAbstractLogger : NSObject <DDLogger>
{
// Direct accessors to be used only for performance
@public
id <DDLogFormatter> _logFormatter;
dispatch_queue_t _loggerQueue;
}
@property (nonatomic, strong, nullable) id <DDLogFormatter> logFormatter;
@property (nonatomic, DISPATCH_QUEUE_REFERENCE_TYPE) dispatch_queue_t loggerQueue;
// For thread-safety assertions
/**
* Return YES if the current logger uses a global queue for logging
*/
@property (nonatomic, readonly, getter=isOnGlobalLoggingQueue) BOOL onGlobalLoggingQueue;
/**
* Return YES if the current logger uses the internal designated queue for logging
*/
@property (nonatomic, readonly, getter=isOnInternalLoggerQueue) BOOL onInternalLoggerQueue;
@end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@interface DDLoggerInformation : NSObject
@property (nonatomic, readonly) id <DDLogger> logger;
@property (nonatomic, readonly) DDLogLevel level;
+ (DDLoggerInformation *)informationWithLogger:(id <DDLogger>)logger
andLevel:(DDLogLevel)level;
@end
NS_ASSUME_NONNULL_END

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,101 @@
// Software License Agreement (BSD License)
//
// Copyright (c) 2010-2016, Deusty, LLC
// All rights reserved.
//
// Redistribution and use of this software in source and binary forms,
// with or without modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Neither the name of Deusty nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific
// prior written permission of Deusty, LLC.
// Disable legacy macros
#ifndef DD_LEGACY_MACROS
#define DD_LEGACY_MACROS 0
#endif
#import "DDLog.h"
/**
* The constant/variable/method responsible for controlling the current log level.
**/
#ifndef LOG_LEVEL_DEF
#define LOG_LEVEL_DEF ddLogLevel
#endif
/**
* Whether async should be used by log messages, excluding error messages that are always sent sync.
**/
#ifndef LOG_ASYNC_ENABLED
#define LOG_ASYNC_ENABLED YES
#endif
/**
* These are the two macros that all other macros below compile into.
* These big multiline macros makes all the other macros easier to read.
**/
#define LOG_MACRO(isAsynchronous, lvl, flg, ctx, atag, fnct, frmt, ...) \
[DDLog log : isAsynchronous \
level : lvl \
flag : flg \
context : ctx \
file : __FILE__ \
function : fnct \
line : __LINE__ \
tag : atag \
format : (frmt), ## __VA_ARGS__]
#define LOG_MACRO_TO_DDLOG(ddlog, isAsynchronous, lvl, flg, ctx, atag, fnct, frmt, ...) \
[ddlog log : isAsynchronous \
level : lvl \
flag : flg \
context : ctx \
file : __FILE__ \
function : fnct \
line : __LINE__ \
tag : atag \
format : (frmt), ## __VA_ARGS__]
/**
* Define version of the macro that only execute if the log level is above the threshold.
* The compiled versions essentially look like this:
*
* if (logFlagForThisLogMsg & ddLogLevel) { execute log message }
*
* When LOG_LEVEL_DEF is defined as ddLogLevel.
*
* As shown further below, Lumberjack actually uses a bitmask as opposed to primitive log levels.
* This allows for a great amount of flexibility and some pretty advanced fine grained logging techniques.
*
* Note that when compiler optimizations are enabled (as they are for your release builds),
* the log messages above your logging threshold will automatically be compiled out.
*
* (If the compiler sees LOG_LEVEL_DEF/ddLogLevel declared as a constant, the compiler simply checks to see
* if the 'if' statement would execute, and if not it strips it from the binary.)
*
* We also define shorthand versions for asynchronous and synchronous logging.
**/
#define LOG_MAYBE(async, lvl, flg, ctx, tag, fnct, frmt, ...) \
do { if(lvl & flg) LOG_MACRO(async, lvl, flg, ctx, tag, fnct, frmt, ##__VA_ARGS__); } while(0)
#define LOG_MAYBE_TO_DDLOG(ddlog, async, lvl, flg, ctx, tag, fnct, frmt, ...) \
do { if(lvl & flg) LOG_MACRO_TO_DDLOG(ddlog, async, lvl, flg, ctx, tag, fnct, frmt, ##__VA_ARGS__); } while(0)
/**
* Ready to use log macros with no context or tag.
**/
#define DDLogError(frmt, ...) LOG_MAYBE(NO, LOG_LEVEL_DEF, DDLogFlagError, 0, nil, __PRETTY_FUNCTION__, frmt, ##__VA_ARGS__)
#define DDLogWarn(frmt, ...) LOG_MAYBE(LOG_ASYNC_ENABLED, LOG_LEVEL_DEF, DDLogFlagWarning, 0, nil, __PRETTY_FUNCTION__, frmt, ##__VA_ARGS__)
#define DDLogInfo(frmt, ...) LOG_MAYBE(LOG_ASYNC_ENABLED, LOG_LEVEL_DEF, DDLogFlagInfo, 0, nil, __PRETTY_FUNCTION__, frmt, ##__VA_ARGS__)
#define DDLogDebug(frmt, ...) LOG_MAYBE(LOG_ASYNC_ENABLED, LOG_LEVEL_DEF, DDLogFlagDebug, 0, nil, __PRETTY_FUNCTION__, frmt, ##__VA_ARGS__)
#define DDLogVerbose(frmt, ...) LOG_MAYBE(LOG_ASYNC_ENABLED, LOG_LEVEL_DEF, DDLogFlagVerbose, 0, nil, __PRETTY_FUNCTION__, frmt, ##__VA_ARGS__)
#define DDLogErrorToDDLog(ddlog, frmt, ...) LOG_MAYBE_TO_DDLOG(ddlog, NO, LOG_LEVEL_DEF, DDLogFlagError, 0, nil, __PRETTY_FUNCTION__, frmt, ##__VA_ARGS__)
#define DDLogWarnToDDLog(ddlog, frmt, ...) LOG_MAYBE_TO_DDLOG(ddlog, LOG_ASYNC_ENABLED, LOG_LEVEL_DEF, DDLogFlagWarning, 0, nil, __PRETTY_FUNCTION__, frmt, ##__VA_ARGS__)
#define DDLogInfoToDDLog(ddlog, frmt, ...) LOG_MAYBE_TO_DDLOG(ddlog, LOG_ASYNC_ENABLED, LOG_LEVEL_DEF, DDLogFlagInfo, 0, nil, __PRETTY_FUNCTION__, frmt, ##__VA_ARGS__)
#define DDLogDebugToDDLog(ddlog, frmt, ...) LOG_MAYBE_TO_DDLOG(ddlog, LOG_ASYNC_ENABLED, LOG_LEVEL_DEF, DDLogFlagDebug, 0, nil, __PRETTY_FUNCTION__, frmt, ##__VA_ARGS__)
#define DDLogVerboseToDDLog(ddlog, frmt, ...) LOG_MAYBE_TO_DDLOG(ddlog, LOG_ASYNC_ENABLED, LOG_LEVEL_DEF, DDLogFlagVerbose, 0, nil, __PRETTY_FUNCTION__, frmt, ##__VA_ARGS__)

View File

@ -0,0 +1,38 @@
// Software License Agreement (BSD License)
//
// Copyright (c) 2010-2016, Deusty, LLC
// All rights reserved.
//
// Redistribution and use of this software in source and binary forms,
// with or without modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Neither the name of Deusty nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific
// prior written permission of Deusty, LLC.
#import <Foundation/Foundation.h>
// Disable legacy macros
#ifndef DD_LEGACY_MACROS
#define DD_LEGACY_MACROS 0
#endif
#import "DDLog.h"
/**
* This class provides a logger for the Apple os_log facility.
**/
API_AVAILABLE(ios(10.0), macos(10.12), tvos(10.0), watchos(3.0))
@interface DDOSLogger : DDAbstractLogger <DDLogger>
/**
* Singleton method
*
* @return the shared instance
*/
@property (class, readonly, strong) DDOSLogger *sharedInstance;
@end

View File

@ -0,0 +1,77 @@
// Software License Agreement (BSD License)
//
// Copyright (c) 2010-2016, Deusty, LLC
// All rights reserved.
//
// Redistribution and use of this software in source and binary forms,
// with or without modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Neither the name of Deusty nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific
// prior written permission of Deusty, LLC.
#import "DDOSLogger.h"
#import <os/log.h>
static DDOSLogger *sharedInstance;
@implementation DDOSLogger
+ (instancetype)sharedInstance {
static dispatch_once_t DDOSLoggerOnceToken;
dispatch_once(&DDOSLoggerOnceToken, ^{
sharedInstance = [[[self class] alloc] init];
});
return sharedInstance;
}
- (instancetype)init {
if (sharedInstance != nil) {
return nil;
}
if (self = [super init]) {
return self;
}
return nil;
}
- (void)logMessage:(DDLogMessage *)logMessage {
// Skip captured log messages
if ([logMessage->_fileName isEqualToString:@"DDASLLogCapture"]) {
return;
}
NSString * message = _logFormatter ? [_logFormatter formatLogMessage:logMessage] : logMessage->_message;
if (message) {
const char *msg = [message UTF8String];
switch (logMessage->_flag) {
case DDLogFlagError :
os_log_error(OS_LOG_DEFAULT, "%{public}s", msg);
break;
case DDLogFlagWarning :
case DDLogFlagInfo :
os_log_info(OS_LOG_DEFAULT, "%{public}s", msg);
break;
case DDLogFlagDebug :
case DDLogFlagVerbose :
default :
os_log_debug(OS_LOG_DEFAULT, "%{public}s", msg);
break;
}
}
}
- (NSString *)loggerName {
return @"cocoa.lumberjack.osLogger";
}
@end

View File

@ -0,0 +1,178 @@
// Software License Agreement (BSD License)
//
// Copyright (c) 2010-2016, Deusty, LLC
// All rights reserved.
//
// Redistribution and use of this software in source and binary forms,
// with or without modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Neither the name of Deusty nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific
// prior written permission of Deusty, LLC.
// Disable legacy macros
#ifndef DD_LEGACY_MACROS
#define DD_LEGACY_MACROS 0
#endif
#import "DDLog.h"
#define LOG_CONTEXT_ALL INT_MAX
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-function"
#if !(TARGET_OS_OSX)
// iOS or tvOS or watchOS
#import <UIKit/UIColor.h>
typedef UIColor DDColor;
static inline DDColor* DDMakeColor(CGFloat r, CGFloat g, CGFloat b) {return [DDColor colorWithRed:(r/255.0f) green:(g/255.0f) blue:(b/255.0f) alpha:1.0f];}
#elif defined(DD_CLI) || !__has_include(<AppKit/NSColor.h>)
// OS X CLI
#import "CLIColor.h"
typedef CLIColor DDColor;
static inline DDColor* DDMakeColor(CGFloat r, CGFloat g, CGFloat b) {return [DDColor colorWithCalibratedRed:(r/255.0f) green:(g/255.0f) blue:(b/255.0f) alpha:1.0f];}
#else
// OS X with AppKit
#import <AppKit/NSColor.h>
typedef NSColor DDColor;
static inline DDColor* DDMakeColor(CGFloat r, CGFloat g, CGFloat b) {return [DDColor colorWithCalibratedRed:(r/255.0f) green:(g/255.0f) blue:(b/255.0f) alpha:1.0f];}
#endif
#pragma clang diagnostic pop
/**
* This class provides a logger for Terminal output or Xcode console output,
* depending on where you are running your code.
*
* As described in the "Getting Started" page,
* the traditional NSLog() function directs it's output to two places:
*
* - Apple System Log (so it shows up in Console.app)
* - StdErr (if stderr is a TTY, so log statements show up in Xcode console)
*
* To duplicate NSLog() functionality you can simply add this logger and an asl logger.
* However, if you instead choose to use file logging (for faster performance),
* you may choose to use only a file logger and a tty logger.
**/
@interface DDTTYLogger : DDAbstractLogger <DDLogger>
/**
* Singleton method
*/
@property (class, readonly, strong) DDTTYLogger *sharedInstance;
/* Inherited from the DDLogger protocol:
*
* Formatters may optionally be added to any logger.
*
* If no formatter is set, the logger simply logs the message as it is given in logMessage,
* or it may use its own built in formatting style.
*
* More information about formatters can be found here:
* Documentation/CustomFormatters.md
*
* The actual implementation of these methods is inherited from DDAbstractLogger.
- (id <DDLogFormatter>)logFormatter;
- (void)setLogFormatter:(id <DDLogFormatter>)formatter;
*/
/**
* Want to use different colors for different log levels?
* Enable this property.
*
* If you run the application via the Terminal (not Xcode),
* the logger will map colors to xterm-256color or xterm-color (if available).
*
* Xcode does NOT natively support colors in the Xcode debugging console.
* You'll need to install the XcodeColors plugin to see colors in the Xcode console.
* https://github.com/robbiehanson/XcodeColors
*
* The default value is NO.
**/
@property (readwrite, assign) BOOL colorsEnabled;
/**
* When using a custom formatter you can set the `logMessage` method not to append
* `\n` character after each output. This allows for some greater flexibility with
* custom formatters. Default value is YES.
**/
@property (nonatomic, readwrite, assign) BOOL automaticallyAppendNewlineForCustomFormatters;
/**
* The default color set (foregroundColor, backgroundColor) is:
*
* - DDLogFlagError = (red, nil)
* - DDLogFlagWarning = (orange, nil)
*
* You can customize the colors however you see fit.
* Please note that you are passing a flag, NOT a level.
*
* GOOD : [ttyLogger setForegroundColor:pink backgroundColor:nil forFlag:DDLogFlagInfo]; // <- Good :)
* BAD : [ttyLogger setForegroundColor:pink backgroundColor:nil forFlag:DDLogLevelInfo]; // <- BAD! :(
*
* DDLogFlagInfo = 0...00100
* DDLogLevelInfo = 0...00111 <- Would match DDLogFlagInfo and DDLogFlagWarning and DDLogFlagError
*
* If you run the application within Xcode, then the XcodeColors plugin is required.
*
* If you run the application from a shell, then DDTTYLogger will automatically map the given color to
* the closest available color. (xterm-256color or xterm-color which have 256 and 16 supported colors respectively.)
*
* This method invokes setForegroundColor:backgroundColor:forFlag:context: and applies it to `LOG_CONTEXT_ALL`.
**/
- (void)setForegroundColor:(DDColor *)txtColor backgroundColor:(DDColor *)bgColor forFlag:(DDLogFlag)mask;
/**
* Just like setForegroundColor:backgroundColor:flag, but allows you to specify a particular logging context.
*
* A logging context is often used to identify log messages coming from a 3rd party framework,
* although logging context's can be used for many different functions.
*
* Use LOG_CONTEXT_ALL to set the deafult color for all contexts that have no specific color set defined.
*
* Logging context's are explained in further detail here:
* Documentation/CustomContext.md
**/
- (void)setForegroundColor:(DDColor *)txtColor backgroundColor:(DDColor *)bgColor forFlag:(DDLogFlag)mask context:(NSInteger)ctxt;
/**
* Similar to the methods above, but allows you to map DDLogMessage->tag to a particular color profile.
* For example, you could do something like this:
*
* static NSString *const PurpleTag = @"PurpleTag";
*
* #define DDLogPurple(frmt, ...) LOG_OBJC_TAG_MACRO(NO, 0, 0, 0, PurpleTag, frmt, ##__VA_ARGS__)
*
* And then where you configure CocoaLumberjack:
*
* purple = DDMakeColor((64/255.0), (0/255.0), (128/255.0));
*
* or any UIColor/NSColor constructor.
*
* Note: For CLI OS X projects that don't link with AppKit use CLIColor objects instead
*
* [[DDTTYLogger sharedInstance] setForegroundColor:purple backgroundColor:nil forTag:PurpleTag];
* [DDLog addLogger:[DDTTYLogger sharedInstance]];
*
* This would essentially give you a straight NSLog replacement that prints in purple:
*
* DDLogPurple(@"I'm a purple log message!");
**/
- (void)setForegroundColor:(DDColor *)txtColor backgroundColor:(DDColor *)bgColor forTag:(id <NSCopying>)tag;
/**
* Clearing color profiles.
**/
- (void)clearColorsForFlag:(DDLogFlag)mask;
- (void)clearColorsForFlag:(DDLogFlag)mask context:(NSInteger)context;
- (void)clearColorsForTag:(id <NSCopying>)tag;
- (void)clearColorsForAllFlags;
- (void)clearColorsForAllTags;
- (void)clearAllColors;
@end

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,117 @@
// Software License Agreement (BSD License)
//
// Copyright (c) 2010-2016, Deusty, LLC
// All rights reserved.
//
// Redistribution and use of this software in source and binary forms,
// with or without modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Neither the name of Deusty nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific
// prior written permission of Deusty, LLC.
#import <Foundation/Foundation.h>
// Disable legacy macros
#ifndef DD_LEGACY_MACROS
#define DD_LEGACY_MACROS 0
#endif
#import "DDLog.h"
/**
* This class provides a log formatter that filters log statements from a logging context not on the whitelist.
*
* A log formatter can be added to any logger to format and/or filter its output.
* You can learn more about log formatters here:
* Documentation/CustomFormatters.md
*
* You can learn more about logging context's here:
* Documentation/CustomContext.md
*
* But here's a quick overview / refresher:
*
* Every log statement has a logging context.
* These come from the underlying logging macros defined in DDLog.h.
* The default logging context is zero.
* You can define multiple logging context's for use in your application.
* For example, logically separate parts of your app each have a different logging context.
* Also 3rd party frameworks that make use of Lumberjack generally use their own dedicated logging context.
**/
@interface DDContextWhitelistFilterLogFormatter : NSObject <DDLogFormatter>
/**
* Designated default initializer
*/
- (instancetype)init NS_DESIGNATED_INITIALIZER;
/**
* Add a context to the whitelist
*
* @param loggingContext the context
*/
- (void)addToWhitelist:(NSUInteger)loggingContext;
/**
* Remove context from whitelist
*
* @param loggingContext the context
*/
- (void)removeFromWhitelist:(NSUInteger)loggingContext;
/**
* Return the whitelist
*/
@property (readonly, copy) NSArray<NSNumber *> *whitelist;
/**
* Check if a context is on the whitelist
*
* @param loggingContext the context
*/
- (BOOL)isOnWhitelist:(NSUInteger)loggingContext;
@end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* This class provides a log formatter that filters log statements from a logging context on the blacklist.
**/
@interface DDContextBlacklistFilterLogFormatter : NSObject <DDLogFormatter>
- (instancetype)init NS_DESIGNATED_INITIALIZER;
/**
* Add a context to the blacklist
*
* @param loggingContext the context
*/
- (void)addToBlacklist:(NSUInteger)loggingContext;
/**
* Remove context from blacklist
*
* @param loggingContext the context
*/
- (void)removeFromBlacklist:(NSUInteger)loggingContext;
/**
* Return the blacklist
*/
@property (readonly, copy) NSArray<NSNumber *> *blacklist;
/**
* Check if a context is on the blacklist
*
* @param loggingContext the context
*/
- (BOOL)isOnBlacklist:(NSUInteger)loggingContext;
@end

View File

@ -0,0 +1,192 @@
// Software License Agreement (BSD License)
//
// Copyright (c) 2010-2016, Deusty, LLC
// All rights reserved.
//
// Redistribution and use of this software in source and binary forms,
// with or without modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Neither the name of Deusty nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific
// prior written permission of Deusty, LLC.
#import "DDContextFilterLogFormatter.h"
#import <libkern/OSAtomic.h>
#if !__has_feature(objc_arc)
#error This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
#endif
@interface DDLoggingContextSet : NSObject
- (void)addToSet:(NSUInteger)loggingContext;
- (void)removeFromSet:(NSUInteger)loggingContext;
@property (readonly, copy) NSArray *currentSet;
- (BOOL)isInSet:(NSUInteger)loggingContext;
@end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@interface DDContextWhitelistFilterLogFormatter () {
DDLoggingContextSet *_contextSet;
}
@end
@implementation DDContextWhitelistFilterLogFormatter
- (instancetype)init {
if ((self = [super init])) {
_contextSet = [[DDLoggingContextSet alloc] init];
}
return self;
}
- (void)addToWhitelist:(NSUInteger)loggingContext {
[_contextSet addToSet:loggingContext];
}
- (void)removeFromWhitelist:(NSUInteger)loggingContext {
[_contextSet removeFromSet:loggingContext];
}
- (NSArray *)whitelist {
return [_contextSet currentSet];
}
- (BOOL)isOnWhitelist:(NSUInteger)loggingContext {
return [_contextSet isInSet:loggingContext];
}
- (NSString *)formatLogMessage:(DDLogMessage *)logMessage {
if ([self isOnWhitelist:logMessage->_context]) {
return logMessage->_message;
} else {
return nil;
}
}
@end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@interface DDContextBlacklistFilterLogFormatter () {
DDLoggingContextSet *_contextSet;
}
@end
@implementation DDContextBlacklistFilterLogFormatter
- (instancetype)init {
if ((self = [super init])) {
_contextSet = [[DDLoggingContextSet alloc] init];
}
return self;
}
- (void)addToBlacklist:(NSUInteger)loggingContext {
[_contextSet addToSet:loggingContext];
}
- (void)removeFromBlacklist:(NSUInteger)loggingContext {
[_contextSet removeFromSet:loggingContext];
}
- (NSArray *)blacklist {
return [_contextSet currentSet];
}
- (BOOL)isOnBlacklist:(NSUInteger)loggingContext {
return [_contextSet isInSet:loggingContext];
}
- (NSString *)formatLogMessage:(DDLogMessage *)logMessage {
if ([self isOnBlacklist:logMessage->_context]) {
return nil;
} else {
return logMessage->_message;
}
}
@end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@interface DDLoggingContextSet () {
OSSpinLock _lock;
NSMutableSet *_set;
}
@end
@implementation DDLoggingContextSet
- (instancetype)init {
if ((self = [super init])) {
_set = [[NSMutableSet alloc] init];
_lock = OS_SPINLOCK_INIT;
}
return self;
}
- (void)addToSet:(NSUInteger)loggingContext {
OSSpinLockLock(&_lock);
{
[_set addObject:@(loggingContext)];
}
OSSpinLockUnlock(&_lock);
}
- (void)removeFromSet:(NSUInteger)loggingContext {
OSSpinLockLock(&_lock);
{
[_set removeObject:@(loggingContext)];
}
OSSpinLockUnlock(&_lock);
}
- (NSArray *)currentSet {
NSArray *result = nil;
OSSpinLockLock(&_lock);
{
result = [_set allObjects];
}
OSSpinLockUnlock(&_lock);
return result;
}
- (BOOL)isInSet:(NSUInteger)loggingContext {
BOOL result = NO;
OSSpinLockLock(&_lock);
{
result = [_set containsObject:@(loggingContext)];
}
OSSpinLockUnlock(&_lock);
return result;
}
@end

View File

@ -0,0 +1,178 @@
// Software License Agreement (BSD License)
//
// Copyright (c) 2010-2016, Deusty, LLC
// All rights reserved.
//
// Redistribution and use of this software in source and binary forms,
// with or without modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Neither the name of Deusty nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific
// prior written permission of Deusty, LLC.
#import <Foundation/Foundation.h>
#import <libkern/OSAtomic.h>
// Disable legacy macros
#ifndef DD_LEGACY_MACROS
#define DD_LEGACY_MACROS 0
#endif
#import "DDLog.h"
/**
* Log formatter mode
*/
typedef NS_ENUM(NSUInteger, DDDispatchQueueLogFormatterMode){
/**
* This is the default option, means the formatter can be reused between multiple loggers and therefore is thread-safe.
* There is, of course, a performance cost for the thread-safety
*/
DDDispatchQueueLogFormatterModeShareble = 0,
/**
* If the formatter will only be used by a single logger, then the thread-safety can be removed
* @note: there is an assert checking if the formatter is added to multiple loggers and the mode is non-shareble
*/
DDDispatchQueueLogFormatterModeNonShareble,
};
/**
* This class provides a log formatter that prints the dispatch_queue label instead of the mach_thread_id.
*
* A log formatter can be added to any logger to format and/or filter its output.
* You can learn more about log formatters here:
* Documentation/CustomFormatters.md
*
* A typical `NSLog` (or `DDTTYLogger`) prints detailed info as `[<process_id>:<thread_id>]`.
* For example:
*
* `2011-10-17 20:21:45.435 AppName[19928:5207] Your log message here`
*
* Where:
* `- 19928 = process id`
* `- 5207 = thread id (mach_thread_id printed in hex)`
*
* When using grand central dispatch (GCD), this information is less useful.
* This is because a single serial dispatch queue may be run on any thread from an internally managed thread pool.
* For example:
*
* `2011-10-17 20:32:31.111 AppName[19954:4d07] Message from my_serial_dispatch_queue`
* `2011-10-17 20:32:31.112 AppName[19954:5207] Message from my_serial_dispatch_queue`
* `2011-10-17 20:32:31.113 AppName[19954:2c55] Message from my_serial_dispatch_queue`
*
* This formatter allows you to replace the standard `[box:info]` with the dispatch_queue name.
* For example:
*
* `2011-10-17 20:32:31.111 AppName[img-scaling] Message from my_serial_dispatch_queue`
* `2011-10-17 20:32:31.112 AppName[img-scaling] Message from my_serial_dispatch_queue`
* `2011-10-17 20:32:31.113 AppName[img-scaling] Message from my_serial_dispatch_queue`
*
* If the dispatch_queue doesn't have a set name, then it falls back to the thread name.
* If the current thread doesn't have a set name, then it falls back to the mach_thread_id in hex (like normal).
*
* Note: If manually creating your own background threads (via `NSThread/alloc/init` or `NSThread/detachNeThread`),
* you can use `[[NSThread currentThread] setName:(NSString *)]`.
**/
@interface DDDispatchQueueLogFormatter : NSObject <DDLogFormatter>
/**
* Standard init method.
* Configure using properties as desired.
**/
- (instancetype)init NS_DESIGNATED_INITIALIZER;
/**
* Initializer with ability to set the queue mode
*
* @param mode choose between DDDispatchQueueLogFormatterModeShareble and DDDispatchQueueLogFormatterModeNonShareble, depending if the formatter is shared between several loggers or not
*/
- (instancetype)initWithMode:(DDDispatchQueueLogFormatterMode)mode;
/**
* The minQueueLength restricts the minimum size of the [detail box].
* If the minQueueLength is set to 0, there is no restriction.
*
* For example, say a dispatch_queue has a label of "diskIO":
*
* If the minQueueLength is 0: [diskIO]
* If the minQueueLength is 4: [diskIO]
* If the minQueueLength is 5: [diskIO]
* If the minQueueLength is 6: [diskIO]
* If the minQueueLength is 7: [diskIO ]
* If the minQueueLength is 8: [diskIO ]
*
* The default minQueueLength is 0 (no minimum, so [detail box] won't be padded).
*
* If you want every [detail box] to have the exact same width,
* set both minQueueLength and maxQueueLength to the same value.
**/
@property (assign, atomic) NSUInteger minQueueLength;
/**
* The maxQueueLength restricts the number of characters that will be inside the [detail box].
* If the maxQueueLength is 0, there is no restriction.
*
* For example, say a dispatch_queue has a label of "diskIO":
*
* If the maxQueueLength is 0: [diskIO]
* If the maxQueueLength is 4: [disk]
* If the maxQueueLength is 5: [diskI]
* If the maxQueueLength is 6: [diskIO]
* If the maxQueueLength is 7: [diskIO]
* If the maxQueueLength is 8: [diskIO]
*
* The default maxQueueLength is 0 (no maximum, so [detail box] won't be truncated).
*
* If you want every [detail box] to have the exact same width,
* set both minQueueLength and maxQueueLength to the same value.
**/
@property (assign, atomic) NSUInteger maxQueueLength;
/**
* Sometimes queue labels have long names like "com.apple.main-queue",
* but you'd prefer something shorter like simply "main".
*
* This method allows you to set such preferred replacements.
* The above example is set by default.
*
* To remove/undo a previous replacement, invoke this method with nil for the 'shortLabel' parameter.
**/
- (NSString *)replacementStringForQueueLabel:(NSString *)longLabel;
/**
* See the `replacementStringForQueueLabel:` description
*/
- (void)setReplacementString:(NSString *)shortLabel forQueueLabel:(NSString *)longLabel;
@end
/**
* Category on `DDDispatchQueueLogFormatter` to make method declarations easier to extend/modify
**/
@interface DDDispatchQueueLogFormatter (OverridableMethods)
/**
* Date formatter default configuration
*/
- (void)configureDateFormatter:(NSDateFormatter *)dateFormatter;
/**
* Formatter method to transfrom from date to string
*/
- (NSString *)stringFromDate:(NSDate *)date;
/**
* Method to compute the queue thread label
*/
- (NSString *)queueThreadLabelForLogMessage:(DDLogMessage *)logMessage;
/**
* The actual method that formats a message (transforms a `DDLogMessage` model into a printable string)
*/
- (NSString *)formatLogMessage:(DDLogMessage *)logMessage;
@end

View File

@ -0,0 +1,278 @@
// Software License Agreement (BSD License)
//
// Copyright (c) 2010-2016, Deusty, LLC
// All rights reserved.
//
// Redistribution and use of this software in source and binary forms,
// with or without modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Neither the name of Deusty nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific
// prior written permission of Deusty, LLC.
#import "DDDispatchQueueLogFormatter.h"
#import <libkern/OSAtomic.h>
#import <objc/runtime.h>
#if !__has_feature(objc_arc)
#error This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
#endif
@interface DDDispatchQueueLogFormatter () {
DDDispatchQueueLogFormatterMode _mode;
NSString *_dateFormatterKey;
int32_t _atomicLoggerCount;
NSDateFormatter *_threadUnsafeDateFormatter; // Use [self stringFromDate]
OSSpinLock _lock;
NSUInteger _minQueueLength; // _prefix == Only access via atomic property
NSUInteger _maxQueueLength; // _prefix == Only access via atomic property
NSMutableDictionary *_replacements; // _prefix == Only access from within spinlock
}
@end
@implementation DDDispatchQueueLogFormatter
- (instancetype)init {
if ((self = [super init])) {
_mode = DDDispatchQueueLogFormatterModeShareble;
// We need to carefully pick the name for storing in thread dictionary to not
// use a formatter configured by subclass and avoid surprises.
Class cls = [self class];
Class superClass = class_getSuperclass(cls);
SEL configMethodName = @selector(configureDateFormatter:);
Method configMethod = class_getInstanceMethod(cls, configMethodName);
while (class_getInstanceMethod(superClass, configMethodName) == configMethod) {
cls = superClass;
superClass = class_getSuperclass(cls);
}
// now `cls` is the class that provides implementation for `configureDateFormatter:`
_dateFormatterKey = [NSString stringWithFormat:@"%s_NSDateFormatter", class_getName(cls)];
_atomicLoggerCount = 0;
_threadUnsafeDateFormatter = nil;
_minQueueLength = 0;
_maxQueueLength = 0;
_lock = OS_SPINLOCK_INIT;
_replacements = [[NSMutableDictionary alloc] init];
// Set default replacements:
_replacements[@"com.apple.main-thread"] = @"main";
}
return self;
}
- (instancetype)initWithMode:(DDDispatchQueueLogFormatterMode)mode {
if ((self = [self init])) {
_mode = mode;
}
return self;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark Configuration
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@synthesize minQueueLength = _minQueueLength;
@synthesize maxQueueLength = _maxQueueLength;
- (NSString *)replacementStringForQueueLabel:(NSString *)longLabel {
NSString *result = nil;
OSSpinLockLock(&_lock);
{
result = _replacements[longLabel];
}
OSSpinLockUnlock(&_lock);
return result;
}
- (void)setReplacementString:(NSString *)shortLabel forQueueLabel:(NSString *)longLabel {
OSSpinLockLock(&_lock);
{
if (shortLabel) {
_replacements[longLabel] = shortLabel;
} else {
[_replacements removeObjectForKey:longLabel];
}
}
OSSpinLockUnlock(&_lock);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark DDLogFormatter
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- (NSDateFormatter *)createDateFormatter {
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[self configureDateFormatter:formatter];
return formatter;
}
- (void)configureDateFormatter:(NSDateFormatter *)dateFormatter {
[dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4];
[dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss:SSS"];
[dateFormatter setLocale:[NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"]];
NSString *calendarIdentifier = nil;
#if defined(__IPHONE_8_0) || defined(__MAC_10_10)
calendarIdentifier = NSCalendarIdentifierGregorian;
#else
calendarIdentifier = NSGregorianCalendar;
#endif
[dateFormatter setCalendar:[[NSCalendar alloc] initWithCalendarIdentifier:calendarIdentifier]];
}
- (NSString *)stringFromDate:(NSDate *)date {
NSDateFormatter *dateFormatter = nil;
if (_mode == DDDispatchQueueLogFormatterModeNonShareble) {
// Single-threaded mode.
dateFormatter = _threadUnsafeDateFormatter;
if (dateFormatter == nil) {
dateFormatter = [self createDateFormatter];
_threadUnsafeDateFormatter = dateFormatter;
}
} else {
// Multi-threaded mode.
// NSDateFormatter is NOT thread-safe.
NSString *key = _dateFormatterKey;
NSMutableDictionary *threadDictionary = [[NSThread currentThread] threadDictionary];
dateFormatter = threadDictionary[key];
if (dateFormatter == nil) {
dateFormatter = [self createDateFormatter];
threadDictionary[key] = dateFormatter;
}
}
return [dateFormatter stringFromDate:date];
}
- (NSString *)queueThreadLabelForLogMessage:(DDLogMessage *)logMessage {
// As per the DDLogFormatter contract, this method is always invoked on the same thread/dispatch_queue
NSUInteger minQueueLength = self.minQueueLength;
NSUInteger maxQueueLength = self.maxQueueLength;
// Get the name of the queue, thread, or machID (whichever we are to use).
NSString *queueThreadLabel = nil;
BOOL useQueueLabel = YES;
BOOL useThreadName = NO;
if (logMessage->_queueLabel) {
// If you manually create a thread, it's dispatch_queue will have one of the thread names below.
// Since all such threads have the same name, we'd prefer to use the threadName or the machThreadID.
NSArray *names = @[
@"com.apple.root.low-priority",
@"com.apple.root.default-priority",
@"com.apple.root.high-priority",
@"com.apple.root.low-overcommit-priority",
@"com.apple.root.default-overcommit-priority",
@"com.apple.root.high-overcommit-priority"
];
for (NSString * name in names) {
if ([logMessage->_queueLabel isEqualToString:name]) {
useQueueLabel = NO;
useThreadName = [logMessage->_threadName length] > 0;
break;
}
}
} else {
useQueueLabel = NO;
useThreadName = [logMessage->_threadName length] > 0;
}
if (useQueueLabel || useThreadName) {
NSString *fullLabel;
NSString *abrvLabel;
if (useQueueLabel) {
fullLabel = logMessage->_queueLabel;
} else {
fullLabel = logMessage->_threadName;
}
OSSpinLockLock(&_lock);
{
abrvLabel = _replacements[fullLabel];
}
OSSpinLockUnlock(&_lock);
if (abrvLabel) {
queueThreadLabel = abrvLabel;
} else {
queueThreadLabel = fullLabel;
}
} else {
queueThreadLabel = logMessage->_threadID;
}
// Now use the thread label in the output
NSUInteger labelLength = [queueThreadLabel length];
// labelLength > maxQueueLength : truncate
// labelLength < minQueueLength : padding
// : exact
if ((maxQueueLength > 0) && (labelLength > maxQueueLength)) {
// Truncate
return [queueThreadLabel substringToIndex:maxQueueLength];
} else if (labelLength < minQueueLength) {
// Padding
NSUInteger numSpaces = minQueueLength - labelLength;
char spaces[numSpaces + 1];
memset(spaces, ' ', numSpaces);
spaces[numSpaces] = '\0';
return [NSString stringWithFormat:@"%@%s", queueThreadLabel, spaces];
} else {
// Exact
return queueThreadLabel;
}
}
- (NSString *)formatLogMessage:(DDLogMessage *)logMessage {
NSString *timestamp = [self stringFromDate:(logMessage->_timestamp)];
NSString *queueThreadLabel = [self queueThreadLabelForLogMessage:logMessage];
return [NSString stringWithFormat:@"%@ [%@] %@", timestamp, queueThreadLabel, logMessage->_message];
}
- (void)didAddToLogger:(id <DDLogger> __attribute__((unused)))logger {
int32_t count = 0;
count = OSAtomicIncrement32(&_atomicLoggerCount);
NSAssert(count <= 1 || _mode == DDDispatchQueueLogFormatterModeShareble, @"Can't reuse formatter with multiple loggers in non-shareable mode.");
}
- (void)willRemoveFromLogger:(id <DDLogger> __attribute__((unused)))logger {
OSAtomicDecrement32(&_atomicLoggerCount);
}
@end

View File

@ -0,0 +1,56 @@
// Software License Agreement (BSD License)
//
// Copyright (c) 2010-2016, Deusty, LLC
// All rights reserved.
//
// Redistribution and use of this software in source and binary forms,
// with or without modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Neither the name of Deusty nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific
// prior written permission of Deusty, LLC.
#import <Foundation/Foundation.h>
// Disable legacy macros
#ifndef DD_LEGACY_MACROS
#define DD_LEGACY_MACROS 0
#endif
#import "DDLog.h"
/**
* This formatter can be used to chain different formatters together.
* The log message will processed in the order of the formatters added.
**/
@interface DDMultiFormatter : NSObject <DDLogFormatter>
/**
* Array of chained formatters
*/
@property (readonly) NSArray<id<DDLogFormatter>> *formatters;
/**
* Add a new formatter
*/
- (void)addFormatter:(id<DDLogFormatter>)formatter NS_SWIFT_NAME(add(_:));
/**
* Remove a formatter
*/
- (void)removeFormatter:(id<DDLogFormatter>)formatter NS_SWIFT_NAME(remove(_:));
/**
* Remove all existing formatters
*/
- (void)removeAllFormatters NS_SWIFT_NAME(removeAll());
/**
* Check if a certain formatter is used
*/
- (BOOL)isFormattingWithFormatter:(id<DDLogFormatter>)formatter;
@end

View File

@ -0,0 +1,144 @@
// Software License Agreement (BSD License)
//
// Copyright (c) 2010-2016, Deusty, LLC
// All rights reserved.
//
// Redistribution and use of this software in source and binary forms,
// with or without modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Neither the name of Deusty nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific
// prior written permission of Deusty, LLC.
#import "DDMultiFormatter.h"
#if TARGET_OS_IOS
// Compiling for iOS
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 60000 // iOS 6.0 or later
#define NEEDS_DISPATCH_RETAIN_RELEASE 0
#else // iOS 5.X or earlier
#define NEEDS_DISPATCH_RETAIN_RELEASE 1
#endif
#elif TARGET_OS_WATCH || TARGET_OS_TV
// Compiling for watchOS, tvOS
#define NEEDS_DISPATCH_RETAIN_RELEASE 0
#else
// Compiling for Mac OS X
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1080 // Mac OS X 10.8 or later
#define NEEDS_DISPATCH_RETAIN_RELEASE 0
#else // Mac OS X 10.7 or earlier
#define NEEDS_DISPATCH_RETAIN_RELEASE 1
#endif
#endif
#if !__has_feature(objc_arc)
#error This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
#endif
@interface DDMultiFormatter () {
dispatch_queue_t _queue;
NSMutableArray *_formatters;
}
- (DDLogMessage *)logMessageForLine:(NSString *)line originalMessage:(DDLogMessage *)message;
@end
@implementation DDMultiFormatter
- (instancetype)init {
self = [super init];
if (self) {
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
_queue = dispatch_queue_create("cocoa.lumberjack.multiformatter", DISPATCH_QUEUE_CONCURRENT);
#else
_queue = dispatch_queue_create("cocoa.lumberjack.multiformatter", NULL);
#endif
_formatters = [NSMutableArray new];
}
return self;
}
#if NEEDS_DISPATCH_RETAIN_RELEASE
- (void)dealloc {
dispatch_release(_queue);
}
#endif
#pragma mark Processing
- (NSString *)formatLogMessage:(DDLogMessage *)logMessage {
__block NSString *line = logMessage->_message;
dispatch_sync(_queue, ^{
for (id<DDLogFormatter> formatter in _formatters) {
DDLogMessage *message = [self logMessageForLine:line originalMessage:logMessage];
line = [formatter formatLogMessage:message];
if (!line) {
break;
}
}
});
return line;
}
- (DDLogMessage *)logMessageForLine:(NSString *)line originalMessage:(DDLogMessage *)message {
DDLogMessage *newMessage = [message copy];
newMessage->_message = line;
return newMessage;
}
#pragma mark Formatters
- (NSArray *)formatters {
__block NSArray *formatters;
dispatch_sync(_queue, ^{
formatters = [_formatters copy];
});
return formatters;
}
- (void)addFormatter:(id<DDLogFormatter>)formatter {
dispatch_barrier_async(_queue, ^{
[_formatters addObject:formatter];
});
}
- (void)removeFormatter:(id<DDLogFormatter>)formatter {
dispatch_barrier_async(_queue, ^{
[_formatters removeObject:formatter];
});
}
- (void)removeAllFormatters {
dispatch_barrier_async(_queue, ^{
[_formatters removeAllObjects];
});
}
- (BOOL)isFormattingWithFormatter:(id<DDLogFormatter>)formatter {
__block BOOL hasFormatter;
dispatch_sync(_queue, ^{
hasFormatter = [_formatters containsObject:formatter];
});
return hasFormatter;
}
@end

View File

@ -0,0 +1,36 @@
framework module CocoaLumberjack {
umbrella header "CocoaLumberjack.h"
export *
module * { export * }
textual header "DDLogMacros.h"
exclude header "DDLog+LOGV.h"
exclude header "DDLegacyMacros.h"
explicit module DDContextFilterLogFormatter {
header "DDContextFilterLogFormatter.h"
export *
}
explicit module DDDispatchQueueLogFormatter {
header "DDDispatchQueueLogFormatter.h"
export *
}
explicit module DDMultiFormatter {
header "DDMultiFormatter.h"
export *
}
explicit module DDASLLogCapture {
header "DDASLLogCapture.h"
export *
}
explicit module DDAbstractDatabaseLogger {
header "DDAbstractDatabaseLogger.h"
export *
}
}

View File

@ -1,6 +1,6 @@
Software License Agreement (BSD License)
Copyright (c) 2010, Deusty, LLC
Copyright (c) 2010-2016, Deusty, LLC
All rights reserved.
Redistribution and use of this software in source and binary forms,

View File

@ -0,0 +1,194 @@
<p align="center" >
<img src="LumberjackLogo.png" title="Lumberjack logo" float=left>
</p>
CocoaLumberjack
===============
[![Build Status](https://travis-ci.org/CocoaLumberjack/CocoaLumberjack.svg?branch=master)](https://travis-ci.org/CocoaLumberjack/CocoaLumberjack)
[![Pod Version](http://img.shields.io/cocoapods/v/CocoaLumberjack.svg?style=flat)](http://cocoadocs.org/docsets/CocoaLumberjack/)
[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)
[![Pod Platform](http://img.shields.io/cocoapods/p/CocoaLumberjack.svg?style=flat)](http://cocoadocs.org/docsets/CocoaLumberjack/)
[![Pod License](http://img.shields.io/cocoapods/l/CocoaLumberjack.svg?style=flat)](http://opensource.org/licenses/BSD-3-Clause)
[![Reference Status](https://www.versioneye.com/objective-c/cocoalumberjack/reference_badge.svg?style=flat)](https://www.versioneye.com/objective-c/cocoalumberjack/references)
[![codecov](https://codecov.io/gh/CocoaLumberjack/CocoaLumberjack/branch/master/graph/badge.svg)](https://codecov.io/gh/CocoaLumberjack/CocoaLumberjack)
**CocoaLumberjack** is a fast & simple, yet powerful & flexible logging framework for Mac and iOS.
### How to get started
- install via [CocoaPods](http://cocoapods.org)
##### Swift version via CocoaPods
```ruby
platform :ios, '8.0'
# You need to set target when you use CocoaPods 1.0.0 or later.
target 'SampleTarget' do
use_frameworks!
pod 'CocoaLumberjack/Swift'
end
```
Note: `Swift` is a subspec which will include all the Obj-C code plus the Swift one, so this is sufficient.
For more details about how to use Swift with Lumberjack, see [this conversation](https://github.com/CocoaLumberjack/CocoaLumberjack/issues/405).
##### Swift Usage
If you installed using CocoaPods or manually:
```swift
import CocoaLumberjack
```
```swift
DDLog.add(DDTTYLogger.sharedInstance) // TTY = Xcode console
DDLog.add(DDASLLogger.sharedInstance) // ASL = Apple System Logs
let fileLogger: DDFileLogger = DDFileLogger() // File Logger
fileLogger.rollingFrequency = TimeInterval(60*60*24) // 24 hours
fileLogger.logFileManager.maximumNumberOfLogFiles = 7
DDLog.add(fileLogger)
...
DDLogVerbose("Verbose");
DDLogDebug("Debug");
DDLogInfo("Info");
DDLogWarn("Warn");
DDLogError("Error");
```
##### Obj-C version via CocoaPods
```ruby
platform :ios, '7.0'
pod 'CocoaLumberjack'
```
##### Obj-C usage
If you're using Lumberjack as a framework, you can `@import CocoaLumberjack`.
Otherwise, `#import <CocoaLumberjack/CocoaLumberjack.h>`
```objc
[DDLog addLogger:[DDTTYLogger sharedInstance]]; // TTY = Xcode console
[DDLog addLogger:[DDASLLogger sharedInstance]]; // ASL = Apple System Logs
DDFileLogger *fileLogger = [[DDFileLogger alloc] init]; // File Logger
fileLogger.rollingFrequency = 60 * 60 * 24; // 24 hour rolling
fileLogger.logFileManager.maximumNumberOfLogFiles = 7;
[DDLog addLogger:fileLogger];
...
DDLogVerbose(@"Verbose");
DDLogDebug(@"Debug");
DDLogInfo(@"Info");
DDLogWarn(@"Warn");
DDLogError(@"Error");
```
##### Installation with Carthage (iOS 8+)
[Carthage](https://github.com/Carthage/Carthage) is a lightweight dependency manager for Swift and Objective-C. It leverages CocoaTouch modules and is less invasive than CocoaPods.
To install with Carthage, follow the instruction on [Carthage](https://github.com/Carthage/Carthage)
Cartfile
```
github "CocoaLumberjack/CocoaLumberjack"
```
- or [install manually](Documentation/GettingStarted.md#manual-installation)
- read the [Getting started](Documentation/GettingStarted.md) guide, check out the [FAQ](Documentation/FAQ.md) section or the other [docs](Documentation/)
- if you find issues or want to suggest improvements, create an issue or a pull request
- for all kinds of questions involving CocoaLumberjack, use the [Google group](http://groups.google.com/group/cocoalumberjack) or StackOverflow (use [#lumberjack](http://stackoverflow.com/questions/tagged/lumberjack)).
### CocoaLumberjack 3
#### Migrating to 3.x
* To be determined
### Features
#### Lumberjack is Fast & Simple, yet Powerful & Flexible.
It is similar in concept to other popular logging frameworks such as log4j, yet is designed specifically for Objective-C, and takes advantage of features such as multi-threading, grand central dispatch (if available), lockless atomic operations, and the dynamic nature of the Objective-C runtime.
#### Lumberjack is Fast
In most cases it is an order of magnitude faster than NSLog.
#### Lumberjack is Simple
It takes as little as a single line of code to configure lumberjack when your application launches. Then simply replace your NSLog statements with DDLog statements and that's about it. (And the DDLog macros have the exact same format and syntax as NSLog, so it's super easy.)
#### Lumberjack is Powerful:
One log statement can be sent to multiple loggers, meaning you can log to a file and the console simultaneously. Want more? Create your own loggers (it's easy) and send your log statements over the network. Or to a database or distributed file system. The sky is the limit.
#### Lumberjack is Flexible:
Configure your logging however you want. Change log levels per file (perfect for debugging). Change log levels per logger (verbose console, but concise log file). Change log levels per xcode configuration (verbose debug, but concise release). Have your log statements compiled out of the release build. Customize the number of log levels for your application. Add your own fine-grained logging. Dynamically change log levels during runtime. Choose how & when you want your log files to be rolled. Upload your log files to a central server. Compress archived log files to save disk space...
### This framework is for you if:
- You're looking for a way to track down that impossible-to-reproduce bug that keeps popping up in the field.
- You're frustrated with the super short console log on the iPhone.
- You're looking to take your application to the next level in terms of support and stability.
- You're looking for an enterprise level logging solution for your application (Mac or iPhone).
### Documentation
- **[Get started using Lumberjack](Documentation/GettingStarted.md)**<br/>
- [Different log levels for Debug and Release builds](Documentation/XcodeTricks.md)<br/>
- [Different log levels for each logger](Documentation/PerLoggerLogLevels.md)<br/>
- [Use colors in the Xcode debugging console](Documentation/XcodeColors.md)<br/>
- [Write your own custom formatters](Documentation/CustomFormatters.md)<br/>
- [FAQ](Documentation/FAQ.md)<br/>
- [Analysis of performance with benchmarks](Documentation/Performance.md)<br/>
- [Common issues you may encounter and their solutions](Documentation/ProblemSolution.md)<br/>
- [AppCode support](Documentation/AppCode-support.md)
- **[Full Lumberjack documentation](Documentation/)**<br/>
### Requirements
The current version of Lumberjack requires:
- Xcode 8 or later
- Swift 3.0 or later
- iOS 5 or later
- OS X 10.7 or later
- WatchOS 2 or later
- TVOS 9 or later
#### Backwards compability
- for Xcode 7.3 and Swift 2.3, use the 2.4.0 version
- for Xcode 7.3 and Swift 2.2, use the 2.3.0 version
- for Xcode 7.2 and 7.1, use the 2.2.0 version
- for Xcode 7.0 or earlier, use the 2.1.0 version
- for Xcode 6 or earlier, use the 2.0.x version
- for OS X < 10.7 support, use the 1.6.0 version
### Communication
- If you **need help**, use [Stack Overflow](http://stackoverflow.com/questions/tagged/lumberjack). (Tag 'lumberjack')
- If you'd like to **ask a general question**, use [Stack Overflow](http://stackoverflow.com/questions/tagged/lumberjack).
- If you **found a bug**, open an issue.
- If you **have a feature request**, open an issue.
- If you **want to contribute**, submit a pull request.
### Author
- [Robbie Hanson](https://github.com/robbiehanson)
- Love the project? Wanna buy me a coffee? (or a beer :D) [![donation](http://www.paypal.com/en_US/i/btn/btn_donate_SM.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=UZRA26JPJB3DA)
### Collaborators
- [Ernesto Rivera](https://github.com/rivera-ernesto)
- [Dmitry Vorobyov](https://github.com/dvor)
- [Bogdan Poplauschi](https://github.com/bpoplauschi)
- [C.W. Betts](https://github.com/MaddTheSane)
### License
- CocoaLumberjack is available under the BSD license. See the [LICENSE file](https://github.com/CocoaLumberjack/CocoaLumberjack/blob/master/LICENSE.txt).
### Architecture
<p align="center" >
<img src="Documentation/CocoaLumberjackClassDiagram.png" title="CocoaLumberjack class diagram">
</p>

View File

@ -0,0 +1 @@
../../../CocoaLumberjack/Classes/CocoaLumberjack.h

View File

@ -0,0 +1 @@
../../../CocoaLumberjack/Classes/DDASLLogCapture.h

View File

@ -0,0 +1 @@
../../../CocoaLumberjack/Classes/DDASLLogger.h

View File

@ -0,0 +1 @@
../../../CocoaLumberjack/Classes/DDAbstractDatabaseLogger.h

View File

@ -0,0 +1 @@
../../../CocoaLumberjack/Classes/DDAssertMacros.h

View File

@ -0,0 +1 @@
../../../CocoaLumberjack/Classes/Extensions/DDContextFilterLogFormatter.h

View File

@ -0,0 +1 @@
../../../CocoaLumberjack/Classes/Extensions/DDDispatchQueueLogFormatter.h

View File

@ -0,0 +1 @@
../../../CocoaLumberjack/Classes/DDFileLogger.h

View File

@ -0,0 +1 @@
../../../CocoaLumberjack/Classes/DDLegacyMacros.h

View File

@ -0,0 +1 @@
../../../CocoaLumberjack/Classes/DDLog+LOGV.h

View File

@ -0,0 +1 @@
../../../CocoaLumberjack/Classes/DDLog.h

View File

@ -0,0 +1 @@
../../../CocoaLumberjack/Classes/DDLogMacros.h

View File

@ -0,0 +1 @@
../../../CocoaLumberjack/Classes/Extensions/DDMultiFormatter.h

View File

@ -0,0 +1 @@
../../../CocoaLumberjack/Classes/DDOSLogger.h

View File

@ -0,0 +1 @@
../../../CocoaLumberjack/Classes/DDTTYLogger.h

View File

@ -0,0 +1 @@
../../../Reachability/Reachability.h

View File

@ -0,0 +1 @@
../../../../../../YapDatabase/Internal/NSDate+YapDatabase.h

View File

@ -0,0 +1 @@
../../../../../../YapDatabase/Internal/NSDictionary+YapDatabase.h

View File

@ -0,0 +1 @@
../../../../../../YapDatabase/Extensions/CloudKit/Internal/YDBCKAttachRequest.h

View File

@ -0,0 +1 @@
../../../../../../YapDatabase/Extensions/CloudKit/Internal/YDBCKChangeQueue.h

View File

@ -0,0 +1 @@
../../../../../../YapDatabase/Extensions/CloudKit/Internal/YDBCKChangeRecord.h

View File

@ -0,0 +1 @@
../../../../../../YapDatabase/Extensions/CloudKit/Utilities/YDBCKChangeSet.h

View File

@ -0,0 +1 @@
../../../../../../YapDatabase/Extensions/CloudKit/Internal/YDBCKMappingTableInfo.h

View File

@ -0,0 +1 @@
../../../../../../YapDatabase/Extensions/CloudKit/Utilities/YDBCKMergeInfo.h

View File

@ -0,0 +1 @@
../../../../../../YapDatabase/Extensions/CloudKit/Utilities/YDBCKRecord.h

View File

@ -0,0 +1 @@
../../../../../../YapDatabase/Extensions/CloudKit/Utilities/YDBCKRecordInfo.h

View File

@ -0,0 +1 @@
../../../../../../YapDatabase/Extensions/CloudKit/Internal/YDBCKRecordTableInfo.h

View File

@ -0,0 +1 @@
../../../../../../YapDatabase/Extensions/ActionManager/YapActionItem.h

View File

@ -0,0 +1 @@
../../../../../../YapDatabase/Extensions/ActionManager/Internal/YapActionItemPrivate.h

View File

@ -0,0 +1 @@
../../../../../../YapDatabase/Extensions/ActionManager/YapActionable.h

View File

@ -0,0 +1 @@
../../../../../../YapDatabase/Utilities/YapBidirectionalCache.h

View File

@ -0,0 +1 @@
../../../../../../YapDatabase/Utilities/YapCache.h

View File

@ -0,0 +1 @@
../../../../../../YapDatabase/Utilities/YapCollectionKey.h

View File

@ -0,0 +1 @@
../../../../../../YapDatabase/YapDatabase.h

View File

@ -0,0 +1 @@
../../../../../../YapDatabase/Extensions/ActionManager/YapDatabaseActionManager.h

View File

@ -0,0 +1 @@
../../../../../../YapDatabase/Extensions/ActionManager/YapDatabaseActionManagerConnection.h

Some files were not shown because too many files have changed in this diff Show More