motion-yapper 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (296) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -2
  3. data/.travis.yml +2 -0
  4. data/Gemfile +1 -0
  5. data/README.md +1 -1
  6. data/Rakefile +1 -1
  7. data/lib/motion-yapper.rb +1 -0
  8. data/lib/yapper.rb +3 -5
  9. data/lib/yapper/config.rb +2 -0
  10. data/lib/yapper/db.rb +105 -40
  11. data/lib/yapper/document.rb +7 -4
  12. data/lib/yapper/document/callbacks.rb +0 -7
  13. data/lib/yapper/document/{persistance.rb → persistence.rb} +27 -21
  14. data/lib/yapper/document/relation.rb +29 -22
  15. data/lib/yapper/document/selection.rb +122 -54
  16. data/lib/yapper/extensions.rb +12 -24
  17. data/lib/yapper/settings.rb +43 -0
  18. data/lib/yapper/timestamps.rb +2 -0
  19. data/lib/yapper/version.rb +1 -1
  20. data/{yapper.gemspec → motion-yapper.gemspec} +0 -0
  21. data/spec/integration/{where_spec.rb → criteria_spec.rb} +78 -10
  22. data/spec/integration/db_spec.rb +70 -0
  23. data/spec/integration/defaults_spec.rb +37 -0
  24. data/spec/integration/extensions_spec.rb +14 -0
  25. data/spec/integration/{persistance_spec.rb → persistence_spec.rb} +0 -0
  26. data/spec/integration/relation_spec.rb +4 -4
  27. data/vendor/Podfile.lock +9 -11
  28. data/vendor/Pods/.build/libPods-CocoaLumberjack.a +0 -0
  29. data/vendor/Pods/.build/libPods-NSData+MD5Digest.a +0 -0
  30. data/vendor/Pods/.build/libPods-YapDatabase.a +0 -0
  31. data/vendor/Pods/.build/libPods.a +0 -0
  32. data/vendor/Pods/BuildHeaders/CocoaLumberjack/DDASLLogger.h +4 -4
  33. data/vendor/Pods/BuildHeaders/CocoaLumberjack/DDAbstractDatabaseLogger.h +14 -14
  34. data/vendor/Pods/{CocoaLumberjack/Lumberjack/Extensions/ContextFilterLogFormatter.h → BuildHeaders/CocoaLumberjack/DDContextFilterLogFormatter.h} +6 -8
  35. data/vendor/Pods/BuildHeaders/CocoaLumberjack/{DispatchQueueLogFormatter.h → DDDispatchQueueLogFormatter.h} +18 -6
  36. data/vendor/Pods/BuildHeaders/CocoaLumberjack/DDFileLogger.h +67 -32
  37. data/vendor/Pods/BuildHeaders/CocoaLumberjack/DDLog+LOGV.h +99 -0
  38. data/vendor/Pods/BuildHeaders/CocoaLumberjack/DDLog.h +98 -65
  39. data/vendor/Pods/BuildHeaders/CocoaLumberjack/DDMultiFormatter.h +30 -0
  40. data/vendor/Pods/BuildHeaders/CocoaLumberjack/DDTTYLogger.h +39 -25
  41. data/vendor/Pods/BuildHeaders/YapDatabase/NSDictionary+YapDatabase.h +8 -0
  42. data/vendor/Pods/BuildHeaders/YapDatabase/YapCache.h +1 -0
  43. data/vendor/Pods/BuildHeaders/YapDatabase/YapCollectionKey.h +3 -0
  44. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabase.h +4 -4
  45. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseConnection.h +21 -19
  46. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseDefaults.h +1 -1
  47. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseExtensionPrivate.h +35 -31
  48. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseFilteredView.h +8 -35
  49. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseFilteredViewPrivate.h +0 -2
  50. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseFilteredViewTransaction.h +17 -17
  51. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseFilteredViewTypes.h +32 -0
  52. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseFullTextSearchPrivate.h +8 -0
  53. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabasePrivate.h +43 -21
  54. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseRelationship.h +35 -0
  55. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseRelationshipConnection.h +29 -0
  56. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseRelationshipEdge.h +163 -0
  57. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseRelationshipEdgePrivate.h +79 -0
  58. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseRelationshipNode.h +99 -0
  59. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseRelationshipOptions.h +59 -0
  60. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseRelationshipPrivate.h +125 -0
  61. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseRelationshipTransaction.h +384 -0
  62. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseSecondaryIndex.h +49 -0
  63. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseSecondaryIndexPrivate.h +10 -0
  64. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseSecondaryIndexSetupPrivate.h +18 -0
  65. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseTransaction.h +131 -21
  66. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseView.h +48 -107
  67. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewChange.h +2 -2
  68. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewConnection.h +1 -0
  69. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewMappings.h +17 -0
  70. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewOptions.h +10 -3
  71. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewPrivate.h +18 -1
  72. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewTransaction.h +75 -24
  73. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewTypes.h +99 -0
  74. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDASLLogger.h +4 -4
  75. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDASLLogger.m +51 -50
  76. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDAbstractDatabaseLogger.h +14 -14
  77. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDAbstractDatabaseLogger.m +546 -546
  78. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDFileLogger.h +67 -32
  79. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDFileLogger.m +1093 -907
  80. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDLog+LOGV.h +99 -0
  81. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDLog.h +98 -65
  82. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDLog.m +873 -748
  83. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDTTYLogger.h +39 -25
  84. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDTTYLogger.m +1284 -1243
  85. data/vendor/Pods/{BuildHeaders/CocoaLumberjack/ContextFilterLogFormatter.h → CocoaLumberjack/Lumberjack/Extensions/DDContextFilterLogFormatter.h} +6 -8
  86. data/vendor/Pods/CocoaLumberjack/Lumberjack/Extensions/{ContextFilterLogFormatter.m → DDContextFilterLogFormatter.m} +70 -70
  87. data/vendor/Pods/CocoaLumberjack/Lumberjack/Extensions/{DispatchQueueLogFormatter.h → DDDispatchQueueLogFormatter.h} +18 -6
  88. data/vendor/Pods/CocoaLumberjack/Lumberjack/Extensions/DDDispatchQueueLogFormatter.m +253 -0
  89. data/vendor/Pods/CocoaLumberjack/Lumberjack/Extensions/DDMultiFormatter.h +30 -0
  90. data/vendor/Pods/CocoaLumberjack/Lumberjack/Extensions/DDMultiFormatter.m +127 -0
  91. data/vendor/Pods/CocoaLumberjack/Lumberjack/Extensions/README.txt +1 -1
  92. data/vendor/Pods/CocoaLumberjack/README.markdown +52 -15
  93. data/vendor/Pods/Headers/CocoaLumberjack/DDASLLogger.h +4 -4
  94. data/vendor/Pods/Headers/CocoaLumberjack/DDAbstractDatabaseLogger.h +14 -14
  95. data/vendor/Pods/Headers/CocoaLumberjack/{ContextFilterLogFormatter.h → DDContextFilterLogFormatter.h} +6 -8
  96. data/vendor/Pods/Headers/CocoaLumberjack/{DispatchQueueLogFormatter.h → DDDispatchQueueLogFormatter.h} +18 -6
  97. data/vendor/Pods/Headers/CocoaLumberjack/DDFileLogger.h +67 -32
  98. data/vendor/Pods/Headers/CocoaLumberjack/DDLog+LOGV.h +99 -0
  99. data/vendor/Pods/Headers/CocoaLumberjack/DDLog.h +98 -65
  100. data/vendor/Pods/Headers/CocoaLumberjack/DDMultiFormatter.h +30 -0
  101. data/vendor/Pods/Headers/CocoaLumberjack/DDTTYLogger.h +39 -25
  102. data/vendor/Pods/Headers/YapDatabase/YapCollectionKey.h +3 -0
  103. data/vendor/Pods/Headers/YapDatabase/YapDatabase.h +4 -4
  104. data/vendor/Pods/Headers/YapDatabase/YapDatabaseConnection.h +21 -19
  105. data/vendor/Pods/Headers/YapDatabase/YapDatabaseFilteredView.h +8 -35
  106. data/vendor/Pods/Headers/YapDatabase/YapDatabaseFilteredViewTransaction.h +17 -17
  107. data/vendor/Pods/Headers/YapDatabase/YapDatabaseFilteredViewTypes.h +32 -0
  108. data/vendor/Pods/Headers/YapDatabase/YapDatabaseRelationship.h +35 -0
  109. data/vendor/Pods/Headers/YapDatabase/YapDatabaseRelationshipConnection.h +29 -0
  110. data/vendor/Pods/Headers/YapDatabase/YapDatabaseRelationshipEdge.h +163 -0
  111. data/vendor/Pods/Headers/YapDatabase/YapDatabaseRelationshipNode.h +99 -0
  112. data/vendor/Pods/Headers/YapDatabase/YapDatabaseRelationshipOptions.h +59 -0
  113. data/vendor/Pods/Headers/YapDatabase/YapDatabaseRelationshipTransaction.h +384 -0
  114. data/vendor/Pods/Headers/YapDatabase/YapDatabaseSecondaryIndex.h +49 -0
  115. data/vendor/Pods/Headers/YapDatabase/YapDatabaseTransaction.h +131 -21
  116. data/vendor/Pods/Headers/YapDatabase/YapDatabaseView.h +48 -107
  117. data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewChange.h +2 -2
  118. data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewConnection.h +1 -0
  119. data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewMappings.h +17 -0
  120. data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewOptions.h +10 -3
  121. data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewTransaction.h +75 -24
  122. data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewTypes.h +99 -0
  123. data/vendor/Pods/Headers/____Pods-CocoaLumberjack-prefix.h +2 -0
  124. data/vendor/Pods/Headers/____Pods-environment.h +15 -15
  125. data/vendor/Pods/Manifest.lock +9 -11
  126. data/vendor/Pods/Pods-CocoaLumberjack-Private.xcconfig +1 -1
  127. data/vendor/Pods/Pods-CocoaLumberjack-prefix.pch +2 -0
  128. data/vendor/Pods/Pods-NSData+MD5Digest-Private.xcconfig +1 -1
  129. data/vendor/Pods/Pods-YapDatabase-Private.xcconfig +1 -1
  130. data/vendor/Pods/{Pods-Acknowledgements.markdown → Pods-acknowledgements.markdown} +0 -37
  131. data/vendor/Pods/{Pods-Acknowledgements.plist → Pods-acknowledgements.plist} +0 -45
  132. data/vendor/Pods/Pods-environment.h +15 -15
  133. data/vendor/Pods/Pods.xcconfig +3 -3
  134. data/vendor/Pods/Pods.xcodeproj/project.pbxproj +2426 -3155
  135. data/vendor/Pods/Pods.xcodeproj/xcuserdata/kareemk.xcuserdatad/xcschemes/Pods-CocoaLumberjack.xcscheme +59 -0
  136. data/vendor/Pods/Pods.xcodeproj/xcuserdata/kareemk.xcuserdatad/xcschemes/Pods-NSData+MD5Digest.xcscheme +59 -0
  137. data/vendor/Pods/Pods.xcodeproj/xcuserdata/kareemk.xcuserdatad/xcschemes/Pods-YapDatabase.xcscheme +59 -0
  138. data/vendor/Pods/Pods.xcodeproj/xcuserdata/kareemk.xcuserdatad/xcschemes/Pods.xcscheme +59 -0
  139. data/vendor/Pods/Pods.xcodeproj/xcuserdata/kareemk.xcuserdatad/xcschemes/xcschememanagement.plist +31 -0
  140. data/vendor/Pods/YapDatabase/README.md +3 -1
  141. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FilteredViews/Internal/YapDatabaseFilteredViewPrivate.h +0 -2
  142. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FilteredViews/YapDatabaseFilteredView.h +8 -35
  143. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FilteredViews/YapDatabaseFilteredView.m +25 -41
  144. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FilteredViews/YapDatabaseFilteredViewTransaction.h +17 -17
  145. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FilteredViews/YapDatabaseFilteredViewTransaction.m +403 -134
  146. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FilteredViews/YapDatabaseFilteredViewTypes.h +32 -0
  147. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FullTextSearch/Internal/YapDatabaseFullTextSearchPrivate.h +8 -0
  148. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FullTextSearch/YapDatabaseFullTextSearchConnection.m +8 -8
  149. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FullTextSearch/YapDatabaseFullTextSearchTransaction.m +113 -62
  150. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Protocol/Internal/YapDatabaseExtensionPrivate.h +35 -31
  151. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Protocol/YapDatabaseExtension.m +25 -0
  152. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Protocol/YapDatabaseExtensionConnection.m +1 -1
  153. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Protocol/YapDatabaseExtensionTransaction.m +25 -1
  154. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/Internal/YapDatabaseRelationshipEdgePrivate.h +79 -0
  155. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/Internal/YapDatabaseRelationshipPrivate.h +125 -0
  156. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationship.h +35 -0
  157. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationship.m +129 -0
  158. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationshipConnection.h +29 -0
  159. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationshipConnection.m +802 -0
  160. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationshipEdge.h +163 -0
  161. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationshipEdge.m +408 -0
  162. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationshipNode.h +99 -0
  163. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationshipOptions.h +59 -0
  164. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationshipOptions.m +29 -0
  165. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationshipTransaction.h +384 -0
  166. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationshipTransaction.m +5254 -0
  167. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/SecondaryIndex/Internal/YapDatabaseSecondaryIndexPrivate.h +10 -0
  168. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/SecondaryIndex/Internal/YapDatabaseSecondaryIndexSetupPrivate.h +18 -0
  169. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/SecondaryIndex/YapDatabaseSecondaryIndex.h +49 -0
  170. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/SecondaryIndex/YapDatabaseSecondaryIndex.m +12 -0
  171. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/SecondaryIndex/YapDatabaseSecondaryIndexConnection.m +9 -8
  172. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/SecondaryIndex/YapDatabaseSecondaryIndexSetup.m +62 -1
  173. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/SecondaryIndex/YapDatabaseSecondaryIndexTransaction.m +148 -45
  174. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Internal/YapDatabaseViewPrivate.h +18 -1
  175. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Utilities/YapDatabaseViewChange.h +2 -2
  176. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Utilities/YapDatabaseViewChange.m +15 -9
  177. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Utilities/YapDatabaseViewMappings.h +17 -0
  178. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Utilities/YapDatabaseViewMappings.m +211 -64
  179. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/YapDatabaseView.h +48 -107
  180. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/YapDatabaseView.m +10 -7
  181. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/YapDatabaseViewConnection.h +1 -0
  182. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/YapDatabaseViewConnection.m +13 -22
  183. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/YapDatabaseViewOptions.h +10 -3
  184. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/YapDatabaseViewTransaction.h +75 -24
  185. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/YapDatabaseViewTransaction.m +725 -244
  186. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/YapDatabaseViewTypes.h +99 -0
  187. data/vendor/Pods/YapDatabase/YapDatabase/Internal/NSDictionary+YapDatabase.h +8 -0
  188. data/vendor/Pods/YapDatabase/YapDatabase/Internal/NSDictionary+YapDatabase.m +19 -0
  189. data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapCache.h +1 -0
  190. data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapCache.m +12 -0
  191. data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapDatabaseDefaults.h +1 -1
  192. data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapDatabaseDefaults.m +3 -3
  193. data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapDatabasePrivate.h +43 -21
  194. data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapNull.m +4 -0
  195. data/vendor/Pods/YapDatabase/YapDatabase/Utilities/YapCollectionKey.h +3 -0
  196. data/vendor/Pods/YapDatabase/YapDatabase/Utilities/YapCollectionKey.m +5 -0
  197. data/vendor/Pods/YapDatabase/YapDatabase/YapDatabase.h +4 -4
  198. data/vendor/Pods/YapDatabase/YapDatabase/YapDatabase.m +84 -93
  199. data/vendor/Pods/YapDatabase/YapDatabase/YapDatabaseConnection.h +21 -19
  200. data/vendor/Pods/YapDatabase/YapDatabase/YapDatabaseConnection.m +381 -209
  201. data/vendor/Pods/YapDatabase/YapDatabase/YapDatabaseTransaction.h +131 -21
  202. data/vendor/Pods/YapDatabase/YapDatabase/YapDatabaseTransaction.m +587 -267
  203. data/vendor/Pods/{Pods.bridgesupport → build-iPhoneSimulator/Pods.bridgesupport} +633 -2557
  204. data/vendor/Pods/build-iPhoneSimulator/libPods.a +0 -0
  205. data/vendor/YapDatabaseRubyMotion/YapDatabaseRubyMotion.bridgesupport +2 -1
  206. data/vendor/YapDatabaseRubyMotion/YapDatabaseRubyMotion.h +2 -1
  207. data/vendor/YapDatabaseRubyMotion/YapDatabaseRubyMotion.m +4 -2
  208. metadata +80 -108
  209. data/Gemfile.lock +0 -63
  210. data/lib/yapper/attachment.rb +0 -48
  211. data/lib/yapper/document/attachment.rb +0 -26
  212. data/lib/yapper/sync.rb +0 -134
  213. data/lib/yapper/sync/data.rb +0 -12
  214. data/lib/yapper/sync/event.rb +0 -194
  215. data/lib/yapper/sync/queue.rb +0 -164
  216. data/spec/integration/all_spec.rb +0 -40
  217. data/spec/integration/sync_spec.rb +0 -42
  218. data/vendor/Pods/AFNetworking/AFNetworking/AFHTTPClient.h +0 -641
  219. data/vendor/Pods/AFNetworking/AFNetworking/AFHTTPClient.m +0 -1396
  220. data/vendor/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperation.h +0 -133
  221. data/vendor/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperation.m +0 -327
  222. data/vendor/Pods/AFNetworking/AFNetworking/AFImageRequestOperation.h +0 -113
  223. data/vendor/Pods/AFNetworking/AFNetworking/AFImageRequestOperation.m +0 -321
  224. data/vendor/Pods/AFNetworking/AFNetworking/AFJSONRequestOperation.h +0 -71
  225. data/vendor/Pods/AFNetworking/AFNetworking/AFJSONRequestOperation.m +0 -150
  226. data/vendor/Pods/AFNetworking/AFNetworking/AFNetworkActivityIndicatorManager.h +0 -75
  227. data/vendor/Pods/AFNetworking/AFNetworking/AFNetworkActivityIndicatorManager.m +0 -157
  228. data/vendor/Pods/AFNetworking/AFNetworking/AFNetworking.h +0 -43
  229. data/vendor/Pods/AFNetworking/AFNetworking/AFPropertyListRequestOperation.h +0 -68
  230. data/vendor/Pods/AFNetworking/AFNetworking/AFPropertyListRequestOperation.m +0 -143
  231. data/vendor/Pods/AFNetworking/AFNetworking/AFURLConnectionOperation.h +0 -370
  232. data/vendor/Pods/AFNetworking/AFNetworking/AFURLConnectionOperation.m +0 -848
  233. data/vendor/Pods/AFNetworking/AFNetworking/AFXMLRequestOperation.h +0 -89
  234. data/vendor/Pods/AFNetworking/AFNetworking/AFXMLRequestOperation.m +0 -167
  235. data/vendor/Pods/AFNetworking/AFNetworking/UIImageView+AFNetworking.h +0 -78
  236. data/vendor/Pods/AFNetworking/AFNetworking/UIImageView+AFNetworking.m +0 -191
  237. data/vendor/Pods/AFNetworking/LICENSE +0 -19
  238. data/vendor/Pods/AFNetworking/README.md +0 -208
  239. data/vendor/Pods/BuildHeaders/AFNetworking/AFHTTPClient.h +0 -641
  240. data/vendor/Pods/BuildHeaders/AFNetworking/AFHTTPRequestOperation.h +0 -133
  241. data/vendor/Pods/BuildHeaders/AFNetworking/AFImageRequestOperation.h +0 -113
  242. data/vendor/Pods/BuildHeaders/AFNetworking/AFJSONRequestOperation.h +0 -71
  243. data/vendor/Pods/BuildHeaders/AFNetworking/AFNetworkActivityIndicatorManager.h +0 -75
  244. data/vendor/Pods/BuildHeaders/AFNetworking/AFNetworking.h +0 -43
  245. data/vendor/Pods/BuildHeaders/AFNetworking/AFPropertyListRequestOperation.h +0 -68
  246. data/vendor/Pods/BuildHeaders/AFNetworking/AFURLConnectionOperation.h +0 -370
  247. data/vendor/Pods/BuildHeaders/AFNetworking/AFXMLRequestOperation.h +0 -89
  248. data/vendor/Pods/BuildHeaders/AFNetworking/UIImageView+AFNetworking.h +0 -78
  249. data/vendor/Pods/BuildHeaders/Reachability/Reachability.h +0 -109
  250. data/vendor/Pods/CocoaLumberjack/Lumberjack/Extensions/DispatchQueueLogFormatter.m +0 -251
  251. data/vendor/Pods/Headers/AFNetworking/AFHTTPClient.h +0 -641
  252. data/vendor/Pods/Headers/AFNetworking/AFHTTPRequestOperation.h +0 -133
  253. data/vendor/Pods/Headers/AFNetworking/AFImageRequestOperation.h +0 -113
  254. data/vendor/Pods/Headers/AFNetworking/AFJSONRequestOperation.h +0 -71
  255. data/vendor/Pods/Headers/AFNetworking/AFNetworkActivityIndicatorManager.h +0 -75
  256. data/vendor/Pods/Headers/AFNetworking/AFNetworking.h +0 -43
  257. data/vendor/Pods/Headers/AFNetworking/AFPropertyListRequestOperation.h +0 -68
  258. data/vendor/Pods/Headers/AFNetworking/AFURLConnectionOperation.h +0 -370
  259. data/vendor/Pods/Headers/AFNetworking/AFXMLRequestOperation.h +0 -89
  260. data/vendor/Pods/Headers/AFNetworking/UIImageView+AFNetworking.h +0 -78
  261. data/vendor/Pods/Headers/Reachability/Reachability.h +0 -109
  262. data/vendor/Pods/Headers/YapDatabase/YapCache.h +0 -90
  263. data/vendor/Pods/Headers/YapDatabase/YapDatabaseConnectionState.h +0 -29
  264. data/vendor/Pods/Headers/YapDatabase/YapDatabaseDefaults.h +0 -37
  265. data/vendor/Pods/Headers/YapDatabase/YapDatabaseExtensionPrivate.h +0 -440
  266. data/vendor/Pods/Headers/YapDatabase/YapDatabaseFilteredViewPrivate.h +0 -19
  267. data/vendor/Pods/Headers/YapDatabase/YapDatabaseFullTextSearchPrivate.h +0 -69
  268. data/vendor/Pods/Headers/YapDatabase/YapDatabaseLogging.h +0 -158
  269. data/vendor/Pods/Headers/YapDatabase/YapDatabaseManager.h +0 -17
  270. data/vendor/Pods/Headers/YapDatabase/YapDatabasePrivate.h +0 -424
  271. data/vendor/Pods/Headers/YapDatabase/YapDatabaseSecondaryIndexPrivate.h +0 -73
  272. data/vendor/Pods/Headers/YapDatabase/YapDatabaseStatement.h +0 -13
  273. data/vendor/Pods/Headers/YapDatabase/YapDatabaseString.h +0 -121
  274. data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewChangePrivate.h +0 -94
  275. data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewMappingsPrivate.h +0 -72
  276. data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewPage.h +0 -36
  277. data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewPageMetadata.h +0 -27
  278. data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewPrivate.h +0 -153
  279. data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewRangeOptionsPrivate.h +0 -17
  280. data/vendor/Pods/Headers/YapDatabase/YapMemoryTable.h +0 -74
  281. data/vendor/Pods/Headers/YapDatabase/YapNull.h +0 -17
  282. data/vendor/Pods/Headers/YapDatabase/YapTouch.h +0 -15
  283. data/vendor/Pods/Headers/____Pods-AFNetworking-prefix.h +0 -17
  284. data/vendor/Pods/Headers/____Pods-Reachability-prefix.h +0 -5
  285. data/vendor/Pods/Pods-AFNetworking-Private.xcconfig +0 -5
  286. data/vendor/Pods/Pods-AFNetworking-dummy.m +0 -5
  287. data/vendor/Pods/Pods-AFNetworking-prefix.pch +0 -17
  288. data/vendor/Pods/Pods-AFNetworking.xcconfig +0 -1
  289. data/vendor/Pods/Pods-Reachability-Private.xcconfig +0 -5
  290. data/vendor/Pods/Pods-Reachability-dummy.m +0 -5
  291. data/vendor/Pods/Pods-Reachability-prefix.pch +0 -5
  292. data/vendor/Pods/Pods-Reachability.xcconfig +0 -1
  293. data/vendor/Pods/Reachability/LICENCE.txt +0 -24
  294. data/vendor/Pods/Reachability/README.md +0 -65
  295. data/vendor/Pods/Reachability/Reachability.h +0 -109
  296. data/vendor/Pods/Reachability/Reachability.m +0 -527
@@ -7,10 +7,10 @@
7
7
  * Welcome to Cocoa Lumberjack!
8
8
  *
9
9
  * The project page has a wealth of documentation if you have any questions.
10
- * https://github.com/robbiehanson/CocoaLumberjack
10
+ * https://github.com/CocoaLumberjack/CocoaLumberjack
11
11
  *
12
12
  * If you're new to the project you may wish to read the "Getting Started" wiki.
13
- * https://github.com/robbiehanson/CocoaLumberjack/wiki/GettingStarted
13
+ * https://github.com/CocoaLumberjack/CocoaLumberjack/wiki/GettingStarted
14
14
  *
15
15
  *
16
16
  * This class provides a logger to write log statements to a file.
@@ -108,19 +108,47 @@
108
108
  * On Mac, this is in ~/Library/Logs/<Application Name>.
109
109
  * On iPhone, this is in ~/Library/Caches/Logs.
110
110
  *
111
- * Log files are named "log-<uuid>.txt",
112
- * where uuid is a 6 character hexadecimal consisting of the set [0123456789ABCDEF].
111
+ * Log files are named "<bundle identifier> <date> <time>.log"
112
+ * Example: com.organization.myapp 2013-12-03 17-14.log
113
113
  *
114
114
  * Archived log files are automatically deleted according to the maximumNumberOfLogFiles property.
115
115
  **/
116
116
  @interface DDLogFileManagerDefault : NSObject <DDLogFileManager>
117
117
  {
118
- NSUInteger maximumNumberOfLogFiles;
119
- NSString *_logsDirectory;
118
+ NSUInteger maximumNumberOfLogFiles;
119
+ NSString *_logsDirectory;
120
120
  }
121
121
 
122
122
  - (id)init;
123
- - (id)initWithLogsDirectory:(NSString *)logsDirectory;
123
+ - (instancetype)initWithLogsDirectory:(NSString *)logsDirectory;
124
+
125
+ /*
126
+ * Methods to override.
127
+ *
128
+ * Log files are named "<bundle identifier> <date> <time>.log"
129
+ * Example: com.organization.myapp 2013-12-03 17-14.log
130
+ *
131
+ * If you wish to change default filename, you can override following two methods.
132
+ * - newLogFileName method would be called on new logfile creation.
133
+ * - isLogFile: method would be called to filter logfiles from all other files in logsDirectory.
134
+ * You have to parse given filename and return YES if it is logFile.
135
+ *
136
+ * **NOTE**
137
+ * newLogFileName returns filename. If appropriate file already exists, number would be added
138
+ * to filename before extension. You have to handle this case in isLogFile: method.
139
+ *
140
+ * Example:
141
+ * - newLogFileName returns "com.organization.myapp 2013-12-03.log",
142
+ * file "com.organization.myapp 2013-12-03.log" would be created.
143
+ * - after some time "com.organization.myapp 2013-12-03.log" is archived
144
+ * - newLogFileName again returns "com.organization.myapp 2013-12-03.log",
145
+ * file "com.organization.myapp 2013-12-03 2.log" would be created.
146
+ * - after some time "com.organization.myapp 2013-12-03 1.log" is archived
147
+ * - newLogFileName again returns "com.organization.myapp 2013-12-03.log",
148
+ * file "com.organization.myapp 2013-12-03 3.log" would be created.
149
+ **/
150
+ - (NSString *)newLogFileName;
151
+ - (BOOL)isLogFile:(NSString *)fileName;
124
152
 
125
153
  /* Inherited from DDLogFileManager protocol:
126
154
 
@@ -156,11 +184,11 @@
156
184
  **/
157
185
  @interface DDLogFileFormatterDefault : NSObject <DDLogFormatter>
158
186
  {
159
- NSDateFormatter *dateFormatter;
187
+ NSDateFormatter *dateFormatter;
160
188
  }
161
189
 
162
190
  - (id)init;
163
- - (id)initWithDateFormatter:(NSDateFormatter *)dateFormatter;
191
+ - (instancetype)initWithDateFormatter:(NSDateFormatter *)dateFormatter;
164
192
 
165
193
  @end
166
194
 
@@ -170,19 +198,20 @@
170
198
 
171
199
  @interface DDFileLogger : DDAbstractLogger <DDLogger>
172
200
  {
173
- __strong id <DDLogFileManager> logFileManager;
174
-
175
- DDLogFileInfo *currentLogFileInfo;
176
- NSFileHandle *currentLogFileHandle;
177
-
178
- dispatch_source_t rollingTimer;
179
-
180
- unsigned long long maximumFileSize;
181
- NSTimeInterval rollingFrequency;
201
+ __strong id <DDLogFileManager> logFileManager;
202
+
203
+ DDLogFileInfo *currentLogFileInfo;
204
+ NSFileHandle *currentLogFileHandle;
205
+
206
+ dispatch_source_t currentLogFileVnode;
207
+ dispatch_source_t rollingTimer;
208
+
209
+ unsigned long long maximumFileSize;
210
+ NSTimeInterval rollingFrequency;
182
211
  }
183
212
 
184
213
  - (id)init;
185
- - (id)initWithLogFileManager:(id <DDLogFileManager>)logFileManager;
214
+ - (instancetype)initWithLogFileManager:(id <DDLogFileManager>)logFileManager;
186
215
 
187
216
  /**
188
217
  * Log File Rolling:
@@ -228,8 +257,13 @@
228
257
 
229
258
 
230
259
  // You can optionally force the current log file to be rolled with this method.
260
+ // CompletionBlock will be called on main queue.
261
+
262
+ - (void)rollLogFileWithCompletionBlock:(void (^)())completionBlock;
263
+
264
+ // Method is deprecated. Use rollLogFileWithCompletionBlock: method instead.
231
265
 
232
- - (void)rollLogFile;
266
+ - (void)rollLogFile __attribute((deprecated));
233
267
 
234
268
  // Inherited from DDAbstractLogger
235
269
 
@@ -258,15 +292,15 @@
258
292
  **/
259
293
  @interface DDLogFileInfo : NSObject
260
294
  {
261
- __strong NSString *filePath;
262
- __strong NSString *fileName;
263
-
264
- __strong NSDictionary *fileAttributes;
265
-
266
- __strong NSDate *creationDate;
267
- __strong NSDate *modificationDate;
268
-
269
- unsigned long long fileSize;
295
+ __strong NSString *filePath;
296
+ __strong NSString *fileName;
297
+
298
+ __strong NSDictionary *fileAttributes;
299
+
300
+ __strong NSDate *creationDate;
301
+ __strong NSDate *modificationDate;
302
+
303
+ unsigned long long fileSize;
270
304
  }
271
305
 
272
306
  @property (strong, nonatomic, readonly) NSString *filePath;
@@ -283,9 +317,9 @@
283
317
 
284
318
  @property (nonatomic, readwrite) BOOL isArchived;
285
319
 
286
- + (id)logFileWithPath:(NSString *)filePath;
320
+ + (instancetype)logFileWithPath:(NSString *)filePath;
287
321
 
288
- - (id)initWithFilePath:(NSString *)filePath;
322
+ - (instancetype)initWithFilePath:(NSString *)filePath;
289
323
 
290
324
  - (void)reset;
291
325
  - (void)renameFile:(NSString *)newFileName;
@@ -309,7 +343,8 @@
309
343
  // On the simulator we add an attribute by appending a filename extension.
310
344
  //
311
345
  // For example:
312
- // log-ABC123.txt -> log-ABC123.archived.txt
346
+ // "mylog.txt" -> "mylog.archived.txt"
347
+ // "mylog" -> "mylog.archived"
313
348
 
314
349
  - (BOOL)hasExtensionAttributeWithName:(NSString *)attrName;
315
350
 
@@ -9,10 +9,10 @@
9
9
  * Welcome to Cocoa Lumberjack!
10
10
  *
11
11
  * The project page has a wealth of documentation if you have any questions.
12
- * https://github.com/robbiehanson/CocoaLumberjack
12
+ * https://github.com/CocoaLumberjack/CocoaLumberjack
13
13
  *
14
14
  * If you're new to the project you may wish to read the "Getting Started" wiki.
15
- * https://github.com/robbiehanson/CocoaLumberjack/wiki/GettingStarted
15
+ * https://github.com/CocoaLumberjack/CocoaLumberjack/wiki/GettingStarted
16
16
  **/
17
17
 
18
18
  #if ! __has_feature(objc_arc)
@@ -31,7 +31,8 @@
31
31
  #define NSLogError(frmt, ...) do{ if(LOG_LEVEL >= 1) NSLog((frmt), ##__VA_ARGS__); } while(0)
32
32
  #define NSLogWarn(frmt, ...) do{ if(LOG_LEVEL >= 2) NSLog((frmt), ##__VA_ARGS__); } while(0)
33
33
  #define NSLogInfo(frmt, ...) do{ if(LOG_LEVEL >= 3) NSLog((frmt), ##__VA_ARGS__); } while(0)
34
- #define NSLogVerbose(frmt, ...) do{ if(LOG_LEVEL >= 4) NSLog((frmt), ##__VA_ARGS__); } while(0)
34
+ #define NSLogDebug(frmt, ...) do{ if(LOG_LEVEL >= 4) NSLog((frmt), ##__VA_ARGS__); } while(0)
35
+ #define NSLogVerbose(frmt, ...) do{ if(LOG_LEVEL >= 5) NSLog((frmt), ##__VA_ARGS__); } while(0)
35
36
 
36
37
  @interface DDLogFileManagerDefault (PrivateAPI)
37
38
 
@@ -48,6 +49,10 @@
48
49
 
49
50
  @end
50
51
 
52
+ #if TARGET_OS_IPHONE
53
+ BOOL doesAppRunInBackground(void);
54
+ #endif
55
+
51
56
  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
52
57
  #pragma mark -
53
58
  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -58,33 +63,39 @@
58
63
 
59
64
  - (id)init
60
65
  {
61
- return [self initWithLogsDirectory:nil];
66
+ return [self initWithLogsDirectory:nil];
62
67
  }
63
68
 
64
- - (id)initWithLogsDirectory:(NSString *)aLogsDirectory
69
+ - (instancetype)initWithLogsDirectory:(NSString *)aLogsDirectory
65
70
  {
66
- if ((self = [super init]))
67
- {
68
- maximumNumberOfLogFiles = DEFAULT_LOG_MAX_NUM_LOG_FILES;
69
-
70
- if (aLogsDirectory)
71
- _logsDirectory = [aLogsDirectory copy];
72
- else
73
- _logsDirectory = [[self defaultLogsDirectory] copy];
74
-
75
- NSKeyValueObservingOptions kvoOptions = NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew;
76
-
77
- [self addObserver:self forKeyPath:@"maximumNumberOfLogFiles" options:kvoOptions context:nil];
78
-
79
- NSLogVerbose(@"DDFileLogManagerDefault: logsDirectory:\n%@", [self logsDirectory]);
80
- NSLogVerbose(@"DDFileLogManagerDefault: sortedLogFileNames:\n%@", [self sortedLogFileNames]);
81
- }
82
- return self;
71
+ if ((self = [super init]))
72
+ {
73
+ maximumNumberOfLogFiles = DEFAULT_LOG_MAX_NUM_LOG_FILES;
74
+
75
+ if (aLogsDirectory)
76
+ _logsDirectory = [aLogsDirectory copy];
77
+ else
78
+ _logsDirectory = [[self defaultLogsDirectory] copy];
79
+
80
+ NSKeyValueObservingOptions kvoOptions = NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew;
81
+
82
+ [self addObserver:self forKeyPath:NSStringFromSelector(@selector(maximumNumberOfLogFiles)) options:kvoOptions context:nil];
83
+
84
+ NSLogVerbose(@"DDFileLogManagerDefault: logsDirectory:\n%@", [self logsDirectory]);
85
+ NSLogVerbose(@"DDFileLogManagerDefault: sortedLogFileNames:\n%@", [self sortedLogFileNames]);
86
+ }
87
+ return self;
83
88
  }
84
89
 
85
90
  - (void)dealloc
86
91
  {
87
- [self removeObserver:self forKeyPath:@"maximumNumberOfLogFiles"];
92
+ // try-catch because the observer might be removed or never added. In this case, removeObserver throws and exception
93
+ @try {
94
+ [self removeObserver:self forKeyPath:NSStringFromSelector(@selector(maximumNumberOfLogFiles))];
95
+ }
96
+ @catch (NSException *exception) {
97
+
98
+ }
88
99
  }
89
100
 
90
101
  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -96,24 +107,24 @@
96
107
  change:(NSDictionary *)change
97
108
  context:(void *)context
98
109
  {
99
- NSNumber *old = [change objectForKey:NSKeyValueChangeOldKey];
100
- NSNumber *new = [change objectForKey:NSKeyValueChangeNewKey];
101
-
102
- if ([old isEqual:new])
103
- {
104
- // No change in value - don't bother with any processing.
105
- return;
106
- }
107
-
108
- if ([keyPath isEqualToString:@"maximumNumberOfLogFiles"])
109
- {
110
- NSLogInfo(@"DDFileLogManagerDefault: Responding to configuration change: maximumNumberOfLogFiles");
111
-
112
- dispatch_async([DDLog loggingQueue], ^{ @autoreleasepool {
113
-
114
- [self deleteOldLogFiles];
115
- }});
116
- }
110
+ NSNumber *old = [change objectForKey:NSKeyValueChangeOldKey];
111
+ NSNumber *new = [change objectForKey:NSKeyValueChangeNewKey];
112
+
113
+ if ([old isEqual:new])
114
+ {
115
+ // No change in value - don't bother with any processing.
116
+ return;
117
+ }
118
+
119
+ if ([keyPath isEqualToString:NSStringFromSelector(@selector(maximumNumberOfLogFiles))])
120
+ {
121
+ NSLogInfo(@"DDFileLogManagerDefault: Responding to configuration change: maximumNumberOfLogFiles");
122
+
123
+ dispatch_async([DDLog loggingQueue], ^{ @autoreleasepool {
124
+
125
+ [self deleteOldLogFiles];
126
+ }});
127
+ }
117
128
  }
118
129
 
119
130
  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -125,55 +136,55 @@
125
136
  **/
126
137
  - (void)deleteOldLogFiles
127
138
  {
128
- NSLogVerbose(@"DDLogFileManagerDefault: deleteOldLogFiles");
129
-
130
- NSUInteger maxNumLogFiles = self.maximumNumberOfLogFiles;
131
- if (maxNumLogFiles == 0)
132
- {
133
- // Unlimited - don't delete any log files
134
- return;
135
- }
136
-
137
- NSArray *sortedLogFileInfos = [self sortedLogFileInfos];
138
-
139
- // Do we consider the first file?
140
- // We are only supposed to be deleting archived files.
141
- // In most cases, the first file is likely the log file that is currently being written to.
142
- // So in most cases, we do not want to consider this file for deletion.
143
-
144
- NSUInteger count = [sortedLogFileInfos count];
145
- BOOL excludeFirstFile = NO;
146
-
147
- if (count > 0)
148
- {
149
- DDLogFileInfo *logFileInfo = [sortedLogFileInfos objectAtIndex:0];
150
-
151
- if (!logFileInfo.isArchived)
152
- {
153
- excludeFirstFile = YES;
154
- }
155
- }
156
-
157
- NSArray *sortedArchivedLogFileInfos;
158
- if (excludeFirstFile)
159
- {
160
- count--;
161
- sortedArchivedLogFileInfos = [sortedLogFileInfos subarrayWithRange:NSMakeRange(1, count)];
162
- }
163
- else
164
- {
165
- sortedArchivedLogFileInfos = sortedLogFileInfos;
166
- }
167
-
168
- NSUInteger i;
169
- for (i = maxNumLogFiles; i < count; i++)
170
- {
171
- DDLogFileInfo *logFileInfo = [sortedArchivedLogFileInfos objectAtIndex:i];
172
-
173
- NSLogInfo(@"DDLogFileManagerDefault: Deleting file: %@", logFileInfo.fileName);
174
-
175
- [[NSFileManager defaultManager] removeItemAtPath:logFileInfo.filePath error:nil];
176
- }
139
+ NSLogVerbose(@"DDLogFileManagerDefault: deleteOldLogFiles");
140
+
141
+ NSUInteger maxNumLogFiles = self.maximumNumberOfLogFiles;
142
+ if (maxNumLogFiles == 0)
143
+ {
144
+ // Unlimited - don't delete any log files
145
+ return;
146
+ }
147
+
148
+ NSArray *sortedLogFileInfos = [self sortedLogFileInfos];
149
+
150
+ // Do we consider the first file?
151
+ // We are only supposed to be deleting archived files.
152
+ // In most cases, the first file is likely the log file that is currently being written to.
153
+ // So in most cases, we do not want to consider this file for deletion.
154
+
155
+ NSUInteger count = [sortedLogFileInfos count];
156
+ BOOL excludeFirstFile = NO;
157
+
158
+ if (count > 0)
159
+ {
160
+ DDLogFileInfo *logFileInfo = [sortedLogFileInfos objectAtIndex:0];
161
+
162
+ if (!logFileInfo.isArchived)
163
+ {
164
+ excludeFirstFile = YES;
165
+ }
166
+ }
167
+
168
+ NSArray *sortedArchivedLogFileInfos;
169
+ if (excludeFirstFile)
170
+ {
171
+ count--;
172
+ sortedArchivedLogFileInfos = [sortedLogFileInfos subarrayWithRange:NSMakeRange(1, count)];
173
+ }
174
+ else
175
+ {
176
+ sortedArchivedLogFileInfos = sortedLogFileInfos;
177
+ }
178
+
179
+ NSUInteger i;
180
+ for (i = maxNumLogFiles; i < count; i++)
181
+ {
182
+ DDLogFileInfo *logFileInfo = [sortedArchivedLogFileInfos objectAtIndex:i];
183
+
184
+ NSLogInfo(@"DDLogFileManagerDefault: Deleting file: %@", logFileInfo.fileName);
185
+
186
+ [[NSFileManager defaultManager] removeItemAtPath:logFileInfo.filePath error:nil];
187
+ }
177
188
  }
178
189
 
179
190
  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -187,64 +198,97 @@
187
198
  - (NSString *)defaultLogsDirectory
188
199
  {
189
200
  #if TARGET_OS_IPHONE
190
- NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
191
- NSString *baseDir = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
192
- NSString *logsDirectory = [baseDir stringByAppendingPathComponent:@"Logs"];
201
+ NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
202
+ NSString *baseDir = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
203
+ NSString *logsDirectory = [baseDir stringByAppendingPathComponent:@"Logs"];
193
204
 
194
205
  #else
195
- NSString *appName = [[NSProcessInfo processInfo] processName];
196
- NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
197
- NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : NSTemporaryDirectory();
198
- NSString *logsDirectory = [[basePath stringByAppendingPathComponent:@"Logs"] stringByAppendingPathComponent:appName];
206
+ NSString *appName = [[NSProcessInfo processInfo] processName];
207
+ NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
208
+ NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : NSTemporaryDirectory();
209
+ NSString *logsDirectory = [[basePath stringByAppendingPathComponent:@"Logs"] stringByAppendingPathComponent:appName];
199
210
 
200
211
  #endif
201
212
 
202
- return logsDirectory;
213
+ return logsDirectory;
203
214
  }
204
215
 
205
216
  - (NSString *)logsDirectory
206
217
  {
207
- // We could do this check once, during initalization, and not bother again.
208
- // But this way the code continues to work if the directory gets deleted while the code is running.
209
-
210
- if (![[NSFileManager defaultManager] fileExistsAtPath:_logsDirectory])
211
- {
212
- NSError *err = nil;
213
- if (![[NSFileManager defaultManager] createDirectoryAtPath:_logsDirectory
214
- withIntermediateDirectories:YES attributes:nil error:&err])
215
- {
216
- NSLogError(@"DDFileLogManagerDefault: Error creating logsDirectory: %@", err);
217
- }
218
- }
219
-
220
- return _logsDirectory;
218
+ // We could do this check once, during initalization, and not bother again.
219
+ // But this way the code continues to work if the directory gets deleted while the code is running.
220
+
221
+ if (![[NSFileManager defaultManager] fileExistsAtPath:_logsDirectory])
222
+ {
223
+ NSError *err = nil;
224
+ if (![[NSFileManager defaultManager] createDirectoryAtPath:_logsDirectory
225
+ withIntermediateDirectories:YES attributes:nil error:&err])
226
+ {
227
+ NSLogError(@"DDFileLogManagerDefault: Error creating logsDirectory: %@", err);
228
+ }
229
+ }
230
+
231
+ return _logsDirectory;
221
232
  }
222
233
 
234
+ /**
235
+ * Default log file name is "<bundle identifier> <date> <time>.log".
236
+ * Example: MobileSafari 2013-12-03 17-14.log
237
+ *
238
+ * You can change it by overriding newLogFileName and isLogFile: methods.
239
+ **/
223
240
  - (BOOL)isLogFile:(NSString *)fileName
224
241
  {
225
- // A log file has a name like "log-<uuid>.txt", where <uuid> is a HEX-string of 6 characters.
226
- //
227
- // For example: log-DFFE99.txt
228
-
229
- BOOL hasProperPrefix = [fileName hasPrefix:@"log-"];
230
-
231
- BOOL hasProperLength = [fileName length] >= 10;
232
-
233
-
234
- if (hasProperPrefix && hasProperLength)
235
- {
236
- NSCharacterSet *hexSet = [NSCharacterSet characterSetWithCharactersInString:@"0123456789ABCDEF"];
237
-
238
- NSString *hex = [fileName substringWithRange:NSMakeRange(4, 6)];
239
- NSString *nohex = [hex stringByTrimmingCharactersInSet:hexSet];
240
-
241
- if ([nohex length] == 0)
242
- {
243
- return YES;
244
- }
245
- }
246
-
247
- return NO;
242
+ NSString *appName = [self applicationName];
243
+
244
+ BOOL hasProperPrefix = [fileName hasPrefix:appName];
245
+ BOOL hasProperSuffix = [fileName hasSuffix:@".log"];
246
+ BOOL hasProperDate = NO;
247
+
248
+ if (hasProperPrefix && hasProperSuffix)
249
+ {
250
+ NSUInteger lengthOfMiddle = fileName.length - appName.length - @".log".length;
251
+
252
+ // Date string should have at least 16 characters - " 2013-12-03 17-14"
253
+ if (lengthOfMiddle >= 17)
254
+ {
255
+ NSRange range = NSMakeRange(appName.length, lengthOfMiddle);
256
+
257
+ NSString *middle = [fileName substringWithRange:range];
258
+ NSArray *components = [middle componentsSeparatedByString:@" "];
259
+
260
+ // When creating logfile if there is existing file with the same name, we append attemp number at the end.
261
+ // Thats why here we can have three or four components. For details see createNewLogFile method.
262
+ //
263
+ // Components:
264
+ // "", "2013-12-03", "17-14"
265
+ // or
266
+ // "", "2013-12-03", "17-14", "1"
267
+ if (components.count == 3 || components.count == 4)
268
+ {
269
+ NSString *dateString = [NSString stringWithFormat:@"%@ %@", components[1], components[2]];
270
+ NSDateFormatter *dateFormatter = [self logFileDateFormatter];
271
+
272
+ NSDate *date = [dateFormatter dateFromString:dateString];
273
+
274
+ if (date)
275
+ {
276
+ hasProperDate = YES;
277
+ }
278
+ }
279
+ }
280
+ }
281
+
282
+ return (hasProperPrefix && hasProperDate && hasProperSuffix);
283
+ }
284
+
285
+ - (NSDateFormatter *)logFileDateFormatter
286
+ {
287
+ NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
288
+ [dateFormatter setDateFormat:@"yyyy'-'MM'-'dd' 'HH'-'mm'"];
289
+ [dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
290
+
291
+ return dateFormatter;
248
292
  }
249
293
 
250
294
  /**
@@ -253,24 +297,35 @@
253
297
  **/
254
298
  - (NSArray *)unsortedLogFilePaths
255
299
  {
256
- NSString *logsDirectory = [self logsDirectory];
257
- NSArray *fileNames = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:logsDirectory error:nil];
258
-
259
- NSMutableArray *unsortedLogFilePaths = [NSMutableArray arrayWithCapacity:[fileNames count]];
260
-
261
- for (NSString *fileName in fileNames)
262
- {
263
- // Filter out any files that aren't log files. (Just for extra safety)
264
-
265
- if ([self isLogFile:fileName])
266
- {
267
- NSString *filePath = [logsDirectory stringByAppendingPathComponent:fileName];
268
-
269
- [unsortedLogFilePaths addObject:filePath];
270
- }
271
- }
272
-
273
- return unsortedLogFilePaths;
300
+ NSString *logsDirectory = [self logsDirectory];
301
+ NSArray *fileNames = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:logsDirectory error:nil];
302
+
303
+ NSMutableArray *unsortedLogFilePaths = [NSMutableArray arrayWithCapacity:[fileNames count]];
304
+
305
+ for (NSString *fileName in fileNames)
306
+ {
307
+ // Filter out any files that aren't log files. (Just for extra safety)
308
+
309
+ #if TARGET_IPHONE_SIMULATOR
310
+ // In case of iPhone simulator there can be 'archived' extension. isLogFile:
311
+ // method knows nothing about it. Thus removing it for this method.
312
+ //
313
+ // See full explanation in the header file.
314
+ NSString *theFileName = [fileName stringByReplacingOccurrencesOfString:@".archived"
315
+ withString:@""];
316
+
317
+ if ([self isLogFile:theFileName])
318
+ #else
319
+ if ([self isLogFile:fileName])
320
+ #endif
321
+ {
322
+ NSString *filePath = [logsDirectory stringByAppendingPathComponent:fileName];
323
+
324
+ [unsortedLogFilePaths addObject:filePath];
325
+ }
326
+ }
327
+
328
+ return unsortedLogFilePaths;
274
329
  }
275
330
 
276
331
  /**
@@ -279,16 +334,16 @@
279
334
  **/
280
335
  - (NSArray *)unsortedLogFileNames
281
336
  {
282
- NSArray *unsortedLogFilePaths = [self unsortedLogFilePaths];
283
-
284
- NSMutableArray *unsortedLogFileNames = [NSMutableArray arrayWithCapacity:[unsortedLogFilePaths count]];
285
-
286
- for (NSString *filePath in unsortedLogFilePaths)
287
- {
288
- [unsortedLogFileNames addObject:[filePath lastPathComponent]];
289
- }
290
-
291
- return unsortedLogFileNames;
337
+ NSArray *unsortedLogFilePaths = [self unsortedLogFilePaths];
338
+
339
+ NSMutableArray *unsortedLogFileNames = [NSMutableArray arrayWithCapacity:[unsortedLogFilePaths count]];
340
+
341
+ for (NSString *filePath in unsortedLogFilePaths)
342
+ {
343
+ [unsortedLogFileNames addObject:[filePath lastPathComponent]];
344
+ }
345
+
346
+ return unsortedLogFileNames;
292
347
  }
293
348
 
294
349
  /**
@@ -298,66 +353,66 @@
298
353
  **/
299
354
  - (NSArray *)unsortedLogFileInfos
300
355
  {
301
- NSArray *unsortedLogFilePaths = [self unsortedLogFilePaths];
302
-
303
- NSMutableArray *unsortedLogFileInfos = [NSMutableArray arrayWithCapacity:[unsortedLogFilePaths count]];
304
-
305
- for (NSString *filePath in unsortedLogFilePaths)
306
- {
307
- DDLogFileInfo *logFileInfo = [[DDLogFileInfo alloc] initWithFilePath:filePath];
308
-
309
- [unsortedLogFileInfos addObject:logFileInfo];
310
- }
311
-
312
- return unsortedLogFileInfos;
356
+ NSArray *unsortedLogFilePaths = [self unsortedLogFilePaths];
357
+
358
+ NSMutableArray *unsortedLogFileInfos = [NSMutableArray arrayWithCapacity:[unsortedLogFilePaths count]];
359
+
360
+ for (NSString *filePath in unsortedLogFilePaths)
361
+ {
362
+ DDLogFileInfo *logFileInfo = [[DDLogFileInfo alloc] initWithFilePath:filePath];
363
+
364
+ [unsortedLogFileInfos addObject:logFileInfo];
365
+ }
366
+
367
+ return unsortedLogFileInfos;
313
368
  }
314
369
 
315
370
  /**
316
371
  * Just like the unsortedLogFilePaths method, but sorts the array.
317
- * The items in the array are sorted by modification date.
318
- * The first item in the array will be the most recently modified log file.
372
+ * The items in the array are sorted by creation date.
373
+ * The first item in the array will be the most recently created log file.
319
374
  **/
320
375
  - (NSArray *)sortedLogFilePaths
321
376
  {
322
- NSArray *sortedLogFileInfos = [self sortedLogFileInfos];
323
-
324
- NSMutableArray *sortedLogFilePaths = [NSMutableArray arrayWithCapacity:[sortedLogFileInfos count]];
325
-
326
- for (DDLogFileInfo *logFileInfo in sortedLogFileInfos)
327
- {
328
- [sortedLogFilePaths addObject:[logFileInfo filePath]];
329
- }
330
-
331
- return sortedLogFilePaths;
377
+ NSArray *sortedLogFileInfos = [self sortedLogFileInfos];
378
+
379
+ NSMutableArray *sortedLogFilePaths = [NSMutableArray arrayWithCapacity:[sortedLogFileInfos count]];
380
+
381
+ for (DDLogFileInfo *logFileInfo in sortedLogFileInfos)
382
+ {
383
+ [sortedLogFilePaths addObject:[logFileInfo filePath]];
384
+ }
385
+
386
+ return sortedLogFilePaths;
332
387
  }
333
388
 
334
389
  /**
335
390
  * Just like the unsortedLogFileNames method, but sorts the array.
336
- * The items in the array are sorted by modification date.
337
- * The first item in the array will be the most recently modified log file.
391
+ * The items in the array are sorted by creation date.
392
+ * The first item in the array will be the most recently created log file.
338
393
  **/
339
394
  - (NSArray *)sortedLogFileNames
340
395
  {
341
- NSArray *sortedLogFileInfos = [self sortedLogFileInfos];
342
-
343
- NSMutableArray *sortedLogFileNames = [NSMutableArray arrayWithCapacity:[sortedLogFileInfos count]];
344
-
345
- for (DDLogFileInfo *logFileInfo in sortedLogFileInfos)
346
- {
347
- [sortedLogFileNames addObject:[logFileInfo fileName]];
348
- }
349
-
350
- return sortedLogFileNames;
396
+ NSArray *sortedLogFileInfos = [self sortedLogFileInfos];
397
+
398
+ NSMutableArray *sortedLogFileNames = [NSMutableArray arrayWithCapacity:[sortedLogFileInfos count]];
399
+
400
+ for (DDLogFileInfo *logFileInfo in sortedLogFileInfos)
401
+ {
402
+ [sortedLogFileNames addObject:[logFileInfo fileName]];
403
+ }
404
+
405
+ return sortedLogFileNames;
351
406
  }
352
407
 
353
408
  /**
354
409
  * Just like the unsortedLogFileInfos method, but sorts the array.
355
- * The items in the array are sorted by modification date.
356
- * The first item in the array will be the most recently modified log file.
410
+ * The items in the array are sorted by creation date.
411
+ * The first item in the array will be the most recently created log file.
357
412
  **/
358
413
  - (NSArray *)sortedLogFileInfos
359
414
  {
360
- return [[self unsortedLogFileInfos] sortedArrayUsingSelector:@selector(reverseCompareByCreationDate:)];
415
+ return [[self unsortedLogFileInfos] sortedArrayUsingSelector:@selector(reverseCompareByCreationDate:)];
361
416
  }
362
417
 
363
418
  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -365,20 +420,19 @@
365
420
  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
366
421
 
367
422
  /**
368
- * Generates a short UUID suitable for use in the log file's name.
369
- * The result will have six characters, all in the hexadecimal set [0123456789ABCDEF].
423
+ * Generates log file name with default format "<bundle identifier> <date> <time>.log"
424
+ * Example: MobileSafari 2013-12-03 17-14.log
425
+ *
426
+ * You can change it by overriding newLogFileName and isLogFile: methods.
370
427
  **/
371
- - (NSString *)generateShortUUID
428
+ - (NSString *)newLogFileName
372
429
  {
373
- CFUUIDRef uuid = CFUUIDCreate(NULL);
374
-
375
- CFStringRef fullStr = CFUUIDCreateString(NULL, uuid);
376
- NSString *result = (__bridge_transfer NSString *)CFStringCreateWithSubstring(NULL, fullStr, CFRangeMake(0, 6));
377
-
378
- CFRelease(fullStr);
379
- CFRelease(uuid);
380
-
381
- return result;
430
+ NSString *appName = [self applicationName];
431
+
432
+ NSDateFormatter *dateFormatter = [self logFileDateFormatter];
433
+ NSString *formattedDate = [dateFormatter stringFromDate:[NSDate date]];
434
+
435
+ return [NSString stringWithFormat:@"%@ %@.log", appName, formattedDate];
382
436
  }
383
437
 
384
438
  /**
@@ -386,28 +440,82 @@
386
440
  **/
387
441
  - (NSString *)createNewLogFile
388
442
  {
389
- // Generate a random log file name, and create the file (if there isn't a collision)
390
-
391
- NSString *logsDirectory = [self logsDirectory];
392
- do
393
- {
394
- NSString *fileName = [NSString stringWithFormat:@"log-%@.txt", [self generateShortUUID]];
395
-
396
- NSString *filePath = [logsDirectory stringByAppendingPathComponent:fileName];
397
-
398
- if (![[NSFileManager defaultManager] fileExistsAtPath:filePath])
399
- {
400
- NSLogVerbose(@"DDLogFileManagerDefault: Creating new log file: %@", fileName);
401
-
402
- [[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil];
403
-
404
- // Since we just created a new log file, we may need to delete some old log files
405
- [self deleteOldLogFiles];
406
-
407
- return filePath;
408
- }
409
-
410
- } while(YES);
443
+ NSString *fileName = [self newLogFileName];
444
+ NSString *logsDirectory = [self logsDirectory];
445
+
446
+ NSUInteger attempt = 1;
447
+ do
448
+ {
449
+ NSString *actualFileName = fileName;
450
+
451
+ if (attempt > 1) {
452
+ NSString *extension = [actualFileName pathExtension];
453
+
454
+ actualFileName = [actualFileName stringByDeletingPathExtension];
455
+ actualFileName = [actualFileName stringByAppendingFormat:@" %lu", (unsigned long)attempt];
456
+ if (extension.length) {
457
+ actualFileName = [actualFileName stringByAppendingPathExtension:extension];
458
+ }
459
+ }
460
+
461
+ NSString *filePath = [logsDirectory stringByAppendingPathComponent:actualFileName];
462
+
463
+ if (![[NSFileManager defaultManager] fileExistsAtPath:filePath])
464
+ {
465
+ NSLogVerbose(@"DDLogFileManagerDefault: Creating new log file: %@", actualFileName);
466
+
467
+ NSDictionary *attributes = nil;
468
+
469
+ #if TARGET_OS_IPHONE
470
+ // When creating log file on iOS we're setting NSFileProtectionKey attribute to NSFileProtectionCompleteUnlessOpen.
471
+ //
472
+ // But in case if app is able to launch from background we need to have an ability to open log file any time we
473
+ // want (even if device is locked). Thats why that attribute have to be changed to
474
+ // NSFileProtectionCompleteUntilFirstUserAuthentication.
475
+
476
+ NSString *key = doesAppRunInBackground() ?
477
+ NSFileProtectionCompleteUntilFirstUserAuthentication : NSFileProtectionCompleteUnlessOpen;
478
+
479
+ attributes = @{ NSFileProtectionKey : key };
480
+ #endif
481
+
482
+ [[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:attributes];
483
+
484
+ // Since we just created a new log file, we may need to delete some old log files
485
+ [self deleteOldLogFiles];
486
+
487
+ return filePath;
488
+ } else {
489
+ attempt++;
490
+ }
491
+
492
+ } while(YES);
493
+ }
494
+
495
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
496
+ #pragma mark Utility
497
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
498
+
499
+ - (NSString *)applicationName
500
+ {
501
+ static NSString *_appName;
502
+ static dispatch_once_t onceToken;
503
+
504
+ dispatch_once(&onceToken, ^{
505
+ _appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIdentifier"];
506
+
507
+ if (! _appName)
508
+ {
509
+ _appName = [[NSProcessInfo processInfo] processName];
510
+ }
511
+
512
+ if (! _appName)
513
+ {
514
+ _appName = @"";
515
+ }
516
+ });
517
+
518
+ return _appName;
411
519
  }
412
520
 
413
521
  @end
@@ -420,32 +528,32 @@
420
528
 
421
529
  - (id)init
422
530
  {
423
- return [self initWithDateFormatter:nil];
531
+ return [self initWithDateFormatter:nil];
424
532
  }
425
533
 
426
- - (id)initWithDateFormatter:(NSDateFormatter *)aDateFormatter
534
+ - (instancetype)initWithDateFormatter:(NSDateFormatter *)aDateFormatter
427
535
  {
428
- if ((self = [super init]))
429
- {
430
- if (aDateFormatter)
431
- {
432
- dateFormatter = aDateFormatter;
433
- }
434
- else
435
- {
436
- dateFormatter = [[NSDateFormatter alloc] init];
437
- [dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4]; // 10.4+ style
438
- [dateFormatter setDateFormat:@"yyyy/MM/dd HH:mm:ss:SSS"];
439
- }
440
- }
441
- return self;
536
+ if ((self = [super init]))
537
+ {
538
+ if (aDateFormatter)
539
+ {
540
+ dateFormatter = aDateFormatter;
541
+ }
542
+ else
543
+ {
544
+ dateFormatter = [[NSDateFormatter alloc] init];
545
+ [dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4]; // 10.4+ style
546
+ [dateFormatter setDateFormat:@"yyyy/MM/dd HH:mm:ss:SSS"];
547
+ }
548
+ }
549
+ return self;
442
550
  }
443
551
 
444
552
  - (NSString *)formatLogMessage:(DDLogMessage *)logMessage
445
553
  {
446
- NSString *dateAndTime = [dateFormatter stringFromDate:(logMessage->timestamp)];
447
-
448
- return [NSString stringWithFormat:@"%@ %@", dateAndTime, logMessage->logMsg];
554
+ NSString *dateAndTime = [dateFormatter stringFromDate:(logMessage->timestamp)];
555
+
556
+ return [NSString stringWithFormat:@"%@ %@", dateAndTime, logMessage->logMsg];
449
557
  }
450
558
 
451
559
  @end
@@ -458,35 +566,40 @@
458
566
 
459
567
  - (id)init
460
568
  {
461
- DDLogFileManagerDefault *defaultLogFileManager = [[DDLogFileManagerDefault alloc] init];
462
-
463
- return [self initWithLogFileManager:defaultLogFileManager];
569
+ DDLogFileManagerDefault *defaultLogFileManager = [[DDLogFileManagerDefault alloc] init];
570
+
571
+ return [self initWithLogFileManager:defaultLogFileManager];
464
572
  }
465
573
 
466
- - (id)initWithLogFileManager:(id <DDLogFileManager>)aLogFileManager
574
+ - (instancetype)initWithLogFileManager:(id <DDLogFileManager>)aLogFileManager
467
575
  {
468
- if ((self = [super init]))
469
- {
470
- maximumFileSize = DEFAULT_LOG_MAX_FILE_SIZE;
471
- rollingFrequency = DEFAULT_LOG_ROLLING_FREQUENCY;
472
-
473
- logFileManager = aLogFileManager;
474
-
475
- formatter = [[DDLogFileFormatterDefault alloc] init];
476
- }
477
- return self;
576
+ if ((self = [super init]))
577
+ {
578
+ maximumFileSize = DEFAULT_LOG_MAX_FILE_SIZE;
579
+ rollingFrequency = DEFAULT_LOG_ROLLING_FREQUENCY;
580
+
581
+ logFileManager = aLogFileManager;
582
+
583
+ formatter = [[DDLogFileFormatterDefault alloc] init];
584
+ }
585
+ return self;
478
586
  }
479
587
 
480
588
  - (void)dealloc
481
589
  {
482
- [currentLogFileHandle synchronizeFile];
483
- [currentLogFileHandle closeFile];
484
-
485
- if (rollingTimer)
486
- {
487
- dispatch_source_cancel(rollingTimer);
488
- rollingTimer = NULL;
489
- }
590
+ [currentLogFileHandle synchronizeFile];
591
+ [currentLogFileHandle closeFile];
592
+
593
+ if (currentLogFileVnode) {
594
+ dispatch_source_cancel(currentLogFileVnode);
595
+ currentLogFileVnode = NULL;
596
+ }
597
+
598
+ if (rollingTimer)
599
+ {
600
+ dispatch_source_cancel(rollingTimer);
601
+ rollingTimer = NULL;
602
+ }
490
603
  }
491
604
 
492
605
  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -497,119 +610,119 @@
497
610
 
498
611
  - (unsigned long long)maximumFileSize
499
612
  {
500
- __block unsigned long long result;
501
-
502
- dispatch_block_t block = ^{
503
- result = maximumFileSize;
504
- };
505
-
506
- // The design of this method is taken from the DDAbstractLogger implementation.
507
- // For extensive documentation please refer to the DDAbstractLogger implementation.
508
-
509
- // Note: The internal implementation MUST access the maximumFileSize variable directly,
510
- // This method is designed explicitly for external access.
511
- //
512
- // Using "self." syntax to go through this method will cause immediate deadlock.
513
- // This is the intended result. Fix it by accessing the ivar directly.
514
- // Great strides have been take to ensure this is safe to do. Plus it's MUCH faster.
515
-
516
- NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
517
- NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");
518
-
519
- dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
520
-
521
- dispatch_sync(globalLoggingQueue, ^{
522
- dispatch_sync(loggerQueue, block);
523
- });
524
-
525
- return result;
613
+ __block unsigned long long result;
614
+
615
+ dispatch_block_t block = ^{
616
+ result = maximumFileSize;
617
+ };
618
+
619
+ // The design of this method is taken from the DDAbstractLogger implementation.
620
+ // For extensive documentation please refer to the DDAbstractLogger implementation.
621
+
622
+ // Note: The internal implementation MUST access the maximumFileSize variable directly,
623
+ // This method is designed explicitly for external access.
624
+ //
625
+ // Using "self." syntax to go through this method will cause immediate deadlock.
626
+ // This is the intended result. Fix it by accessing the ivar directly.
627
+ // Great strides have been take to ensure this is safe to do. Plus it's MUCH faster.
628
+
629
+ NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
630
+ NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");
631
+
632
+ dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
633
+
634
+ dispatch_sync(globalLoggingQueue, ^{
635
+ dispatch_sync(loggerQueue, block);
636
+ });
637
+
638
+ return result;
526
639
  }
527
640
 
528
641
  - (void)setMaximumFileSize:(unsigned long long)newMaximumFileSize
529
642
  {
530
- dispatch_block_t block = ^{ @autoreleasepool {
531
-
532
- maximumFileSize = newMaximumFileSize;
533
- [self maybeRollLogFileDueToSize];
534
-
535
- }};
536
-
537
- // The design of this method is taken from the DDAbstractLogger implementation.
538
- // For extensive documentation please refer to the DDAbstractLogger implementation.
539
-
540
- // Note: The internal implementation MUST access the maximumFileSize variable directly,
541
- // This method is designed explicitly for external access.
542
- //
543
- // Using "self." syntax to go through this method will cause immediate deadlock.
544
- // This is the intended result. Fix it by accessing the ivar directly.
545
- // Great strides have been take to ensure this is safe to do. Plus it's MUCH faster.
546
-
547
- NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
548
- NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");
549
-
550
- dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
551
-
552
- dispatch_async(globalLoggingQueue, ^{
553
- dispatch_async(loggerQueue, block);
554
- });
643
+ dispatch_block_t block = ^{ @autoreleasepool {
644
+
645
+ maximumFileSize = newMaximumFileSize;
646
+ [self maybeRollLogFileDueToSize];
647
+
648
+ }};
649
+
650
+ // The design of this method is taken from the DDAbstractLogger implementation.
651
+ // For extensive documentation please refer to the DDAbstractLogger implementation.
652
+
653
+ // Note: The internal implementation MUST access the maximumFileSize variable directly,
654
+ // This method is designed explicitly for external access.
655
+ //
656
+ // Using "self." syntax to go through this method will cause immediate deadlock.
657
+ // This is the intended result. Fix it by accessing the ivar directly.
658
+ // Great strides have been take to ensure this is safe to do. Plus it's MUCH faster.
659
+
660
+ NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
661
+ NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");
662
+
663
+ dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
664
+
665
+ dispatch_async(globalLoggingQueue, ^{
666
+ dispatch_async(loggerQueue, block);
667
+ });
555
668
  }
556
669
 
557
670
  - (NSTimeInterval)rollingFrequency
558
671
  {
559
- __block NSTimeInterval result;
560
-
561
- dispatch_block_t block = ^{
562
- result = rollingFrequency;
563
- };
564
-
565
- // The design of this method is taken from the DDAbstractLogger implementation.
566
- // For extensive documentation please refer to the DDAbstractLogger implementation.
567
-
568
- // Note: The internal implementation should access the rollingFrequency variable directly,
569
- // This method is designed explicitly for external access.
570
- //
571
- // Using "self." syntax to go through this method will cause immediate deadlock.
572
- // This is the intended result. Fix it by accessing the ivar directly.
573
- // Great strides have been take to ensure this is safe to do. Plus it's MUCH faster.
574
-
575
- NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
576
- NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");
577
-
578
- dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
579
-
580
- dispatch_sync(globalLoggingQueue, ^{
581
- dispatch_sync(loggerQueue, block);
582
- });
583
-
584
- return result;
672
+ __block NSTimeInterval result;
673
+
674
+ dispatch_block_t block = ^{
675
+ result = rollingFrequency;
676
+ };
677
+
678
+ // The design of this method is taken from the DDAbstractLogger implementation.
679
+ // For extensive documentation please refer to the DDAbstractLogger implementation.
680
+
681
+ // Note: The internal implementation should access the rollingFrequency variable directly,
682
+ // This method is designed explicitly for external access.
683
+ //
684
+ // Using "self." syntax to go through this method will cause immediate deadlock.
685
+ // This is the intended result. Fix it by accessing the ivar directly.
686
+ // Great strides have been take to ensure this is safe to do. Plus it's MUCH faster.
687
+
688
+ NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
689
+ NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");
690
+
691
+ dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
692
+
693
+ dispatch_sync(globalLoggingQueue, ^{
694
+ dispatch_sync(loggerQueue, block);
695
+ });
696
+
697
+ return result;
585
698
  }
586
699
 
587
700
  - (void)setRollingFrequency:(NSTimeInterval)newRollingFrequency
588
701
  {
589
- dispatch_block_t block = ^{ @autoreleasepool {
590
-
591
- rollingFrequency = newRollingFrequency;
592
- [self maybeRollLogFileDueToAge];
593
- }};
594
-
595
- // The design of this method is taken from the DDAbstractLogger implementation.
596
- // For extensive documentation please refer to the DDAbstractLogger implementation.
597
-
598
- // Note: The internal implementation should access the rollingFrequency variable directly,
599
- // This method is designed explicitly for external access.
600
- //
601
- // Using "self." syntax to go through this method will cause immediate deadlock.
602
- // This is the intended result. Fix it by accessing the ivar directly.
603
- // Great strides have been take to ensure this is safe to do. Plus it's MUCH faster.
604
-
605
- NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
606
- NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");
607
-
608
- dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
609
-
610
- dispatch_async(globalLoggingQueue, ^{
611
- dispatch_async(loggerQueue, block);
612
- });
702
+ dispatch_block_t block = ^{ @autoreleasepool {
703
+
704
+ rollingFrequency = newRollingFrequency;
705
+ [self maybeRollLogFileDueToAge];
706
+ }};
707
+
708
+ // The design of this method is taken from the DDAbstractLogger implementation.
709
+ // For extensive documentation please refer to the DDAbstractLogger implementation.
710
+
711
+ // Note: The internal implementation should access the rollingFrequency variable directly,
712
+ // This method is designed explicitly for external access.
713
+ //
714
+ // Using "self." syntax to go through this method will cause immediate deadlock.
715
+ // This is the intended result. Fix it by accessing the ivar directly.
716
+ // Great strides have been take to ensure this is safe to do. Plus it's MUCH faster.
717
+
718
+ NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
719
+ NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");
720
+
721
+ dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
722
+
723
+ dispatch_async(globalLoggingQueue, ^{
724
+ dispatch_async(loggerQueue, block);
725
+ });
613
726
  }
614
727
 
615
728
  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -618,139 +731,157 @@
618
731
 
619
732
  - (void)scheduleTimerToRollLogFileDueToAge
620
733
  {
621
- if (rollingTimer)
622
- {
623
- dispatch_source_cancel(rollingTimer);
624
- rollingTimer = NULL;
625
- }
626
-
627
- if (currentLogFileInfo == nil || rollingFrequency <= 0.0)
628
- {
629
- return;
630
- }
631
-
632
- NSDate *logFileCreationDate = [currentLogFileInfo creationDate];
633
-
634
- NSTimeInterval ti = [logFileCreationDate timeIntervalSinceReferenceDate];
635
- ti += rollingFrequency;
636
-
637
- NSDate *logFileRollingDate = [NSDate dateWithTimeIntervalSinceReferenceDate:ti];
638
-
639
- NSLogVerbose(@"DDFileLogger: scheduleTimerToRollLogFileDueToAge");
640
-
641
- NSLogVerbose(@"DDFileLogger: logFileCreationDate: %@", logFileCreationDate);
642
- NSLogVerbose(@"DDFileLogger: logFileRollingDate : %@", logFileRollingDate);
643
-
644
- rollingTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, loggerQueue);
645
-
646
- dispatch_source_set_event_handler(rollingTimer, ^{ @autoreleasepool {
647
-
648
- [self maybeRollLogFileDueToAge];
649
-
650
- }});
651
-
652
- #if !OS_OBJECT_USE_OBJC
653
- dispatch_source_t theRollingTimer = rollingTimer;
654
- dispatch_source_set_cancel_handler(rollingTimer, ^{
655
- dispatch_release(theRollingTimer);
656
- });
657
- #endif
658
-
659
- uint64_t delay = (uint64_t)([logFileRollingDate timeIntervalSinceNow] * NSEC_PER_SEC);
660
- dispatch_time_t fireTime = dispatch_time(DISPATCH_TIME_NOW, delay);
661
-
662
- dispatch_source_set_timer(rollingTimer, fireTime, DISPATCH_TIME_FOREVER, 1.0);
663
- dispatch_resume(rollingTimer);
734
+ if (rollingTimer)
735
+ {
736
+ dispatch_source_cancel(rollingTimer);
737
+ rollingTimer = NULL;
738
+ }
739
+
740
+ if (currentLogFileInfo == nil || rollingFrequency <= 0.0)
741
+ {
742
+ return;
743
+ }
744
+
745
+ NSDate *logFileCreationDate = [currentLogFileInfo creationDate];
746
+
747
+ NSTimeInterval ti = [logFileCreationDate timeIntervalSinceReferenceDate];
748
+ ti += rollingFrequency;
749
+
750
+ NSDate *logFileRollingDate = [NSDate dateWithTimeIntervalSinceReferenceDate:ti];
751
+
752
+ NSLogVerbose(@"DDFileLogger: scheduleTimerToRollLogFileDueToAge");
753
+
754
+ NSLogVerbose(@"DDFileLogger: logFileCreationDate: %@", logFileCreationDate);
755
+ NSLogVerbose(@"DDFileLogger: logFileRollingDate : %@", logFileRollingDate);
756
+
757
+ rollingTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, loggerQueue);
758
+
759
+ dispatch_source_set_event_handler(rollingTimer, ^{ @autoreleasepool {
760
+
761
+ [self maybeRollLogFileDueToAge];
762
+
763
+ }});
764
+
765
+ #if !OS_OBJECT_USE_OBJC
766
+ dispatch_source_t theRollingTimer = rollingTimer;
767
+ dispatch_source_set_cancel_handler(rollingTimer, ^{
768
+ dispatch_release(theRollingTimer);
769
+ });
770
+ #endif
771
+
772
+ uint64_t delay = (uint64_t)([logFileRollingDate timeIntervalSinceNow] * NSEC_PER_SEC);
773
+ dispatch_time_t fireTime = dispatch_time(DISPATCH_TIME_NOW, delay);
774
+
775
+ dispatch_source_set_timer(rollingTimer, fireTime, DISPATCH_TIME_FOREVER, 1.0);
776
+ dispatch_resume(rollingTimer);
664
777
  }
665
778
 
779
+
666
780
  - (void)rollLogFile
667
781
  {
668
- // This method is public.
669
- // We need to execute the rolling on our logging thread/queue.
670
-
671
- dispatch_block_t block = ^{ @autoreleasepool {
672
-
673
- [self rollLogFileNow];
674
- }};
675
-
676
- // The design of this method is taken from the DDAbstractLogger implementation.
677
- // For extensive documentation please refer to the DDAbstractLogger implementation.
678
-
679
- if ([self isOnInternalLoggerQueue])
680
- {
681
- block();
682
- }
683
- else
684
- {
685
- dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
686
- NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
687
-
688
- dispatch_async(globalLoggingQueue, ^{
689
- dispatch_async(loggerQueue, block);
690
- });
691
- }
782
+ [self rollLogFileWithCompletionBlock:nil];
783
+ }
784
+
785
+ - (void)rollLogFileWithCompletionBlock:(void (^)())completionBlock
786
+ {
787
+ // This method is public.
788
+ // We need to execute the rolling on our logging thread/queue.
789
+
790
+ dispatch_block_t block = ^{ @autoreleasepool {
791
+
792
+ [self rollLogFileNow];
793
+
794
+ if (completionBlock)
795
+ {
796
+ dispatch_async(dispatch_get_main_queue(), ^{
797
+ completionBlock();
798
+ });
799
+ }
800
+ }};
801
+
802
+ // The design of this method is taken from the DDAbstractLogger implementation.
803
+ // For extensive documentation please refer to the DDAbstractLogger implementation.
804
+
805
+ if ([self isOnInternalLoggerQueue])
806
+ {
807
+ block();
808
+ }
809
+ else
810
+ {
811
+ dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
812
+ NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
813
+
814
+ dispatch_async(globalLoggingQueue, ^{
815
+ dispatch_async(loggerQueue, block);
816
+ });
817
+ }
692
818
  }
693
819
 
694
820
  - (void)rollLogFileNow
695
821
  {
696
- NSLogVerbose(@"DDFileLogger: rollLogFileNow");
697
-
698
-
699
- if (currentLogFileHandle == nil) return;
700
-
701
- [currentLogFileHandle synchronizeFile];
702
- [currentLogFileHandle closeFile];
703
- currentLogFileHandle = nil;
704
-
705
- currentLogFileInfo.isArchived = YES;
706
-
707
- if ([logFileManager respondsToSelector:@selector(didRollAndArchiveLogFile:)])
708
- {
709
- [logFileManager didRollAndArchiveLogFile:(currentLogFileInfo.filePath)];
710
- }
711
-
712
- currentLogFileInfo = nil;
713
-
714
- if (rollingTimer)
715
- {
716
- dispatch_source_cancel(rollingTimer);
717
- rollingTimer = NULL;
718
- }
822
+ NSLogVerbose(@"DDFileLogger: rollLogFileNow");
823
+
824
+
825
+ if (currentLogFileHandle == nil) return;
826
+
827
+ [currentLogFileHandle synchronizeFile];
828
+ [currentLogFileHandle closeFile];
829
+ currentLogFileHandle = nil;
830
+
831
+ currentLogFileInfo.isArchived = YES;
832
+
833
+ if ([logFileManager respondsToSelector:@selector(didRollAndArchiveLogFile:)])
834
+ {
835
+ [logFileManager didRollAndArchiveLogFile:(currentLogFileInfo.filePath)];
836
+ }
837
+
838
+ currentLogFileInfo = nil;
839
+
840
+ if (currentLogFileVnode) {
841
+ dispatch_source_cancel(currentLogFileVnode);
842
+ currentLogFileVnode = NULL;
843
+ }
844
+
845
+ if (rollingTimer)
846
+ {
847
+ dispatch_source_cancel(rollingTimer);
848
+ rollingTimer = NULL;
849
+ }
719
850
  }
720
851
 
721
852
  - (void)maybeRollLogFileDueToAge
722
853
  {
723
- if (rollingFrequency > 0.0 && currentLogFileInfo.age >= rollingFrequency)
724
- {
725
- NSLogVerbose(@"DDFileLogger: Rolling log file due to age...");
726
-
727
- [self rollLogFileNow];
728
- }
729
- else
730
- {
731
- [self scheduleTimerToRollLogFileDueToAge];
732
- }
854
+ if (rollingFrequency > 0.0 && currentLogFileInfo.age >= rollingFrequency)
855
+ {
856
+ NSLogVerbose(@"DDFileLogger: Rolling log file due to age...");
857
+
858
+ [self rollLogFileNow];
859
+ }
860
+ else
861
+ {
862
+ [self scheduleTimerToRollLogFileDueToAge];
863
+ }
733
864
  }
734
865
 
735
866
  - (void)maybeRollLogFileDueToSize
736
867
  {
737
- // This method is called from logMessage.
738
- // Keep it FAST.
739
-
740
- // Note: Use direct access to maximumFileSize variable.
741
- // We specifically wrote our own getter/setter method to allow us to do this (for performance reasons).
742
-
743
- if (maximumFileSize > 0)
744
- {
745
- unsigned long long fileSize = [currentLogFileHandle offsetInFile];
746
-
747
- if (fileSize >= maximumFileSize)
748
- {
749
- NSLogVerbose(@"DDFileLogger: Rolling log file due to size (%qu)...", fileSize);
750
-
751
- [self rollLogFileNow];
752
- }
753
- }
868
+ // This method is called from logMessage.
869
+ // Keep it FAST.
870
+
871
+ // Note: Use direct access to maximumFileSize variable.
872
+ // We specifically wrote our own getter/setter method to allow us to do this (for performance reasons).
873
+
874
+ if (maximumFileSize > 0)
875
+ {
876
+ unsigned long long fileSize = [currentLogFileHandle offsetInFile];
877
+
878
+ if (fileSize >= maximumFileSize)
879
+ {
880
+ NSLogVerbose(@"DDFileLogger: Rolling log file due to size (%qu)...", fileSize);
881
+
882
+ [self rollLogFileNow];
883
+ }
884
+ }
754
885
  }
755
886
 
756
887
  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -766,120 +897,175 @@
766
897
  **/
767
898
  - (DDLogFileInfo *)currentLogFileInfo
768
899
  {
769
- if (currentLogFileInfo == nil)
770
- {
771
- NSArray *sortedLogFileInfos = [logFileManager sortedLogFileInfos];
772
-
773
- if ([sortedLogFileInfos count] > 0)
774
- {
775
- DDLogFileInfo *mostRecentLogFileInfo = [sortedLogFileInfos objectAtIndex:0];
776
-
777
- BOOL useExistingLogFile = YES;
778
- BOOL shouldArchiveMostRecent = NO;
779
-
780
- if (mostRecentLogFileInfo.isArchived)
781
- {
782
- useExistingLogFile = NO;
783
- shouldArchiveMostRecent = NO;
784
- }
785
- else if (maximumFileSize > 0 && mostRecentLogFileInfo.fileSize >= maximumFileSize)
786
- {
787
- useExistingLogFile = NO;
788
- shouldArchiveMostRecent = YES;
789
- }
790
- else if (rollingFrequency > 0.0 && mostRecentLogFileInfo.age >= rollingFrequency)
791
- {
792
- useExistingLogFile = NO;
793
- shouldArchiveMostRecent = YES;
794
- }
795
-
796
- if (useExistingLogFile)
797
- {
798
- NSLogVerbose(@"DDFileLogger: Resuming logging with file %@", mostRecentLogFileInfo.fileName);
799
-
800
- currentLogFileInfo = mostRecentLogFileInfo;
801
- }
802
- else
803
- {
804
- if (shouldArchiveMostRecent)
805
- {
806
- mostRecentLogFileInfo.isArchived = YES;
807
-
808
- if ([logFileManager respondsToSelector:@selector(didArchiveLogFile:)])
809
- {
810
- [logFileManager didArchiveLogFile:(mostRecentLogFileInfo.filePath)];
811
- }
812
- }
813
- }
814
- }
815
-
816
- if (currentLogFileInfo == nil)
817
- {
818
- NSString *currentLogFilePath = [logFileManager createNewLogFile];
819
-
820
- currentLogFileInfo = [[DDLogFileInfo alloc] initWithFilePath:currentLogFilePath];
821
- }
822
- }
823
-
824
- return currentLogFileInfo;
900
+ if (currentLogFileInfo == nil)
901
+ {
902
+ NSArray *sortedLogFileInfos = [logFileManager sortedLogFileInfos];
903
+
904
+ if ([sortedLogFileInfos count] > 0)
905
+ {
906
+ DDLogFileInfo *mostRecentLogFileInfo = [sortedLogFileInfos objectAtIndex:0];
907
+
908
+ BOOL useExistingLogFile = YES;
909
+ BOOL shouldArchiveMostRecent = NO;
910
+
911
+ if (mostRecentLogFileInfo.isArchived)
912
+ {
913
+ useExistingLogFile = NO;
914
+ shouldArchiveMostRecent = NO;
915
+ }
916
+ else if (maximumFileSize > 0 && mostRecentLogFileInfo.fileSize >= maximumFileSize)
917
+ {
918
+ useExistingLogFile = NO;
919
+ shouldArchiveMostRecent = YES;
920
+ }
921
+ else if (rollingFrequency > 0.0 && mostRecentLogFileInfo.age >= rollingFrequency)
922
+ {
923
+ useExistingLogFile = NO;
924
+ shouldArchiveMostRecent = YES;
925
+ }
926
+
927
+
928
+ #if TARGET_OS_IPHONE
929
+ // When creating log file on iOS we're setting NSFileProtectionKey attribute to NSFileProtectionCompleteUnlessOpen.
930
+ //
931
+ // But in case if app is able to launch from background we need to have an ability to open log file any time we
932
+ // want (even if device is locked). Thats why that attribute have to be changed to
933
+ // NSFileProtectionCompleteUntilFirstUserAuthentication.
934
+ //
935
+ // If previous log was created when app wasn't running in background, but now it is - we archive it and create
936
+ // a new one.
937
+
938
+ if (useExistingLogFile && doesAppRunInBackground()) {
939
+ NSString *key = mostRecentLogFileInfo.fileAttributes[NSFileProtectionKey];
940
+
941
+ if (! [key isEqualToString:NSFileProtectionCompleteUntilFirstUserAuthentication]) {
942
+ useExistingLogFile = NO;
943
+ shouldArchiveMostRecent = YES;
944
+ }
945
+ }
946
+ #endif
947
+
948
+ if (useExistingLogFile)
949
+ {
950
+ NSLogVerbose(@"DDFileLogger: Resuming logging with file %@", mostRecentLogFileInfo.fileName);
951
+
952
+ currentLogFileInfo = mostRecentLogFileInfo;
953
+ }
954
+ else
955
+ {
956
+ if (shouldArchiveMostRecent)
957
+ {
958
+ mostRecentLogFileInfo.isArchived = YES;
959
+
960
+ if ([logFileManager respondsToSelector:@selector(didArchiveLogFile:)])
961
+ {
962
+ [logFileManager didArchiveLogFile:(mostRecentLogFileInfo.filePath)];
963
+ }
964
+ }
965
+ }
966
+ }
967
+
968
+ if (currentLogFileInfo == nil)
969
+ {
970
+ NSString *currentLogFilePath = [logFileManager createNewLogFile];
971
+
972
+ currentLogFileInfo = [[DDLogFileInfo alloc] initWithFilePath:currentLogFilePath];
973
+ }
974
+ }
975
+
976
+ return currentLogFileInfo;
825
977
  }
826
978
 
827
979
  - (NSFileHandle *)currentLogFileHandle
828
980
  {
829
- if (currentLogFileHandle == nil)
830
- {
831
- NSString *logFilePath = [[self currentLogFileInfo] filePath];
832
-
833
- currentLogFileHandle = [NSFileHandle fileHandleForWritingAtPath:logFilePath];
834
- [currentLogFileHandle seekToEndOfFile];
835
-
836
- if (currentLogFileHandle)
837
- {
838
- [self scheduleTimerToRollLogFileDueToAge];
839
- }
840
- }
841
-
842
- return currentLogFileHandle;
981
+ if (currentLogFileHandle == nil)
982
+ {
983
+ NSString *logFilePath = [[self currentLogFileInfo] filePath];
984
+
985
+ currentLogFileHandle = [NSFileHandle fileHandleForWritingAtPath:logFilePath];
986
+ [currentLogFileHandle seekToEndOfFile];
987
+
988
+ if (currentLogFileHandle)
989
+ {
990
+ [self scheduleTimerToRollLogFileDueToAge];
991
+
992
+ // Here we are monitoring the log file. In case if it would be deleted ormoved
993
+ // somewhere we want to roll it and use a new one.
994
+ currentLogFileVnode = dispatch_source_create(
995
+ DISPATCH_SOURCE_TYPE_VNODE,
996
+ [currentLogFileHandle fileDescriptor],
997
+ DISPATCH_VNODE_DELETE | DISPATCH_VNODE_RENAME,
998
+ loggerQueue
999
+ );
1000
+
1001
+ dispatch_source_set_event_handler(currentLogFileVnode, ^{ @autoreleasepool {
1002
+ NSLogInfo(@"DDFileLogger: Current logfile was moved. Rolling it and creating a new one");
1003
+ [self rollLogFileNow];
1004
+ }});
1005
+
1006
+ #if !OS_OBJECT_USE_OBJC
1007
+ dispatch_source_t vnode = currentLogFileVnode;
1008
+ dispatch_source_set_cancel_handler(currentLogFileVnode, ^{
1009
+ dispatch_release(vnode);
1010
+ });
1011
+ #endif
1012
+
1013
+ dispatch_resume(currentLogFileVnode);
1014
+ }
1015
+ }
1016
+
1017
+ return currentLogFileHandle;
843
1018
  }
844
1019
 
845
1020
  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
846
1021
  #pragma mark DDLogger Protocol
847
1022
  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
848
1023
 
1024
+ static int exception_count = 0;
849
1025
  - (void)logMessage:(DDLogMessage *)logMessage
850
1026
  {
851
- NSString *logMsg = logMessage->logMsg;
852
-
853
- if (formatter)
854
- {
855
- logMsg = [formatter formatLogMessage:logMessage];
856
- }
857
-
858
- if (logMsg)
859
- {
860
- if (![logMsg hasSuffix:@"\n"])
861
- {
862
- logMsg = [logMsg stringByAppendingString:@"\n"];
863
- }
864
-
865
- NSData *logData = [logMsg dataUsingEncoding:NSUTF8StringEncoding];
866
-
867
- [[self currentLogFileHandle] writeData:logData];
868
-
869
- [self maybeRollLogFileDueToSize];
870
- }
1027
+ NSString *logMsg = logMessage->logMsg;
1028
+
1029
+ if (formatter)
1030
+ {
1031
+ logMsg = [formatter formatLogMessage:logMessage];
1032
+ }
1033
+
1034
+ if (logMsg)
1035
+ {
1036
+ if (![logMsg hasSuffix:@"\n"])
1037
+ {
1038
+ logMsg = [logMsg stringByAppendingString:@"\n"];
1039
+ }
1040
+
1041
+ NSData *logData = [logMsg dataUsingEncoding:NSUTF8StringEncoding];
1042
+
1043
+ @try {
1044
+ [[self currentLogFileHandle] writeData:logData];
1045
+
1046
+ [self maybeRollLogFileDueToSize];
1047
+ }
1048
+ @catch (NSException *exception) {
1049
+ exception_count++;
1050
+ if (exception_count <= 10) {
1051
+ NSLogError(@"DDFileLogger.logMessage: %@", exception);
1052
+ if (exception_count == 10)
1053
+ NSLogError(@"DDFileLogger.logMessage: Too many exceptions -- will not log any more of them.");
1054
+ }
1055
+ }
1056
+ }
871
1057
  }
872
1058
 
873
1059
  - (void)willRemoveLogger
874
1060
  {
875
- // If you override me be sure to invoke [super willRemoveLogger];
876
-
877
- [self rollLogFileNow];
1061
+ // If you override me be sure to invoke [super willRemoveLogger];
1062
+
1063
+ [self rollLogFileNow];
878
1064
  }
879
1065
 
880
1066
  - (NSString *)loggerName
881
1067
  {
882
- return @"cocoa.lumberjack.fileLogger";
1068
+ return @"cocoa.lumberjack.fileLogger";
883
1069
  }
884
1070
 
885
1071
  @end
@@ -910,18 +1096,18 @@
910
1096
 
911
1097
  #pragma mark Lifecycle
912
1098
 
913
- + (id)logFileWithPath:(NSString *)aFilePath
1099
+ + (instancetype)logFileWithPath:(NSString *)aFilePath
914
1100
  {
915
- return [[DDLogFileInfo alloc] initWithFilePath:aFilePath];
1101
+ return [[self alloc] initWithFilePath:aFilePath];
916
1102
  }
917
1103
 
918
- - (id)initWithFilePath:(NSString *)aFilePath
1104
+ - (instancetype)initWithFilePath:(NSString *)aFilePath
919
1105
  {
920
- if ((self = [super init]))
921
- {
922
- filePath = [aFilePath copy];
923
- }
924
- return self;
1106
+ if ((self = [super init]))
1107
+ {
1108
+ filePath = [aFilePath copy];
1109
+ }
1110
+ return self;
925
1111
  }
926
1112
 
927
1113
  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -930,101 +1116,66 @@
930
1116
 
931
1117
  - (NSDictionary *)fileAttributes
932
1118
  {
933
- if (fileAttributes == nil)
934
- {
935
- fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil];
936
- }
937
- return fileAttributes;
1119
+ if (fileAttributes == nil)
1120
+ {
1121
+ fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil];
1122
+ }
1123
+ return fileAttributes;
938
1124
  }
939
1125
 
940
1126
  - (NSString *)fileName
941
1127
  {
942
- if (fileName == nil)
943
- {
944
- fileName = [filePath lastPathComponent];
945
- }
946
- return fileName;
1128
+ if (fileName == nil)
1129
+ {
1130
+ fileName = [filePath lastPathComponent];
1131
+ }
1132
+ return fileName;
947
1133
  }
948
1134
 
949
1135
  - (NSDate *)modificationDate
950
1136
  {
951
- if (modificationDate == nil)
952
- {
953
- modificationDate = [[self fileAttributes] objectForKey:NSFileModificationDate];
954
- }
955
-
956
- return modificationDate;
1137
+ if (modificationDate == nil)
1138
+ {
1139
+ modificationDate = [[self fileAttributes] objectForKey:NSFileModificationDate];
1140
+ }
1141
+
1142
+ return modificationDate;
957
1143
  }
958
1144
 
959
1145
  - (NSDate *)creationDate
960
1146
  {
961
- if (creationDate == nil)
962
- {
963
-
964
- #if TARGET_OS_IPHONE
965
-
966
- const char *path = [filePath UTF8String];
967
-
968
- struct attrlist attrList;
969
- memset(&attrList, 0, sizeof(attrList));
970
- attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
971
- attrList.commonattr = ATTR_CMN_CRTIME;
972
-
973
- struct {
974
- u_int32_t attrBufferSizeInBytes;
975
- struct timespec crtime;
976
- } attrBuffer;
977
-
978
- int result = getattrlist(path, &attrList, &attrBuffer, sizeof(attrBuffer), 0);
979
- if (result == 0)
980
- {
981
- double seconds = (double)(attrBuffer.crtime.tv_sec);
982
- double nanos = (double)(attrBuffer.crtime.tv_nsec);
983
-
984
- NSTimeInterval ti = seconds + (nanos / 1000000000.0);
985
-
986
- creationDate = [NSDate dateWithTimeIntervalSince1970:ti];
987
- }
988
- else
989
- {
990
- NSLogError(@"DDLogFileInfo: creationDate(%@): getattrlist result = %i", self.fileName, result);
991
- }
992
-
993
- #else
994
-
995
- creationDate = [[self fileAttributes] objectForKey:NSFileCreationDate];
996
-
997
- #endif
998
-
999
- }
1000
- return creationDate;
1147
+ if (creationDate == nil)
1148
+ {
1149
+ creationDate = [[self fileAttributes] objectForKey:NSFileCreationDate];
1150
+ }
1151
+ return creationDate;
1001
1152
  }
1002
1153
 
1003
1154
  - (unsigned long long)fileSize
1004
1155
  {
1005
- if (fileSize == 0)
1006
- {
1007
- fileSize = [[[self fileAttributes] objectForKey:NSFileSize] unsignedLongLongValue];
1008
- }
1009
-
1010
- return fileSize;
1156
+ if (fileSize == 0)
1157
+ {
1158
+ fileSize = [[[self fileAttributes] objectForKey:NSFileSize] unsignedLongLongValue];
1159
+ }
1160
+
1161
+ return fileSize;
1011
1162
  }
1012
1163
 
1013
1164
  - (NSTimeInterval)age
1014
1165
  {
1015
- return [[self creationDate] timeIntervalSinceNow] * -1.0;
1166
+ return [[self creationDate] timeIntervalSinceNow] * -1.0;
1016
1167
  }
1017
1168
 
1018
1169
  - (NSString *)description
1019
1170
  {
1020
- return [@{@"filePath": self.filePath,
1021
- @"fileName": self.fileName,
1022
- @"fileAttributes": self.fileAttributes,
1023
- @"creationDate": self.creationDate,
1024
- @"modificationDate": self.modificationDate,
1025
- @"fileSize": @(self.fileSize),
1026
- @"age": @(self.age),
1027
- @"isArchived": @(self.isArchived)} description];
1171
+ return [@{@"filePath": self.filePath ?: @"",
1172
+ @"fileName": self.fileName ?: @"",
1173
+ @"fileAttributes": self.fileAttributes ?: @"",
1174
+ @"creationDate": self.creationDate ?: @"",
1175
+ @"modificationDate": self.modificationDate ?: @"",
1176
+ @"fileSize": @(self.fileSize),
1177
+ @"age": @(self.age),
1178
+ @"isArchived": @(self.isArchived)} description];
1028
1179
  }
1029
1180
 
1030
1181
  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -1033,43 +1184,43 @@
1033
1184
 
1034
1185
  - (BOOL)isArchived
1035
1186
  {
1036
-
1187
+
1037
1188
  #if TARGET_IPHONE_SIMULATOR
1038
-
1039
- // Extended attributes don't work properly on the simulator.
1040
- // So we have to use a less attractive alternative.
1041
- // See full explanation in the header file.
1042
-
1043
- return [self hasExtensionAttributeWithName:XATTR_ARCHIVED_NAME];
1044
-
1189
+
1190
+ // Extended attributes don't work properly on the simulator.
1191
+ // So we have to use a less attractive alternative.
1192
+ // See full explanation in the header file.
1193
+
1194
+ return [self hasExtensionAttributeWithName:XATTR_ARCHIVED_NAME];
1195
+
1045
1196
  #else
1046
-
1047
- return [self hasExtendedAttributeWithName:XATTR_ARCHIVED_NAME];
1048
-
1197
+
1198
+ return [self hasExtendedAttributeWithName:XATTR_ARCHIVED_NAME];
1199
+
1049
1200
  #endif
1050
1201
  }
1051
1202
 
1052
1203
  - (void)setIsArchived:(BOOL)flag
1053
1204
  {
1054
-
1205
+
1055
1206
  #if TARGET_IPHONE_SIMULATOR
1056
-
1057
- // Extended attributes don't work properly on the simulator.
1058
- // So we have to use a less attractive alternative.
1059
- // See full explanation in the header file.
1060
-
1061
- if (flag)
1062
- [self addExtensionAttributeWithName:XATTR_ARCHIVED_NAME];
1063
- else
1064
- [self removeExtensionAttributeWithName:XATTR_ARCHIVED_NAME];
1065
-
1207
+
1208
+ // Extended attributes don't work properly on the simulator.
1209
+ // So we have to use a less attractive alternative.
1210
+ // See full explanation in the header file.
1211
+
1212
+ if (flag)
1213
+ [self addExtensionAttributeWithName:XATTR_ARCHIVED_NAME];
1214
+ else
1215
+ [self removeExtensionAttributeWithName:XATTR_ARCHIVED_NAME];
1216
+
1066
1217
  #else
1067
-
1068
- if (flag)
1069
- [self addExtendedAttributeWithName:XATTR_ARCHIVED_NAME];
1070
- else
1071
- [self removeExtendedAttributeWithName:XATTR_ARCHIVED_NAME];
1072
-
1218
+
1219
+ if (flag)
1220
+ [self addExtendedAttributeWithName:XATTR_ARCHIVED_NAME];
1221
+ else
1222
+ [self removeExtendedAttributeWithName:XATTR_ARCHIVED_NAME];
1223
+
1073
1224
  #endif
1074
1225
  }
1075
1226
 
@@ -1079,36 +1230,43 @@
1079
1230
 
1080
1231
  - (void)reset
1081
1232
  {
1082
- fileName = nil;
1083
- fileAttributes = nil;
1084
- creationDate = nil;
1085
- modificationDate = nil;
1233
+ fileName = nil;
1234
+ fileAttributes = nil;
1235
+ creationDate = nil;
1236
+ modificationDate = nil;
1086
1237
  }
1087
1238
 
1088
1239
  - (void)renameFile:(NSString *)newFileName
1089
1240
  {
1090
- // This method is only used on the iPhone simulator, where normal extended attributes are broken.
1091
- // See full explanation in the header file.
1092
-
1093
- if (![newFileName isEqualToString:[self fileName]])
1094
- {
1095
- NSString *fileDir = [filePath stringByDeletingLastPathComponent];
1096
-
1097
- NSString *newFilePath = [fileDir stringByAppendingPathComponent:newFileName];
1098
-
1099
- NSLogVerbose(@"DDLogFileInfo: Renaming file: '%@' -> '%@'", self.fileName, newFileName);
1100
-
1101
- NSError *error = nil;
1102
- if (![[NSFileManager defaultManager] moveItemAtPath:filePath toPath:newFilePath error:&error])
1103
- {
1104
- NSLogError(@"DDLogFileInfo: Error renaming file (%@): %@", self.fileName, error);
1105
- }
1106
-
1107
- filePath = newFilePath;
1108
- [self reset];
1109
- }
1241
+ // This method is only used on the iPhone simulator, where normal extended attributes are broken.
1242
+ // See full explanation in the header file.
1243
+
1244
+ if (![newFileName isEqualToString:[self fileName]])
1245
+ {
1246
+ NSString *fileDir = [filePath stringByDeletingLastPathComponent];
1247
+
1248
+ NSString *newFilePath = [fileDir stringByAppendingPathComponent:newFileName];
1249
+
1250
+ NSLogVerbose(@"DDLogFileInfo: Renaming file: '%@' -> '%@'", self.fileName, newFileName);
1251
+
1252
+ NSError *error = nil;
1253
+ if (![[NSFileManager defaultManager] fileExistsAtPath:newFilePath]){
1254
+ if([[NSFileManager defaultManager] removeItemAtPath:newFilePath error:&error]){
1255
+ NSLogError(@"DDLogFileInfo: Error deleting archive (%@): %@", self.fileName, error);
1256
+ }
1257
+ }
1258
+
1259
+ if (![[NSFileManager defaultManager] moveItemAtPath:filePath toPath:newFilePath error:&error])
1260
+ {
1261
+ NSLogError(@"DDLogFileInfo: Error renaming file (%@): %@", self.fileName, error);
1262
+ }
1263
+
1264
+ filePath = newFilePath;
1265
+ [self reset];
1266
+ }
1110
1267
  }
1111
1268
 
1269
+
1112
1270
  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1113
1271
  #pragma mark Attribute Management
1114
1272
  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -1121,183 +1279,185 @@
1121
1279
 
1122
1280
  - (BOOL)hasExtensionAttributeWithName:(NSString *)attrName
1123
1281
  {
1124
- // This method is only used on the iPhone simulator, where normal extended attributes are broken.
1125
- // See full explanation in the header file.
1126
-
1127
- // Split the file name into components.
1128
- //
1129
- // log-ABC123.archived.uploaded.txt
1130
- //
1131
- // 0. log-ABC123
1132
- // 1. archived
1133
- // 2. uploaded
1134
- // 3. txt
1135
- //
1136
- // So we want to search for the attrName in the components (ignoring the first and last array indexes).
1137
-
1138
- NSArray *components = [[self fileName] componentsSeparatedByString:@"."];
1139
-
1140
- // Watch out for file names without an extension
1141
-
1142
- NSUInteger count = [components count];
1143
- NSUInteger max = (count >= 2) ? count-1 : count;
1144
-
1145
- NSUInteger i;
1146
- for (i = 1; i < max; i++)
1147
- {
1148
- NSString *attr = [components objectAtIndex:i];
1149
-
1150
- if ([attrName isEqualToString:attr])
1151
- {
1152
- return YES;
1153
- }
1154
- }
1155
-
1156
- return NO;
1282
+ // This method is only used on the iPhone simulator, where normal extended attributes are broken.
1283
+ // See full explanation in the header file.
1284
+
1285
+ // Split the file name into components. File name may have various format, but generally
1286
+ // structure is same:
1287
+ //
1288
+ // <name part>.<extension part> and <name part>.archived.<extension part>
1289
+ // or
1290
+ // <name part> and <name part>.archived
1291
+ //
1292
+ // So we want to search for the attrName in the components (ignoring the first array index).
1293
+
1294
+ NSArray *components = [[self fileName] componentsSeparatedByString:@"."];
1295
+
1296
+ // Watch out for file names without an extension
1297
+
1298
+ for (NSUInteger i = 1; i < components.count; i++)
1299
+ {
1300
+ NSString *attr = [components objectAtIndex:i];
1301
+
1302
+ if ([attrName isEqualToString:attr])
1303
+ {
1304
+ return YES;
1305
+ }
1306
+ }
1307
+
1308
+ return NO;
1157
1309
  }
1158
1310
 
1159
1311
  - (void)addExtensionAttributeWithName:(NSString *)attrName
1160
1312
  {
1161
- // This method is only used on the iPhone simulator, where normal extended attributes are broken.
1162
- // See full explanation in the header file.
1163
-
1164
- if ([attrName length] == 0) return;
1165
-
1166
- // Example:
1167
- // attrName = "archived"
1168
- //
1169
- // "log-ABC123.txt" -> "log-ABC123.archived.txt"
1170
-
1171
- NSArray *components = [[self fileName] componentsSeparatedByString:@"."];
1172
-
1173
- NSUInteger count = [components count];
1174
-
1175
- NSUInteger estimatedNewLength = [[self fileName] length] + [attrName length] + 1;
1176
- NSMutableString *newFileName = [NSMutableString stringWithCapacity:estimatedNewLength];
1177
-
1178
- if (count > 0)
1179
- {
1180
- [newFileName appendString:[components objectAtIndex:0]];
1181
- }
1182
-
1183
- NSString *lastExt = @"";
1184
-
1185
- NSUInteger i;
1186
- for (i = 1; i < count; i++)
1187
- {
1188
- NSString *attr = [components objectAtIndex:i];
1189
- if ([attr length] == 0)
1190
- {
1191
- continue;
1192
- }
1193
-
1194
- if ([attrName isEqualToString:attr])
1195
- {
1196
- // Extension attribute already exists in file name
1197
- return;
1198
- }
1199
-
1200
- if ([lastExt length] > 0)
1201
- {
1202
- [newFileName appendFormat:@".%@", lastExt];
1203
- }
1204
-
1205
- lastExt = attr;
1206
- }
1207
-
1208
- [newFileName appendFormat:@".%@", attrName];
1209
-
1210
- if ([lastExt length] > 0)
1211
- {
1212
- [newFileName appendFormat:@".%@", lastExt];
1213
- }
1214
-
1215
- [self renameFile:newFileName];
1313
+ // This method is only used on the iPhone simulator, where normal extended attributes are broken.
1314
+ // See full explanation in the header file.
1315
+
1316
+ if ([attrName length] == 0) return;
1317
+
1318
+ // Example:
1319
+ // attrName = "archived"
1320
+ //
1321
+ // "mylog.txt" -> "mylog.archived.txt"
1322
+ // "mylog" -> "mylog.archived"
1323
+
1324
+ NSArray *components = [[self fileName] componentsSeparatedByString:@"."];
1325
+
1326
+ NSUInteger count = [components count];
1327
+
1328
+ NSUInteger estimatedNewLength = [[self fileName] length] + [attrName length] + 1;
1329
+ NSMutableString *newFileName = [NSMutableString stringWithCapacity:estimatedNewLength];
1330
+
1331
+ if (count > 0)
1332
+ {
1333
+ [newFileName appendString:[components objectAtIndex:0]];
1334
+ }
1335
+
1336
+ NSString *lastExt = @"";
1337
+
1338
+ NSUInteger i;
1339
+ for (i = 1; i < count; i++)
1340
+ {
1341
+ NSString *attr = [components objectAtIndex:i];
1342
+ if ([attr length] == 0)
1343
+ {
1344
+ continue;
1345
+ }
1346
+
1347
+ if ([attrName isEqualToString:attr])
1348
+ {
1349
+ // Extension attribute already exists in file name
1350
+ return;
1351
+ }
1352
+
1353
+ if ([lastExt length] > 0)
1354
+ {
1355
+ [newFileName appendFormat:@".%@", lastExt];
1356
+ }
1357
+
1358
+ lastExt = attr;
1359
+ }
1360
+
1361
+ [newFileName appendFormat:@".%@", attrName];
1362
+
1363
+ if ([lastExt length] > 0)
1364
+ {
1365
+ [newFileName appendFormat:@".%@", lastExt];
1366
+ }
1367
+
1368
+ [self renameFile:newFileName];
1216
1369
  }
1217
1370
 
1218
1371
  - (void)removeExtensionAttributeWithName:(NSString *)attrName
1219
1372
  {
1220
- // This method is only used on the iPhone simulator, where normal extended attributes are broken.
1221
- // See full explanation in the header file.
1222
-
1223
- if ([attrName length] == 0) return;
1224
-
1225
- // Example:
1226
- // attrName = "archived"
1227
- //
1228
- // "log-ABC123.txt" -> "log-ABC123.archived.txt"
1229
-
1230
- NSArray *components = [[self fileName] componentsSeparatedByString:@"."];
1231
-
1232
- NSUInteger count = [components count];
1233
-
1234
- NSUInteger estimatedNewLength = [[self fileName] length];
1235
- NSMutableString *newFileName = [NSMutableString stringWithCapacity:estimatedNewLength];
1236
-
1237
- if (count > 0)
1238
- {
1239
- [newFileName appendString:[components objectAtIndex:0]];
1240
- }
1241
-
1242
- BOOL found = NO;
1243
-
1244
- NSUInteger i;
1245
- for (i = 1; i < count; i++)
1246
- {
1247
- NSString *attr = [components objectAtIndex:i];
1248
-
1249
- if ([attrName isEqualToString:attr])
1250
- {
1251
- found = YES;
1252
- }
1253
- else
1254
- {
1255
- [newFileName appendFormat:@".%@", attr];
1256
- }
1257
- }
1258
-
1259
- if (found)
1260
- {
1261
- [self renameFile:newFileName];
1262
- }
1373
+ // This method is only used on the iPhone simulator, where normal extended attributes are broken.
1374
+ // See full explanation in the header file.
1375
+
1376
+ if ([attrName length] == 0) return;
1377
+
1378
+ // Example:
1379
+ // attrName = "archived"
1380
+ //
1381
+ // "mylog.archived.txt" -> "mylog.txt"
1382
+ // "mylog.archived" -> "mylog"
1383
+
1384
+ NSArray *components = [[self fileName] componentsSeparatedByString:@"."];
1385
+
1386
+ NSUInteger count = [components count];
1387
+
1388
+ NSUInteger estimatedNewLength = [[self fileName] length];
1389
+ NSMutableString *newFileName = [NSMutableString stringWithCapacity:estimatedNewLength];
1390
+
1391
+ if (count > 0)
1392
+ {
1393
+ [newFileName appendString:[components objectAtIndex:0]];
1394
+ }
1395
+
1396
+ BOOL found = NO;
1397
+
1398
+ NSUInteger i;
1399
+ for (i = 1; i < count; i++)
1400
+ {
1401
+ NSString *attr = [components objectAtIndex:i];
1402
+
1403
+ if ([attrName isEqualToString:attr])
1404
+ {
1405
+ found = YES;
1406
+ }
1407
+ else
1408
+ {
1409
+ [newFileName appendFormat:@".%@", attr];
1410
+ }
1411
+ }
1412
+
1413
+ if (found)
1414
+ {
1415
+ [self renameFile:newFileName];
1416
+ }
1263
1417
  }
1264
1418
 
1265
1419
  #else
1266
1420
 
1267
1421
  - (BOOL)hasExtendedAttributeWithName:(NSString *)attrName
1268
1422
  {
1269
- const char *path = [filePath UTF8String];
1270
- const char *name = [attrName UTF8String];
1271
-
1272
- ssize_t result = getxattr(path, name, NULL, 0, 0, 0);
1273
-
1274
- return (result >= 0);
1423
+ const char *path = [filePath UTF8String];
1424
+ const char *name = [attrName UTF8String];
1425
+
1426
+ ssize_t result = getxattr(path, name, NULL, 0, 0, 0);
1427
+
1428
+ return (result >= 0);
1275
1429
  }
1276
1430
 
1277
1431
  - (void)addExtendedAttributeWithName:(NSString *)attrName
1278
1432
  {
1279
- const char *path = [filePath UTF8String];
1280
- const char *name = [attrName UTF8String];
1281
-
1282
- int result = setxattr(path, name, NULL, 0, 0, 0);
1283
-
1284
- if (result < 0)
1285
- {
1286
- NSLogError(@"DDLogFileInfo: setxattr(%@, %@): error = %i", attrName, self.fileName, result);
1287
- }
1433
+ const char *path = [filePath UTF8String];
1434
+ const char *name = [attrName UTF8String];
1435
+
1436
+ int result = setxattr(path, name, NULL, 0, 0, 0);
1437
+
1438
+ if (result < 0)
1439
+ {
1440
+ NSLogError(@"DDLogFileInfo: setxattr(%@, %@): error = %s",
1441
+ attrName,
1442
+ self.fileName,
1443
+ strerror(errno));
1444
+ }
1288
1445
  }
1289
1446
 
1290
1447
  - (void)removeExtendedAttributeWithName:(NSString *)attrName
1291
1448
  {
1292
- const char *path = [filePath UTF8String];
1293
- const char *name = [attrName UTF8String];
1294
-
1295
- int result = removexattr(path, name, 0);
1296
-
1297
- if (result < 0 && errno != ENOATTR)
1298
- {
1299
- NSLogError(@"DDLogFileInfo: removexattr(%@, %@): error = %i", attrName, self.fileName, result);
1300
- }
1449
+ const char *path = [filePath UTF8String];
1450
+ const char *name = [attrName UTF8String];
1451
+
1452
+ int result = removexattr(path, name, 0);
1453
+
1454
+ if (result < 0 && errno != ENOATTR)
1455
+ {
1456
+ NSLogError(@"DDLogFileInfo: removexattr(%@, %@): error = %s",
1457
+ attrName,
1458
+ self.fileName,
1459
+ strerror(errno));
1460
+ }
1301
1461
  }
1302
1462
 
1303
1463
  #endif
@@ -1308,46 +1468,72 @@
1308
1468
 
1309
1469
  - (BOOL)isEqual:(id)object
1310
1470
  {
1311
- if ([object isKindOfClass:[self class]])
1312
- {
1313
- DDLogFileInfo *another = (DDLogFileInfo *)object;
1314
-
1315
- return [filePath isEqualToString:[another filePath]];
1316
- }
1317
-
1318
- return NO;
1471
+ if ([object isKindOfClass:[self class]])
1472
+ {
1473
+ DDLogFileInfo *another = (DDLogFileInfo *)object;
1474
+
1475
+ return [filePath isEqualToString:[another filePath]];
1476
+ }
1477
+
1478
+ return NO;
1319
1479
  }
1320
1480
 
1321
1481
  - (NSComparisonResult)reverseCompareByCreationDate:(DDLogFileInfo *)another
1322
1482
  {
1323
- NSDate *us = [self creationDate];
1324
- NSDate *them = [another creationDate];
1325
-
1326
- NSComparisonResult result = [us compare:them];
1327
-
1328
- if (result == NSOrderedAscending)
1329
- return NSOrderedDescending;
1330
-
1331
- if (result == NSOrderedDescending)
1332
- return NSOrderedAscending;
1333
-
1334
- return NSOrderedSame;
1483
+ NSDate *us = [self creationDate];
1484
+ NSDate *them = [another creationDate];
1485
+
1486
+ NSComparisonResult result = [us compare:them];
1487
+
1488
+ if (result == NSOrderedAscending)
1489
+ return NSOrderedDescending;
1490
+
1491
+ if (result == NSOrderedDescending)
1492
+ return NSOrderedAscending;
1493
+
1494
+ return NSOrderedSame;
1335
1495
  }
1336
1496
 
1337
1497
  - (NSComparisonResult)reverseCompareByModificationDate:(DDLogFileInfo *)another
1338
1498
  {
1339
- NSDate *us = [self modificationDate];
1340
- NSDate *them = [another modificationDate];
1341
-
1342
- NSComparisonResult result = [us compare:them];
1343
-
1344
- if (result == NSOrderedAscending)
1345
- return NSOrderedDescending;
1346
-
1347
- if (result == NSOrderedDescending)
1348
- return NSOrderedAscending;
1349
-
1350
- return NSOrderedSame;
1499
+ NSDate *us = [self modificationDate];
1500
+ NSDate *them = [another modificationDate];
1501
+
1502
+ NSComparisonResult result = [us compare:them];
1503
+
1504
+ if (result == NSOrderedAscending)
1505
+ return NSOrderedDescending;
1506
+
1507
+ if (result == NSOrderedDescending)
1508
+ return NSOrderedAscending;
1509
+
1510
+ return NSOrderedSame;
1351
1511
  }
1352
1512
 
1353
1513
  @end
1514
+
1515
+ #if TARGET_OS_IPHONE
1516
+ /**
1517
+ * When creating log file on iOS we're setting NSFileProtectionKey attribute to NSFileProtectionCompleteUnlessOpen.
1518
+ *
1519
+ * But in case if app is able to launch from background we need to have an ability to open log file any time we
1520
+ * want (even if device is locked). Thats why that attribute have to be changed to
1521
+ * NSFileProtectionCompleteUntilFirstUserAuthentication.
1522
+ */
1523
+ BOOL doesAppRunInBackground()
1524
+ {
1525
+ BOOL answer = NO;
1526
+
1527
+ NSArray *backgroundModes = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UIBackgroundModes"];
1528
+
1529
+ for (NSString *mode in backgroundModes) {
1530
+ if (mode.length > 0) {
1531
+ answer = YES;
1532
+ break;
1533
+ }
1534
+ }
1535
+
1536
+ return answer;
1537
+ }
1538
+ #endif
1539
+